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