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