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