|
|
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: // マウスサンプリングは電源オン時は有効らしい
! 57: gScheduler->AddEvent(&mouse_event[0]);
! 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;
! 162: gScheduler->AddEvent(&key_event);
! 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: {
! 214: // 1バイト目、ボタン状態。
! 215: // mouse_[rlm] 変数は押し下げが true、LUNA のマウスは押し下げが %0
! 216: uint8 b = 0x80 |
! 217: (mouse_l ? 0 : 0x04) |
! 218: (mouse_m ? 0 : 0x02) |
! 219: (mouse_r ? 0 : 0x01);
! 220:
! 221: // 2バイト目が X、3バイト目が Y。
! 222: // 移動量は絶対値 0x7f でサチる (signed char ではない)。
! 223: if (mouse_x < -127)
! 224: mouse_x = -127;
! 225: if (mouse_x > 127)
! 226: mouse_x = 127;
! 227:
! 228: if (mouse_y < -127)
! 229: mouse_y = -127;
! 230: if (mouse_y > 127)
! 231: mouse_y = 127;
! 232:
! 233: // 1バイト目はここで送信
! 234: gSIO->Rx(1, b);
! 235:
! 236: // 2バイト目は 2msec 秒後に予約
! 237: mouse_event[1].time = 2_msec;
! 238: mouse_event[1].code = (uint8)mouse_x;
! 239: gScheduler->AddEvent(&mouse_event[1]);
! 240:
! 241: // 3バイト目は 4msec 秒後に予約
! 242: mouse_event[2].time = 4_msec;
! 243: mouse_event[2].code = (uint8)mouse_y;
! 244: gScheduler->AddEvent(&mouse_event[2]);
! 245: }
! 246:
! 247: // 積算リセット
! 248: mouse_x = reset_x;
! 249: mouse_y = reset_y;
! 250: prev_r = mouse_r;
! 251: prev_l = mouse_l;
! 252: prev_m = mouse_m;
! 253:
! 254: // 20msec 後に再び自分を呼び出す
! 255: mouse_event[0].time = 20_msec;
! 256: gScheduler->AddEvent(&mouse_event[0]);
! 257: }
! 258:
! 259: // マウスの後続バイトを送出するイベントコールバック
! 260: void
! 261: LunaKeyboard::MouseCallback(int code)
! 262: {
! 263: gSIO->Rx(1, code);
1.1 root 264: }
265:
266: // 共通キーコードを LUNA キーコードに変換して返す。
267: // LUNA キーがなければ NoKey を返す。
268: uint
269: LunaKeyboard::keycode2lunakey(uint keycode)
270: {
271: if (keycode >= countof(keycode2lunakey_table)) {
272: return NoKey;
273: }
274:
275: return keycode2lunakey_table[keycode];
276: }
277:
278: // キーコード変換表
279: // 共通キーコードから LUNA キーコードに変換する。
280: // ぶっちゃけた話共通キーコードは LUNA キーコードをベースにしているので、
281: // 穴がある以外は全部透過。
282: /*static*/ const uint
283: LunaKeyboard::keycode2lunakey_table[128] = {
284: NoKey, // [00]
285: NoKey, // [01]
286: NoKey, // [02]
287: NoKey, // [03]
288: NoKey, // [04]
289: NoKey, // [05]
290: NoKey, // [06]
291: NoKey, // [07]
292: NoKey, // [08]
293: LunaKey_TAB, // [09]
294: LunaKey_CTRL, // [0a]
295: LunaKey_kana, // [0b]
296: LunaKey_SHIFT_L, // [0c]
297: LunaKey_SHIFT_R, // [0d]
298: LunaKey_CAPS, // [0e]
299: LunaKey_SF, // [0f]
300:
301: LunaKey_ESC, // [10]
302: LunaKey_BS, // [11]
303: LunaKey_enter, // [12]
304: NoKey, // [13]
305: LunaKey_space, // [14]
306: LunaKey_DEL, // [15]
307: LunaKey_XFER, // [16]
308: LunaKey_VALID, // [17]
309: LunaKey_PF11, // [18]
310: LunaKey_PF12, // [19]
311: LunaKey_PF13, // [1a]
312: LunaKey_PF14, // [1b]
313: LunaKey_up, // [1c]
314: LunaKey_left, // [1d]
315: LunaKey_right, // [1e]
316: LunaKey_down, // [1f]
317:
318: NoKey, // [20]
319: NoKey, // [21]
320: LunaKey_1, // [22]
321: LunaKey_2, // [23]
322: LunaKey_3, // [24]
323: LunaKey_4, // [25]
324: LunaKey_5, // [26]
325: LunaKey_6, // [27]
326: LunaKey_7, // [28]
327: LunaKey_8, // [29]
328: LunaKey_9, // [2a]
329: LunaKey_0, // [2b]
330: LunaKey_minus, // [2c]
331: LunaKey_circum, // [2d]
332: LunaKey_backslash, // [2e]
333: NoKey, // [2f]
334:
335: NoKey, // [30]
336: NoKey, // [31]
337: LunaKey_Q, // [32]
338: LunaKey_W, // [33]
339: LunaKey_E, // [34]
340: LunaKey_R, // [35]
341: LunaKey_T, // [36]
342: LunaKey_Y, // [37]
343: LunaKey_U, // [38]
344: LunaKey_I, // [39]
345: LunaKey_O, // [3a]
346: LunaKey_P, // [3b]
347: LunaKey_at, // [3c]
348: LunaKey_bracketleft, // [3d]
349: NoKey, // [3e]
350: NoKey, // [3f]
351:
352: NoKey, // [40]
353: NoKey, // [41]
354: LunaKey_A, // [42]
355: LunaKey_S, // [43]
356: LunaKey_D, // [44]
357: LunaKey_F, // [45]
358: LunaKey_G, // [46]
359: LunaKey_H, // [47]
360: LunaKey_J, // [48]
361: LunaKey_K, // [49]
362: LunaKey_L, // [4a]
363: LunaKey_semicolon, // [4b]
364: LunaKey_colon, // [4c]
365: LunaKey_bracketright, // [4d]
366: NoKey, // [4e]
367: NoKey, // [4f]
368:
369: NoKey, // [50]
370: NoKey, // [51]
371: LunaKey_Z, // [52]
372: LunaKey_X, // [53]
373: LunaKey_C, // [54]
374: LunaKey_V, // [55]
375: LunaKey_B, // [56]
376: LunaKey_N, // [57]
377: LunaKey_M, // [58]
378: LunaKey_comma, // [59]
379: LunaKey_period, // [5a]
380: LunaKey_slash, // [5b]
381: LunaKey_underscore, // [5c]
382: NoKey, // [5d]
383: NoKey, // [5e]
384: NoKey, // [5f]
385:
386: NoKey, // [60]
387: LunaKey_PAD_plus, // [61]
388: LunaKey_PAD_minus, // [62]
389: LunaKey_PAD_7, // [63]
390: LunaKey_PAD_8, // [64]
391: LunaKey_PAD_9, // [65]
392: LunaKey_PAD_4, // [66]
393: LunaKey_PAD_5, // [67]
394: LunaKey_PAD_6, // [68]
395: LunaKey_PAD_1, // [69]
396: LunaKey_PAD_2, // [6a]
397: LunaKey_PAD_3, // [6b]
398: LunaKey_PAD_0, // [6c]
399: LunaKey_PAD_decimal, // [6d]
400: LunaKey_PAD_enter, // [6e]
401: NoKey, // [6f]
402:
403: NoKey, // [70]
404: NoKey, // [71]
405: LunaKey_F1, // [72]
406: LunaKey_F2, // [73]
407: LunaKey_F3, // [74]
408: LunaKey_F4, // [75]
409: LunaKey_F5, // [76]
410: LunaKey_F6, // [77]
411: LunaKey_F7, // [78]
412: LunaKey_F8, // [79]
413: LunaKey_F9, // [7a]
414: LunaKey_F10, // [7b]
415: LunaKey_PAD_multiply, // [7c]
416: LunaKey_PAD_divide, // [7d]
417: LunaKey_PAD_equal, // [7e]
418: LunaKey_PAD_comma, // [7f]
419: };
420:
421: /*static*/ const char * const
422: LunaKeyboard::keyname[] =
423: {
424: "", // 00
425: "", // 01
426: "", // 02
427: "", // 03
428: "", // 04
429: "", // 05
430: "", // 06
431: "", // 07
432: "", // 08
433: "TAB", // 09
434: "CTRL", // 0a
435: "かな", // 0b
436: "SHIFT", // 0c
437: "SHIFT", // 0d
438: "CAPS", // 0e
439: "S.F", // 0f
440:
441: "ESC", // 10
442: "BS", // 11
443: "Enter", // 12
444: "", // 13
445: "Space", // 14
446: "DEL", // 15
447: "XFER", // 16
448: "VALID", // 17
449: "PF11", // 18
450: "PF12", // 19
451: "PF13", // 1a
452: "PF14", // 1b
453: "↑", // 1c
454: "←", // 1d
455: "→", // 1e
456: "↓", // 1f
457:
458: "", // 20
459: "", // 21
460: "1!", // 22
461: "2\"", // 23
462: "3#", // 24
463: "4$", // 25
464: "5%", // 26
465: "6&", // 27
466: "7'", // 28
467: "8(", // 29
468: "9)", // 2a
469: "0", // 2b
470: "-=", // 2c
471: "^~", // 2d
472: "\\|", // 2e
473: "", // 2f
474:
475: "", // 30
476: "", // 31
477: "Q", // 32
478: "W", // 33
479: "E", // 34
480: "R", // 35
481: "T", // 36
482: "Y", // 37
483: "U", // 38
484: "I", // 39
485: "O", // 3a
486: "P", // 3b
487: "@`", // 3c
488: "[{", // 3d
489: "", // 3e
490: "", // 3f
491:
492: "", // 40
493: "", // 41
494: "A", // 42
495: "S", // 43
496: "D", // 44
497: "F", // 45
498: "G", // 46
499: "H", // 47
500: "J", // 48
501: "K", // 49
502: "L", // 4a
503: ";+", // 4b
504: ":*", // 4c
505: "]}", // 4d
506: "", // 4e
507: "", // 4f
508:
509: "", // 50
510: "", // 51
511: "Z", // 52
512: "X", // 53
513: "C", // 54
514: "V", // 55
515: "B", // 56
516: "N", // 57
517: "M", // 58
518: ",<", // 59
519: ".>", // 5a
520: "/?", // 5b
521: " _", // 5c
522: "", // 5d
523: "", // 5e
524: "", // 5f
525:
526: "", // 60
527: "PAD+", // 61
528: "PAD-", // 62
529: "PAD7", // 63
530: "PAD8", // 64
531: "PAD9", // 65
532: "PAD4", // 66
533: "PAD5", // 67
534: "PAD6", // 68
535: "PAD1", // 69
536: "PAD2", // 6a
537: "PAD3", // 6b
538: "PAD0", // 6c
539: "PAD.", // 6d
540: "PADEn", // 6e
541: "", // 6f
542:
543: "", // 70
544: "", // 71
545: "F1", // 72
546: "F2", // 73
547: "F3", // 74
548: "F4", // 75
549: "F5", // 76
550: "F6", // 77
551: "F7", // 78
552: "F8", // 79
553: "F9", // 7a
554: "F10", // 7b
555: "PAD*", // 7c
556: "PAD/", // 7d
557: "PAD=", // 7e
558: "PAD,", // 7f
559: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.