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