|
|
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.1.4 root 25: led.resize(2);
1.1 root 26:
1.1.1.2 root 27: key_event.dev = this;
28: key_event.func = (DeviceCallback_t)&LunaKeyboard::KeyboardCallback;
29: key_event.time = 0;
1.1.1.9 ! root 30: key_event.SetName("Keyboard Slot");
1.1.1.2 root 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;
1.1.1.6 root 42: mouse_event[i].time = 2_msec * i;
1.1.1.2 root 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.9 ! root 52: // 電源オン
! 53: bool
! 54: LunaKeyboard::PowerOn()
! 55: {
! 56: // XXX リセットはマウスには届かないような気がするので
! 57: // 電源オンで初期化。
! 58: mouse_x = 0;
! 59: mouse_y = 0;
! 60: mouse_r = false;
! 61: mouse_l = false;
! 62: mouse_m = false;
! 63: prev_r = false;
! 64: prev_l = false;
! 65: prev_m = false;
! 66:
! 67: return true;
! 68: }
! 69:
1.1.1.2 root 70: // リセット
71: void
72: LunaKeyboard::ResetHard()
73: {
1.1.1.9 ! root 74: inherited::ResetHard();
! 75:
1.1.1.6 root 76: // 動作中のタイマーは一旦とめる
77: key_event.Stop();
78: for (int i = 0; i < countof(mouse_event); i++) {
79: mouse_event[i].Stop();
80: }
81:
82: // で、マウスサンプリングは電源オン時から有効らしい
1.1.1.3 root 83: mouse_event[0].Start();
1.1.1.2 root 84: }
85:
86: // モニター
1.1.1.5 root 87: void
88: LunaKeyboard::MonitorUpdate(TextScreen& monitor)
1.1.1.2 root 89: {
90: int x, y;
91: monitor.Clear();
92:
93: x = mouse_x;
94: y = mouse_y;
95: if (x < -999)
96: x = -999;
97: if (x > 999)
98: x = 999;
99: if (y < -999)
100: y = -999;
101: if (y > 999)
102: y = 999;
103: monitor.Print(0, 0, "Mouse: x=%-4d y=%-4d %c %c %c",
104: x, y,
105: (mouse_l ? 'L' : '-'),
106: (mouse_m ? 'M' : '-'),
107: (mouse_r ? 'R' : '-'));
108: }
109:
1.1.1.9 ! root 110: // 共通キーコードを LUNA キーコードに変換して返す。
! 111: // 対応する LUNA のキーがなければ 0 を返す。
! 112: uint
! 113: LunaKeyboard::KeyToMDKey(uint keycode) const
1.1.1.4 root 114: {
1.1.1.9 ! root 115: if (keycode >= countof(keycode2lunakey_table)) {
1.1.1.4 root 116: return 0;
117: }
118:
1.1.1.9 ! root 119: return keycode2lunakey_table[keycode];
1.1 root 120: }
121:
1.1.1.9 ! root 122: // シフト状態なら true を返す
! 123: bool
! 124: LunaKeyboard::IsShift() const
1.1 root 125: {
1.1.1.9 ! root 126: return pressed[KC_SHIFT_L] || pressed[KC_SHIFT_R];
1.1.1.4 root 127: }
128:
1.1.1.9 ! root 129: // キー処理 (MD固有部分)
! 130: bool
! 131: LunaKeyboard::ProcessKey(uint keystat)
1.1.1.4 root 132: {
1.1.1.9 ! root 133: if (KC_IS_MAKE(keystat)) {
! 134: // LED はトグル?
! 135: uint keycode = KC_CODE(keystat);
! 136: int n = Keycode2LED(keycode);
! 137: if (n >= 0) {
! 138: led[n] = !led[n];
! 139: }
! 140: }
1.1 root 141:
1.1.1.9 ! root 142: return true;
1.1.1.2 root 143: }
144:
1.1.1.9 ! root 145: // 共通キーコードから LED 番号を返す。LED キーでなければ -1 を返す。
! 146: int
! 147: LunaKeyboard::Keycode2LED(uint keycode) const
1.1.1.2 root 148: {
1.1.1.9 ! root 149: // 2つしかないのでこのくらいでいいか
! 150: if (keycode == KC_kana)
! 151: return 0;
! 152: if (keycode == KC_CAPS)
! 153: return 1;
1.1.1.2 root 154:
1.1.1.9 ! root 155: return -1;
1.1.1.2 root 156: }
157:
158: // マウス入力
159: void
160: LunaKeyboard::MouseInput(int x, int y, bool rb, bool lb, bool mb)
161: {
162: // ホストからマウスイベントのたびに呼ばれるので、ここで積算。
163: // 20msec ごとのサンプリングのタイミングで積算結果を処理する。
164: // LUNA のマウスの Y 方向は上に動く方向がプラスなので、ホスト入力とは逆。
165: mouse_x += x;
166: mouse_y -= y;
167: mouse_r = rb;
168: mouse_l = lb;
169: mouse_m = mb;
170: }
171:
1.1.1.9 ! root 172: // キーイベントを起こせる空きスロットを計算して、イベントを開始
! 173: void
! 174: LunaKeyboard::SendStart()
! 175: {
! 176: // 例えば、スロット 4 期間内のどこかでキー入力(K)が起きると
! 177: // スロット 5 の先頭時刻にイベント(E)を起こす。
! 178: //
! 179: // 通算スロット 44 45 46
! 180: // スロット番号 4 5 6
! 181: // +-----+-----+-----+..
! 182: // | K--->E
! 183: // +-----+-----+-----+..
! 184: //
! 185: // スロット 9 期間内のどこかでキー入力(K)が起きると、(0, 1, 2 はマウス用
! 186: // のスロットにしているので、これを飛ばして) スロット 3 の先頭でイベント
! 187: // (E)を起こす。
! 188: //
! 189: // 通算スロット 209 210 211 212 213
! 190: // スロット番号 9 0 1 2 3
! 191: // +-----+-----+-----+-----+-----+..
! 192: // | K------------------>E
! 193: // +-----+-----+-----+-----+-----+..
! 194:
! 195: // イベントが進行中ならなにもせず帰る
! 196: if (key_event.IsRunning()) {
! 197: return;
! 198: }
! 199:
! 200: uint64 now = gMPU->GetVirtTime();
! 201:
! 202: // t は現在の仮想時刻に対応する通算スロット
! 203: uint64 t = now / 2_msec;
! 204: // n はその次の通算スロット
! 205: uint64 n = t + 1;
! 206:
! 207: // マウススロットなら避ける
! 208: while (n % 10 < 3) {
! 209: n++;
! 210: }
! 211:
! 212: // n の時刻がイベントを起こす時刻
! 213: uint64 target = n * 2_msec;
! 214:
! 215: // イベントを登録。
! 216: key_event.time = target - now;
! 217: key_event.Start();
! 218: }
! 219:
1.1.1.2 root 220: // キー入力コールバック
221: // SIO に送信するタイミングで呼ばれる。
222: void
1.1.1.6 root 223: LunaKeyboard::KeyboardCallback(Event& ev)
1.1.1.2 root 224: {
1.1.1.9 ! root 225: // 呼ばれたということはキューは空でないはず
! 226: assert(sendqueue.Empty() == false);
! 227:
! 228: // キューから取り出す。ここで取り出せるのは keystat
! 229: uint keystat = sendqueue.Dequeue();
! 230: uint keycode = KC_CODE(keystat);
! 231: // ここで LUNA キーコードに変換 (変換できないはずはない)
! 232: uint mdkey = KeyToMDKey(keycode);
! 233: assert(mdkey != 0);
1.1.1.6 root 234:
1.1.1.9 ! root 235: // 送信
! 236: if (KC_IS_BREAK(keystat)) {
! 237: mdkey |= 0x80;
! 238: }
! 239: gSIO->Rx(1, mdkey);
! 240:
! 241: if (Keycode2LED(keystat) >= 0) {
! 242: // かなと CAP キーの押下なら、続けてキーの復旧も送る。
! 243: // 押下の時だけここに来ればいいので keycode じゃなく keystat。
1.1.1.4 root 244:
1.1.1.9 ! root 245: // (BreakKey() が内部でもう一度イベントをキックしている)
! 246: BreakKey(keycode);
! 247: }
! 248:
! 249: // キューにまだあるならここで次のイベントをキックする必要がある
! 250: if (sendqueue.Empty() == false) {
! 251: SendStart();
1.1.1.4 root 252: }
1.1.1.2 root 253: }
254:
255: // マウスサンプリングコールバック
256: // 20msec ごとに呼ばれる。
257: void
1.1.1.6 root 258: LunaKeyboard::MouseSamplingCallback(Event& ev)
1.1.1.2 root 259: {
260: int reset_x = 0;
261: int reset_y = 0;
262:
263: // 移動量±1は送信しないが次回に向けた積算は続けるそうだ。
264: if (mouse_x == -1 || mouse_x == 1) {
265: reset_x = mouse_x;
266: mouse_x = 0;
267: }
268: if (mouse_y == -1 || mouse_y == 1) {
269: reset_y = mouse_y;
270: mouse_y = 0;
271: }
272:
273: // 移動量が±1 を超えるかボタンがどれかでも変化すれば送信。
274: if (mouse_x != 0 ||
275: mouse_y != 0 ||
276: mouse_r != prev_r ||
277: mouse_l != prev_l ||
278: mouse_m != prev_m)
279: {
1.1.1.3 root 280: putlog(2, "Mouse Sampling x=%d y=%d %c%c%c",
281: mouse_x, mouse_y,
282: (mouse_r ? 'L' : '-'),
283: (mouse_m ? 'M' : '-'),
284: (mouse_l ? 'R' : '-'));
285:
1.1.1.2 root 286: // 1バイト目、ボタン状態。
287: // mouse_[rlm] 変数は押し下げが true、LUNA のマウスは押し下げが %0
288: uint8 b = 0x80 |
289: (mouse_l ? 0 : 0x04) |
290: (mouse_m ? 0 : 0x02) |
291: (mouse_r ? 0 : 0x01);
292:
293: // 2バイト目が X、3バイト目が Y。
294: // 移動量は絶対値 0x7f でサチる (signed char ではない)。
295: if (mouse_x < -127)
296: mouse_x = -127;
297: if (mouse_x > 127)
298: mouse_x = 127;
299:
300: if (mouse_y < -127)
301: mouse_y = -127;
302: if (mouse_y > 127)
303: mouse_y = 127;
304:
305: // 1バイト目はここで送信
306: gSIO->Rx(1, b);
307:
1.1.1.6 root 308: // 2バイト目は 2msec 秒後に送信
1.1.1.2 root 309: mouse_event[1].code = (uint8)mouse_x;
1.1.1.3 root 310: mouse_event[1].Start();
1.1.1.2 root 311:
1.1.1.6 root 312: // 3バイト目は 4msec 秒後に送信
1.1.1.2 root 313: mouse_event[2].code = (uint8)mouse_y;
1.1.1.3 root 314: mouse_event[2].Start();
315: } else {
316: putlog(3, "Mouse Sampling inactive");
1.1.1.2 root 317: }
318:
319: // 積算リセット
320: mouse_x = reset_x;
321: mouse_y = reset_y;
322: prev_r = mouse_r;
323: prev_l = mouse_l;
324: prev_m = mouse_m;
325:
326: // 20msec 後に再び自分を呼び出す
1.1.1.6 root 327: ev.Start();
1.1.1.2 root 328: }
329:
330: // マウスの後続バイトを送出するイベントコールバック
331: void
1.1.1.6 root 332: LunaKeyboard::MouseCallback(Event& ev)
1.1.1.2 root 333: {
1.1.1.6 root 334: gSIO->Rx(1, ev.code);
1.1 root 335: }
336:
1.1.1.4 root 337: // ホストからの制御
338: void
339: LunaKeyboard::Command(uint32 data)
340: {
341: }
342:
1.1 root 343:
344: // キーコード変換表
345: // 共通キーコードから LUNA キーコードに変換する。
346: // ぶっちゃけた話共通キーコードは LUNA キーコードをベースにしているので、
347: // 穴がある以外は全部透過。
348: /*static*/ const uint
1.1.1.9 ! root 349: LunaKeyboard::keycode2lunakey_table[0x80] = {
1.1 root 350: NoKey, // [00]
351: NoKey, // [01]
352: NoKey, // [02]
353: NoKey, // [03]
354: NoKey, // [04]
355: NoKey, // [05]
356: NoKey, // [06]
357: NoKey, // [07]
358: NoKey, // [08]
359: LunaKey_TAB, // [09]
360: LunaKey_CTRL, // [0a]
361: LunaKey_kana, // [0b]
362: LunaKey_SHIFT_L, // [0c]
363: LunaKey_SHIFT_R, // [0d]
364: LunaKey_CAPS, // [0e]
365: LunaKey_SF, // [0f]
366:
367: LunaKey_ESC, // [10]
368: LunaKey_BS, // [11]
369: LunaKey_enter, // [12]
370: NoKey, // [13]
371: LunaKey_space, // [14]
372: LunaKey_DEL, // [15]
373: LunaKey_XFER, // [16]
374: LunaKey_VALID, // [17]
375: LunaKey_PF11, // [18]
376: LunaKey_PF12, // [19]
377: LunaKey_PF13, // [1a]
378: LunaKey_PF14, // [1b]
379: LunaKey_up, // [1c]
380: LunaKey_left, // [1d]
381: LunaKey_right, // [1e]
382: LunaKey_down, // [1f]
383:
384: NoKey, // [20]
385: NoKey, // [21]
386: LunaKey_1, // [22]
387: LunaKey_2, // [23]
388: LunaKey_3, // [24]
389: LunaKey_4, // [25]
390: LunaKey_5, // [26]
391: LunaKey_6, // [27]
392: LunaKey_7, // [28]
393: LunaKey_8, // [29]
394: LunaKey_9, // [2a]
395: LunaKey_0, // [2b]
396: LunaKey_minus, // [2c]
397: LunaKey_circum, // [2d]
398: LunaKey_backslash, // [2e]
399: NoKey, // [2f]
400:
401: NoKey, // [30]
402: NoKey, // [31]
403: LunaKey_Q, // [32]
404: LunaKey_W, // [33]
405: LunaKey_E, // [34]
406: LunaKey_R, // [35]
407: LunaKey_T, // [36]
408: LunaKey_Y, // [37]
409: LunaKey_U, // [38]
410: LunaKey_I, // [39]
411: LunaKey_O, // [3a]
412: LunaKey_P, // [3b]
413: LunaKey_at, // [3c]
414: LunaKey_bracketleft, // [3d]
415: NoKey, // [3e]
416: NoKey, // [3f]
417:
418: NoKey, // [40]
419: NoKey, // [41]
420: LunaKey_A, // [42]
421: LunaKey_S, // [43]
422: LunaKey_D, // [44]
423: LunaKey_F, // [45]
424: LunaKey_G, // [46]
425: LunaKey_H, // [47]
426: LunaKey_J, // [48]
427: LunaKey_K, // [49]
428: LunaKey_L, // [4a]
429: LunaKey_semicolon, // [4b]
430: LunaKey_colon, // [4c]
431: LunaKey_bracketright, // [4d]
432: NoKey, // [4e]
433: NoKey, // [4f]
434:
435: NoKey, // [50]
436: NoKey, // [51]
437: LunaKey_Z, // [52]
438: LunaKey_X, // [53]
439: LunaKey_C, // [54]
440: LunaKey_V, // [55]
441: LunaKey_B, // [56]
442: LunaKey_N, // [57]
443: LunaKey_M, // [58]
444: LunaKey_comma, // [59]
445: LunaKey_period, // [5a]
446: LunaKey_slash, // [5b]
447: LunaKey_underscore, // [5c]
448: NoKey, // [5d]
449: NoKey, // [5e]
450: NoKey, // [5f]
451:
452: NoKey, // [60]
453: LunaKey_PAD_plus, // [61]
454: LunaKey_PAD_minus, // [62]
455: LunaKey_PAD_7, // [63]
456: LunaKey_PAD_8, // [64]
457: LunaKey_PAD_9, // [65]
458: LunaKey_PAD_4, // [66]
459: LunaKey_PAD_5, // [67]
460: LunaKey_PAD_6, // [68]
461: LunaKey_PAD_1, // [69]
462: LunaKey_PAD_2, // [6a]
463: LunaKey_PAD_3, // [6b]
464: LunaKey_PAD_0, // [6c]
465: LunaKey_PAD_decimal, // [6d]
466: LunaKey_PAD_enter, // [6e]
467: NoKey, // [6f]
468:
469: NoKey, // [70]
470: NoKey, // [71]
471: LunaKey_F1, // [72]
472: LunaKey_F2, // [73]
473: LunaKey_F3, // [74]
474: LunaKey_F4, // [75]
475: LunaKey_F5, // [76]
476: LunaKey_F6, // [77]
477: LunaKey_F7, // [78]
478: LunaKey_F8, // [79]
479: LunaKey_F9, // [7a]
480: LunaKey_F10, // [7b]
481: LunaKey_PAD_multiply, // [7c]
482: LunaKey_PAD_divide, // [7d]
483: LunaKey_PAD_equal, // [7e]
484: LunaKey_PAD_comma, // [7f]
485: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.