|
|
1.1 root 1: //
2: // nono
1.1.1.4 ! root 3: // Copyright (C) 2020 nono project
! 4: // Licensed under nono-license.txt
1.1 root 5: //
6:
1.1.1.2 root 7: // キーボードとマウス
8: //
9: // キーボード/マウスからシリアルポートへの入力は、1バイトの送信自体に約1msec
10: // (9600bps、スタートビット1、ストップビット1) で送信後に 1msec 空けるそう
11: // なので、ここでは単純に 2msec を1スロットとする。
12: // マウスは 20msec ごとにサンプリングして連続する3バイトを送り、
13: // キーボードは任意のスロットで 1バイト送ってくるので、概念的には
14: // 10スロットのうち 0, 1, 2 をマウスが、3..9 をキーボードが使用する
15: // ということにする。
16:
1.1 root 17: #include "lunakbd.h"
1.1.1.2 root 18: #include "mystring.h"
1.1 root 19: #include "sio.h"
20:
21: // コンストラクタ
22: LunaKeyboard::LunaKeyboard()
23: {
1.1.1.2 root 24: monitor.Init(30, 1);
25:
1.1 root 26: memset(reptable, 0, sizeof(reptable));
1.1.1.4 ! root 27: led.resize(2);
1.1 root 28:
1.1.1.2 root 29: key_event.dev = this;
30: key_event.func = (DeviceCallback_t)&LunaKeyboard::KeyboardCallback;
31: key_event.time = 0;
32: key_event.SetName("KeyInput");
33:
34: // マウスイベント#0 はサンプリング用も兼ねているので常にオン
35: mouse_event[0].dev = this;
36: mouse_event[0].func =
37: (DeviceCallback_t)&LunaKeyboard::MouseSamplingCallback;
38: mouse_event[0].time = 20_msec;
39: mouse_event[0].SetName("Mouse Sampling");
40:
41: for (int i = 1; i < 3; i++) {
42: mouse_event[i].dev = this;
43: mouse_event[i].func = (DeviceCallback_t)&LunaKeyboard::MouseCallback;
44: mouse_event[i].time = 0;
45: mouse_event[i].SetName(string_format("Mouse Slot%d", i));
46: }
1.1 root 47: }
48:
49: // デストラクタ
50: LunaKeyboard::~LunaKeyboard()
51: {
52: }
53:
1.1.1.2 root 54: // リセット
55: void
56: LunaKeyboard::ResetHard()
57: {
58: // マウスサンプリングは電源オン時は有効らしい
1.1.1.3 root 59: mouse_event[0].Start();
1.1.1.2 root 60: }
61:
62: // モニター
63: bool
64: LunaKeyboard::MonitorUpdate()
65: {
66: int x, y;
67: monitor.Clear();
68:
69: x = mouse_x;
70: y = mouse_y;
71: if (x < -999)
72: x = -999;
73: if (x > 999)
74: x = 999;
75: if (y < -999)
76: y = -999;
77: if (y > 999)
78: y = 999;
79: monitor.Print(0, 0, "Mouse: x=%-4d y=%-4d %c %c %c",
80: x, y,
81: (mouse_l ? 'L' : '-'),
82: (mouse_m ? 'M' : '-'),
83: (mouse_r ? 'R' : '-'));
84:
85: return true;
86: }
87:
1.1.1.4 ! root 88: // LUNA キーコードから LED 番号を返す。LED キーでなければ -1 を返す。
! 89: int
! 90: LunaKeyboard::LunaKey2LED(uint lunakey) const
! 91: {
! 92: // 2つしかないのでこのくらいでいいか
! 93: if (lunakey == LunaKey_kana)
! 94: return 0;
! 95: if (lunakey == LunaKey_CAPS)
! 96: return 1;
! 97:
! 98: return -1;
! 99: }
! 100:
1.1 root 101: // キーを押した
102: void
103: LunaKeyboard::MakeKey(uint keycode)
104: {
105: uint lunakey;
106:
107: // 共通キーコードから LUNA キーコードに
108: lunakey = keycode2lunakey(keycode);
109:
110: // LUNA にないキーは無視
111: if (lunakey == NoKey) {
112: return;
113: }
114:
115: // すでにこのキーが押されていれば送らない
116: if (reptable[lunakey]) {
117: return;
118: }
119:
1.1.1.4 ! root 120: // LED はトグル?
! 121: int n = LunaKey2LED(lunakey);
! 122: if (n >= 0) {
! 123: led[n] = !led[n];
! 124: }
! 125:
1.1 root 126: // キーが押された
127: putlog(1, "MakeKey %d(%s)", lunakey, keyname[lunakey]);
128: reptable[lunakey] = 1;
129:
1.1.1.2 root 130: // イベントを登録
1.1.1.4 ! root 131: // (LED キーの自動 Break はイベントコールバック側で処理する)
1.1.1.2 root 132: SetKeyEvent(lunakey);
1.1 root 133: }
134:
135: // キーを離した
136: void
137: LunaKeyboard::BreakKey(uint keycode)
138: {
139: uint lunakey;
140:
141: // 共通キーコードから LUNA キーコードに
142: lunakey = keycode2lunakey(keycode);
143:
144: // LUNA にないキーは無視
145: if (lunakey == NoKey) {
146: return;
147: }
148:
1.1.1.4 ! root 149: // LED キーはここでは処理しない (MakeKey() で処理してある)
! 150: if (LunaKey2LED(lunakey) >= 0) {
! 151: return;
! 152: }
! 153:
! 154: BreakKeyCommon(lunakey);
! 155: }
! 156:
! 157: // キーを離した (通常キーと LED キーの場合の両方から呼ばれる)
! 158: void
! 159: LunaKeyboard::BreakKeyCommon(uint lunakey)
! 160: {
1.1 root 161: // キーが離された
162: putlog(2, "BreakKey %d(%s)", lunakey, keyname[lunakey]);
163: reptable[lunakey] = 0;
164:
1.1.1.2 root 165: // イベントを登録
166: SetKeyEvent(lunakey | 0x80);
167: }
168:
169: // キー入力用の空きスロットにイベントをセット
170: void
171: LunaKeyboard::SetKeyEvent(uint code)
172: {
173: uint64 now = gScheduler->GetVirtTime();
174:
175: // t は現在の仮想時刻に対応するスロット
176: uint64 t = (now / 2_msec) % 10;
177: // n はその次のスロット
178: uint64 n = (t + 1) % 10;
179:
180: // マウススロットなら避ける
181: if (n < 3)
182: n = 3;
183:
184: // このイベントが起きる時間を再計算
185: uint64 target = (now / 20_msec) * 20_msec + n * 2_msec;
186: if (n < t) {
187: // n が折り返している場合は n は次の20msec 枠内
188: target += 20_msec;
189: }
190:
191: // イベントを登録。
192: if (key_sending == false) {
193: key_sending = true;
194: key_event.time = target - now;
195: key_event.code = code;
1.1.1.3 root 196: key_event.Start();
1.1.1.2 root 197: }
198: }
199:
200: // マウス入力
201: void
202: LunaKeyboard::MouseInput(int x, int y, bool rb, bool lb, bool mb)
203: {
204: // ホストからマウスイベントのたびに呼ばれるので、ここで積算。
205: // 20msec ごとのサンプリングのタイミングで積算結果を処理する。
206: // LUNA のマウスの Y 方向は上に動く方向がプラスなので、ホスト入力とは逆。
207: mouse_x += x;
208: mouse_y -= y;
209: mouse_r = rb;
210: mouse_l = lb;
211: mouse_m = mb;
212: }
213:
214: // キー入力コールバック
215: // SIO に送信するタイミングで呼ばれる。
216: void
217: LunaKeyboard::KeyboardCallback(int code)
218: {
219: gSIO->Rx(1, code);
220: key_sending = false;
1.1.1.4 ! root 221:
! 222: // かなと CAP キーの押下なら、続けてキーの復旧も送る。
! 223: if (LunaKey2LED(code) >= 0) {
! 224: BreakKeyCommon(code);
! 225: }
1.1.1.2 root 226: }
227:
228: // マウスサンプリングコールバック
229: // 20msec ごとに呼ばれる。
230: void
231: LunaKeyboard::MouseSamplingCallback(int arg)
232: {
233: int reset_x = 0;
234: int reset_y = 0;
235:
236: // 移動量±1は送信しないが次回に向けた積算は続けるそうだ。
237: if (mouse_x == -1 || mouse_x == 1) {
238: reset_x = mouse_x;
239: mouse_x = 0;
240: }
241: if (mouse_y == -1 || mouse_y == 1) {
242: reset_y = mouse_y;
243: mouse_y = 0;
244: }
245:
246: // 移動量が±1 を超えるかボタンがどれかでも変化すれば送信。
247: if (mouse_x != 0 ||
248: mouse_y != 0 ||
249: mouse_r != prev_r ||
250: mouse_l != prev_l ||
251: mouse_m != prev_m)
252: {
1.1.1.3 root 253: putlog(2, "Mouse Sampling x=%d y=%d %c%c%c",
254: mouse_x, mouse_y,
255: (mouse_r ? 'L' : '-'),
256: (mouse_m ? 'M' : '-'),
257: (mouse_l ? 'R' : '-'));
258:
1.1.1.2 root 259: // 1バイト目、ボタン状態。
260: // mouse_[rlm] 変数は押し下げが true、LUNA のマウスは押し下げが %0
261: uint8 b = 0x80 |
262: (mouse_l ? 0 : 0x04) |
263: (mouse_m ? 0 : 0x02) |
264: (mouse_r ? 0 : 0x01);
265:
266: // 2バイト目が X、3バイト目が Y。
267: // 移動量は絶対値 0x7f でサチる (signed char ではない)。
268: if (mouse_x < -127)
269: mouse_x = -127;
270: if (mouse_x > 127)
271: mouse_x = 127;
272:
273: if (mouse_y < -127)
274: mouse_y = -127;
275: if (mouse_y > 127)
276: mouse_y = 127;
277:
278: // 1バイト目はここで送信
279: gSIO->Rx(1, b);
280:
281: // 2バイト目は 2msec 秒後に予約
282: mouse_event[1].time = 2_msec;
283: mouse_event[1].code = (uint8)mouse_x;
1.1.1.3 root 284: mouse_event[1].Start();
1.1.1.2 root 285:
286: // 3バイト目は 4msec 秒後に予約
287: mouse_event[2].time = 4_msec;
288: mouse_event[2].code = (uint8)mouse_y;
1.1.1.3 root 289: mouse_event[2].Start();
290: } else {
291: putlog(3, "Mouse Sampling inactive");
1.1.1.2 root 292: }
293:
294: // 積算リセット
295: mouse_x = reset_x;
296: mouse_y = reset_y;
297: prev_r = mouse_r;
298: prev_l = mouse_l;
299: prev_m = mouse_m;
300:
301: // 20msec 後に再び自分を呼び出す
302: mouse_event[0].time = 20_msec;
1.1.1.3 root 303: mouse_event[0].Start();
1.1.1.2 root 304: }
305:
306: // マウスの後続バイトを送出するイベントコールバック
307: void
308: LunaKeyboard::MouseCallback(int code)
309: {
310: gSIO->Rx(1, code);
1.1 root 311: }
312:
1.1.1.4 ! root 313: // ホストからの制御
! 314: void
! 315: LunaKeyboard::Command(uint32 data)
! 316: {
! 317: }
! 318:
1.1 root 319: // 共通キーコードを LUNA キーコードに変換して返す。
320: // LUNA キーがなければ NoKey を返す。
321: uint
322: LunaKeyboard::keycode2lunakey(uint keycode)
323: {
324: if (keycode >= countof(keycode2lunakey_table)) {
325: return NoKey;
326: }
327:
328: return keycode2lunakey_table[keycode];
329: }
330:
331: // キーコード変換表
332: // 共通キーコードから LUNA キーコードに変換する。
333: // ぶっちゃけた話共通キーコードは LUNA キーコードをベースにしているので、
334: // 穴がある以外は全部透過。
335: /*static*/ const uint
336: LunaKeyboard::keycode2lunakey_table[128] = {
337: NoKey, // [00]
338: NoKey, // [01]
339: NoKey, // [02]
340: NoKey, // [03]
341: NoKey, // [04]
342: NoKey, // [05]
343: NoKey, // [06]
344: NoKey, // [07]
345: NoKey, // [08]
346: LunaKey_TAB, // [09]
347: LunaKey_CTRL, // [0a]
348: LunaKey_kana, // [0b]
349: LunaKey_SHIFT_L, // [0c]
350: LunaKey_SHIFT_R, // [0d]
351: LunaKey_CAPS, // [0e]
352: LunaKey_SF, // [0f]
353:
354: LunaKey_ESC, // [10]
355: LunaKey_BS, // [11]
356: LunaKey_enter, // [12]
357: NoKey, // [13]
358: LunaKey_space, // [14]
359: LunaKey_DEL, // [15]
360: LunaKey_XFER, // [16]
361: LunaKey_VALID, // [17]
362: LunaKey_PF11, // [18]
363: LunaKey_PF12, // [19]
364: LunaKey_PF13, // [1a]
365: LunaKey_PF14, // [1b]
366: LunaKey_up, // [1c]
367: LunaKey_left, // [1d]
368: LunaKey_right, // [1e]
369: LunaKey_down, // [1f]
370:
371: NoKey, // [20]
372: NoKey, // [21]
373: LunaKey_1, // [22]
374: LunaKey_2, // [23]
375: LunaKey_3, // [24]
376: LunaKey_4, // [25]
377: LunaKey_5, // [26]
378: LunaKey_6, // [27]
379: LunaKey_7, // [28]
380: LunaKey_8, // [29]
381: LunaKey_9, // [2a]
382: LunaKey_0, // [2b]
383: LunaKey_minus, // [2c]
384: LunaKey_circum, // [2d]
385: LunaKey_backslash, // [2e]
386: NoKey, // [2f]
387:
388: NoKey, // [30]
389: NoKey, // [31]
390: LunaKey_Q, // [32]
391: LunaKey_W, // [33]
392: LunaKey_E, // [34]
393: LunaKey_R, // [35]
394: LunaKey_T, // [36]
395: LunaKey_Y, // [37]
396: LunaKey_U, // [38]
397: LunaKey_I, // [39]
398: LunaKey_O, // [3a]
399: LunaKey_P, // [3b]
400: LunaKey_at, // [3c]
401: LunaKey_bracketleft, // [3d]
402: NoKey, // [3e]
403: NoKey, // [3f]
404:
405: NoKey, // [40]
406: NoKey, // [41]
407: LunaKey_A, // [42]
408: LunaKey_S, // [43]
409: LunaKey_D, // [44]
410: LunaKey_F, // [45]
411: LunaKey_G, // [46]
412: LunaKey_H, // [47]
413: LunaKey_J, // [48]
414: LunaKey_K, // [49]
415: LunaKey_L, // [4a]
416: LunaKey_semicolon, // [4b]
417: LunaKey_colon, // [4c]
418: LunaKey_bracketright, // [4d]
419: NoKey, // [4e]
420: NoKey, // [4f]
421:
422: NoKey, // [50]
423: NoKey, // [51]
424: LunaKey_Z, // [52]
425: LunaKey_X, // [53]
426: LunaKey_C, // [54]
427: LunaKey_V, // [55]
428: LunaKey_B, // [56]
429: LunaKey_N, // [57]
430: LunaKey_M, // [58]
431: LunaKey_comma, // [59]
432: LunaKey_period, // [5a]
433: LunaKey_slash, // [5b]
434: LunaKey_underscore, // [5c]
435: NoKey, // [5d]
436: NoKey, // [5e]
437: NoKey, // [5f]
438:
439: NoKey, // [60]
440: LunaKey_PAD_plus, // [61]
441: LunaKey_PAD_minus, // [62]
442: LunaKey_PAD_7, // [63]
443: LunaKey_PAD_8, // [64]
444: LunaKey_PAD_9, // [65]
445: LunaKey_PAD_4, // [66]
446: LunaKey_PAD_5, // [67]
447: LunaKey_PAD_6, // [68]
448: LunaKey_PAD_1, // [69]
449: LunaKey_PAD_2, // [6a]
450: LunaKey_PAD_3, // [6b]
451: LunaKey_PAD_0, // [6c]
452: LunaKey_PAD_decimal, // [6d]
453: LunaKey_PAD_enter, // [6e]
454: NoKey, // [6f]
455:
456: NoKey, // [70]
457: NoKey, // [71]
458: LunaKey_F1, // [72]
459: LunaKey_F2, // [73]
460: LunaKey_F3, // [74]
461: LunaKey_F4, // [75]
462: LunaKey_F5, // [76]
463: LunaKey_F6, // [77]
464: LunaKey_F7, // [78]
465: LunaKey_F8, // [79]
466: LunaKey_F9, // [7a]
467: LunaKey_F10, // [7b]
468: LunaKey_PAD_multiply, // [7c]
469: LunaKey_PAD_divide, // [7d]
470: LunaKey_PAD_equal, // [7e]
471: LunaKey_PAD_comma, // [7f]
472: };
473:
474: /*static*/ const char * const
475: LunaKeyboard::keyname[] =
476: {
477: "", // 00
478: "", // 01
479: "", // 02
480: "", // 03
481: "", // 04
482: "", // 05
483: "", // 06
484: "", // 07
485: "", // 08
486: "TAB", // 09
487: "CTRL", // 0a
488: "かな", // 0b
489: "SHIFT", // 0c
490: "SHIFT", // 0d
491: "CAPS", // 0e
492: "S.F", // 0f
493:
494: "ESC", // 10
495: "BS", // 11
496: "Enter", // 12
497: "", // 13
498: "Space", // 14
499: "DEL", // 15
500: "XFER", // 16
501: "VALID", // 17
502: "PF11", // 18
503: "PF12", // 19
504: "PF13", // 1a
505: "PF14", // 1b
506: "↑", // 1c
507: "←", // 1d
508: "→", // 1e
509: "↓", // 1f
510:
511: "", // 20
512: "", // 21
513: "1!", // 22
514: "2\"", // 23
515: "3#", // 24
516: "4$", // 25
517: "5%", // 26
518: "6&", // 27
519: "7'", // 28
520: "8(", // 29
521: "9)", // 2a
522: "0", // 2b
523: "-=", // 2c
524: "^~", // 2d
525: "\\|", // 2e
526: "", // 2f
527:
528: "", // 30
529: "", // 31
530: "Q", // 32
531: "W", // 33
532: "E", // 34
533: "R", // 35
534: "T", // 36
535: "Y", // 37
536: "U", // 38
537: "I", // 39
538: "O", // 3a
539: "P", // 3b
540: "@`", // 3c
541: "[{", // 3d
542: "", // 3e
543: "", // 3f
544:
545: "", // 40
546: "", // 41
547: "A", // 42
548: "S", // 43
549: "D", // 44
550: "F", // 45
551: "G", // 46
552: "H", // 47
553: "J", // 48
554: "K", // 49
555: "L", // 4a
556: ";+", // 4b
557: ":*", // 4c
558: "]}", // 4d
559: "", // 4e
560: "", // 4f
561:
562: "", // 50
563: "", // 51
564: "Z", // 52
565: "X", // 53
566: "C", // 54
567: "V", // 55
568: "B", // 56
569: "N", // 57
570: "M", // 58
571: ",<", // 59
572: ".>", // 5a
573: "/?", // 5b
574: " _", // 5c
575: "", // 5d
576: "", // 5e
577: "", // 5f
578:
579: "", // 60
580: "PAD+", // 61
581: "PAD-", // 62
582: "PAD7", // 63
583: "PAD8", // 64
584: "PAD9", // 65
585: "PAD4", // 66
586: "PAD5", // 67
587: "PAD6", // 68
588: "PAD1", // 69
589: "PAD2", // 6a
590: "PAD3", // 6b
591: "PAD0", // 6c
592: "PAD.", // 6d
593: "PADEn", // 6e
594: "", // 6f
595:
596: "", // 70
597: "", // 71
598: "F1", // 72
599: "F2", // 73
600: "F3", // 74
601: "F4", // 75
602: "F5", // 76
603: "F6", // 77
604: "F7", // 78
605: "F8", // 79
606: "F9", // 7a
607: "F10", // 7b
608: "PAD*", // 7c
609: "PAD/", // 7d
610: "PAD=", // 7e
611: "PAD,", // 7f
612: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.