|
|
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: //
1.1.1.13! root 8: // LUNA のキーボードとマウス
! 9: //
! 10:
1.1.1.2 root 11: // キーボード/マウスからシリアルポートへの入力は、1バイトの送信自体に約1msec
12: // (9600bps、スタートビット1、ストップビット1) で送信後に 1msec 空けるそう
13: // なので、ここでは単純に 2msec を1スロットとする。
14:
1.1 root 15: #include "lunakbd.h"
1.1.1.13! root 16: #include "scheduler.h"
1.1 root 17: #include "sio.h"
1.1.1.12 root 18: #include "uimessage.h"
1.1 root 19:
20: // コンストラクタ
21: LunaKeyboard::LunaKeyboard()
22: {
1.1.1.4 root 23: led.resize(2);
1.1 root 24:
1.1.1.13! root 25: event.func = ToEventCallback(&LunaKeyboard::Callback);
! 26: event.Regist("Keyboard/Mouse");
1.1.1.10 root 27:
1.1.1.13! root 28: monitor.func = ToMonitorCallback(&LunaKeyboard::MonitorUpdate);
1.1.1.12 root 29: monitor.SetSize(40, 4);
1.1.1.10 root 30: monitor.Regist(ID_MONITOR_KEYBOARD);
1.1 root 31: }
32:
33: // デストラクタ
34: LunaKeyboard::~LunaKeyboard()
35: {
36: }
37:
1.1.1.13! root 38: // キーボード接続時の MD 固有処理
! 39: void
! 40: LunaKeyboard::MDConnect()
1.1.1.9 root 41: {
42: // XXX リセットはマウスには届かないような気がするので
1.1.1.13! root 43: // 接続時(電源オン)で初期化。
1.1.1.9 root 44: mouse_x = 0;
45: mouse_y = 0;
46: mouse_r = false;
47: mouse_l = false;
48: mouse_m = false;
49: prev_r = false;
50: prev_l = false;
51: prev_m = false;
52:
1.1.1.13! root 53: // ブザー停止状態で初期化すると定義されている
1.1.1.12 root 54: buzzer_on = false;
55:
1.1.1.13! root 56: // デフォルトでマウス有効
! 57: MouseOn();
1.1.1.9 root 58: }
59:
1.1.1.13! root 60: // キーボード取り外し時の MD 固有処理
1.1.1.2 root 61: void
1.1.1.13! root 62: LunaKeyboard::MDDisconnect()
1.1.1.2 root 63: {
1.1.1.13! root 64: // 動作中のタイマーは停止
! 65: gScheduler->StopEvent(event);
1.1.1.9 root 66:
1.1.1.13! root 67: // 電源が切れるのでブザー停止
! 68: buzzer_on = false;
1.1.1.6 root 69:
1.1.1.13! root 70: // マウスサンプリングは停止
! 71: MouseOff();
1.1.1.2 root 72: }
73:
74: // モニター
1.1.1.5 root 75: void
1.1.1.10 root 76: LunaKeyboard::MonitorUpdate(Monitor *, TextScreen& screen)
1.1.1.2 root 77: {
1.1.1.12 root 78: int x;
79: int y;
80: int mx;
81: int my;
82:
1.1.1.10 root 83: screen.Clear();
1.1.1.12 root 84: y = 0;
1.1.1.2 root 85:
1.1.1.12 root 86: // 0123456789012345678901234567890123456789
87: // LED: CAP Kana
88: // Buzzer: 150msec 6000Hz
89: // Mouse: sampling=off x=-999 y=-999 L M R
90: x = 8;
91: screen.Puts(0, y, "LED:");
92: screen.Puts(x, y, TA::OnOff(led[1]), "CAP");
93: screen.Puts(x + 4, y, TA::OnOff(led[0]), "Kana");
94: y++;
95: screen.Puts(0, y, "Buzzer:");
96: screen.Print(x, y, buzzer_on ? TA::Normal : TA::Disable,
97: "%umsec %uHz", buzzer_msec, buzzer_freq);
98: y++;
99:
100: // マウスとの間を1行開ける
101: y++;
102:
103: mx = mouse_x;
104: my = mouse_y;
105: if (mx < -999)
106: mx = -999;
107: if (mx > 999)
108: mx = 999;
109: if (my < -999)
110: my = -999;
111: if (my > 999)
112: my = 999;
113:
114: screen.Puts(0, y, "Mouse:");
115: screen.Print(x, y, "sampling=%s", mouse_on ? "on" : "off");
116: screen.Print(x + 13, y, (mouse_on ? TA::Normal : TA::Disable),
117: "x=%-4d y=%-4d", mx, my);
118: if (mouse_on) {
119: screen.Puts(x + 27, y, TA::OnOff(mouse_l), "L");
120: screen.Puts(x + 29, y, TA::OnOff(mouse_m), "M");
121: screen.Puts(x + 31, y, TA::OnOff(mouse_r), "R");
122: } else {
123: screen.Puts(x + 27, y, TA::Disable, "L M R");
124: }
1.1.1.2 root 125: }
126:
1.1.1.12 root 127: // 共通 keystat を LUNA キーコードに変換して返す。
1.1.1.9 root 128: // 対応する LUNA のキーがなければ 0 を返す。
129: uint
1.1.1.12 root 130: LunaKeyboard::KeyToMDKey(uint keystat) const
1.1.1.4 root 131: {
1.1.1.12 root 132: uint keycode = KC_CODE(keystat);
1.1.1.9 root 133: if (keycode >= countof(keycode2lunakey_table)) {
1.1.1.4 root 134: return 0;
135: }
136:
1.1.1.12 root 137: uint mdkey = keycode2lunakey_table[keycode];
138: if (mdkey && KC_IS_BREAK(keystat)) {
139: mdkey |= 0x80;
140: }
141: return mdkey;
1.1 root 142: }
143:
1.1.1.9 root 144: // シフト状態なら true を返す
145: bool
146: LunaKeyboard::IsShift() const
1.1 root 147: {
1.1.1.9 root 148: return pressed[KC_SHIFT_L] || pressed[KC_SHIFT_R];
1.1.1.4 root 149: }
150:
1.1.1.10 root 151: // キー入力を1つ処理する
152: void
153: LunaKeyboard::KeyInput(uint keystat)
1.1.1.4 root 154: {
1.1.1.10 root 155: uint keycode = KC_CODE(keystat);
156: bool ismake = KC_IS_MAKE(keystat);
157:
158: assert(keycode < KC_max);
159:
1.1.1.12 root 160: // LUNA キーボードの LED キーは、
161: // LED 消灯中の押下で Make、点灯中の押下で Break を送り、
162: // LED キーの開放は VM に対しては何もしない。Issue#83
163: //
164: // LED ismake keystat 送信コード
165: // ------------ -------------
166: // off MAKE : MAKE MAKE キー押下、Make を入力 (LED を on)
167: // on MAKE : MAKE BREAK キー押下、Break を入力 (LED を off)
168: // off BREAK : BREAK none キー開放
169: // on BREAK : BREAK none キー開放
170: int n = Keycode2LED(keycode);
171: if (n >= 0) {
172: if (ismake) {
173: keystat |= (led[n] ? KC_FLAG_LED_BREAK : KC_FLAG_LED_MAKE);
174: } else {
175: // Break 時はキー入力はしない (キーの開放処理自体は必要)
176: keystat |= KC_FLAG_LED_DROP;
177: }
178: }
179:
1.1.1.10 root 180: // 共通処理へ
181: if (KeyInputCommon(keystat) == false) {
182: return;
183: }
184:
1.1.1.12 root 185: // 処理できたらここで LED の状態を更新
186: if (n >= 0 && ismake) {
187: led[n] = !led[n];
188:
189: // LED 状態が変更になったので全走査指示。
190: // KeyInputCommon() 内で一度ポストしてるので無駄気味だが仕方ない…
191: UIMessage::Post(UIMessage::KEYBOARD);
1.1.1.9 root 192: }
1.1 root 193:
1.1.1.10 root 194: // LUNA のキーボードはキーボード側でキーリピートしないので
195: // ここでは何もしなくてよい
1.1.1.2 root 196: }
197:
1.1.1.9 root 198: // 共通キーコードから LED 番号を返す。LED キーでなければ -1 を返す。
199: int
200: LunaKeyboard::Keycode2LED(uint keycode) const
1.1.1.2 root 201: {
1.1.1.9 root 202: // 2つしかないのでこのくらいでいいか
203: if (keycode == KC_kana)
204: return 0;
205: if (keycode == KC_CAPS)
206: return 1;
1.1.1.2 root 207:
1.1.1.9 root 208: return -1;
1.1.1.2 root 209: }
210:
1.1.1.12 root 211: // LED 番号から共通キーコードを返す。LED 番号が不正なら KC_none を返す。
212: uint
213: LunaKeyboard::LED2Keycode(int ledcode) const
214: {
215: // 2つしかないのでこのくらいでいいか
216: if (ledcode == 0)
217: return KC_kana;
218: if (ledcode == 1)
219: return KC_CAPS;
220:
221: return KC_none;
222: }
223:
1.1.1.2 root 224: // マウス入力
225: void
226: LunaKeyboard::MouseInput(int x, int y, bool rb, bool lb, bool mb)
227: {
228: // ホストからマウスイベントのたびに呼ばれるので、ここで積算。
229: // 20msec ごとのサンプリングのタイミングで積算結果を処理する。
230: // LUNA のマウスの Y 方向は上に動く方向がプラスなので、ホスト入力とは逆。
1.1.1.12 root 231: if (mouse_on) {
232: mouse_x += x;
233: mouse_y -= y;
234: mouse_r = rb;
235: mouse_l = lb;
236: mouse_m = mb;
237: }
1.1.1.2 root 238: }
239:
1.1.1.12 root 240: // キー送信を開始 (Keyboard から呼ばれる)
1.1.1.9 root 241: void
242: LunaKeyboard::SendStart()
243: {
1.1.1.12 root 244: // ここでは次の 2msec 単位にイベントコールバックを起動するだけ。
245: Start(2_msec);
246: }
1.1.1.9 root 247:
1.1.1.12 root 248: // イベントを次の period nsec 単位後に開始。
249: void
250: LunaKeyboard::Start(uint64 period)
251: {
1.1.1.13! root 252: uint64 now = gScheduler->GetVirtTime();
1.1.1.12 root 253: uint64 target = ((now / period) + 1) * period;
254: // XXX メンバの event.vtime 参照してるけどどうするかね
255: if (event.IsRunning() == false || target < event.vtime) {
256: event.time = target - now;
1.1.1.13! root 257: gScheduler->RestartEvent(event);
1.1.1.9 root 258: }
259: }
260:
1.1.1.12 root 261: // イベントコールバック。
262: // キー入力、マウス入力、ブザー出力のいずれかが発生している間 2msec ごとに
263: // 呼ばれる。
1.1.1.2 root 264: void
1.1.1.12 root 265: LunaKeyboard::Callback(Event& ev)
1.1.1.2 root 266: {
1.1.1.13! root 267: uint64 now = gScheduler->GetVirtTime();
1.1.1.12 root 268: uint mdkey;
1.1.1.6 root 269:
1.1.1.12 root 270: // マウスサンプリングオンなら 20msec ごとにサンプリングを行う。
271: if (mouse_on && (now / 2_msec) % 10 == 0) {
272: MouseSampling();
1.1.1.9 root 273: }
274:
1.1.1.13! root 275: // キューから取り出す。ここで取り出せるのは MDKey またはマウスデータ
1.1.1.12 root 276: if (sendqueue.Dequeue(&mdkey)) {
277: // 送信
278: gSIO->Rx(1, mdkey);
279: }
1.1.1.4 root 280:
1.1.1.12 root 281: if (buzzer_on && now > buzzer_end) {
282: buzzer_on = false;
283: Release();
1.1.1.9 root 284: }
285:
1.1.1.12 root 286: if (sendqueue.Empty() == false || buzzer_on) {
287: // 送信データが残っていれば次は 2msec 後
288: Start(2_msec);
289: } else if (mouse_on) {
290: // そうでなくて、マウスサンプリングがオンなら次の 20msec 単位後
291: Start(20_msec);
1.1.1.4 root 292: }
1.1.1.2 root 293: }
294:
1.1.1.12 root 295: // マウスサンプリング
1.1.1.2 root 296: void
1.1.1.12 root 297: LunaKeyboard::MouseSampling()
1.1.1.2 root 298: {
299: // 移動量が±1 を超えるかボタンがどれかでも変化すれば送信。
1.1.1.11 root 300: if (mouse_x < -1 || mouse_x > 1 ||
301: mouse_y < -1 || mouse_y > 1 ||
1.1.1.2 root 302: mouse_r != prev_r ||
303: mouse_l != prev_l ||
304: mouse_m != prev_m)
305: {
1.1.1.12 root 306: putlog(2, "Mouse Sampling x=%d y=%d %c%c%c",
307: mouse_x, mouse_y,
308: (mouse_l ? 'L' : '-'),
309: (mouse_m ? 'M' : '-'),
310: (mouse_r ? 'R' : '-'));
311:
312: // 1バイト目、ボタン状態。
313: // mouse_[lmr] 変数は押し下げが true、LUNA のマウスは押し下げが %0
314: uint8 b = 0x80 |
315: (mouse_l ? 0 : 0x04) |
316: (mouse_m ? 0 : 0x02) |
317: (mouse_r ? 0 : 0x01);
318:
319: // 2バイト目が X、3バイト目が Y。
320: // 移動量は絶対値 0x7f でサチる (signed char ではない)。
321: if (mouse_x < -127)
322: mouse_x = -127;
323: if (mouse_x > 127)
324: mouse_x = 127;
325:
326: if (mouse_y < -127)
327: mouse_y = -127;
328: if (mouse_y > 127)
329: mouse_y = 127;
330:
331: // キューに入れておく
332: sendqueue.Enqueue(b);
333: sendqueue.Enqueue((uint8)mouse_x);
334: sendqueue.Enqueue((uint8)mouse_y);
335:
336: // 積算リセット
337: mouse_x = 0;
338: mouse_y = 0;
339: prev_r = mouse_r;
340: prev_l = mouse_l;
341: prev_m = mouse_m;
1.1.1.2 root 342: }
1.1.1.11 root 343: }
344:
1.1.1.12 root 345: // マウスサンプリングを ON にする
1.1.1.11 root 346: void
1.1.1.12 root 347: LunaKeyboard::MouseOn()
1.1.1.11 root 348: {
1.1.1.12 root 349: // 厳密なタイミングは分からないので、
350: // 実装都合で次のマウススロットからサンプリングを開始(再開)する。
351: mouse_on = true;
1.1.1.2 root 352:
1.1.1.12 root 353: // 次の 20msec 単位後から開始
354: Start(20_msec);
355: }
356:
357: // マウスサンプリングを OFF にする
358: void
359: LunaKeyboard::MouseOff()
360: {
361: mouse_on = false;
1.1.1.11 root 362: mouse_x = 0;
363: mouse_y = 0;
1.1.1.12 root 364: mouse_r = false;
365: mouse_l = false;
366: mouse_m = false;
367: prev_r = false;
368: prev_l = false;
369: prev_m = false;
1.1.1.2 root 370: }
371:
1.1.1.12 root 372: // ?
1.1.1.2 root 373: void
1.1.1.12 root 374: LunaKeyboard::MouseSendStart()
1.1.1.2 root 375: {
1.1 root 376: }
377:
1.1.1.12 root 378: static const uint buzzer_msec_table[] = { 40, 150, 400, 700 };
379: static const uint buzzer_freq_table[] = {
380: 6000, 3000, 1500, 1000, 600, 300, 150, 100
381: };
382:
1.1.1.4 root 383: // ホストからの制御
384: void
385: LunaKeyboard::Command(uint32 data)
386: {
1.1.1.12 root 387: switch (data & 0xe0) {
388: case 0x00: // LED 点灯コマンド
389: {
390: // 7 6 5 4 3 2 1 0
391: // +---+---+---+---+---+---+---+---+
392: // | 0 0 0 |LED| x x x |COD|
393: // +---+---+---+---+---+---+---+---+
394: // | +--- 0:かな 1:CAP
395: // +------------------- 0:消灯 1:点灯
396: uint code = data & 0x01;
397: uint on = data & 0x10;
398: led[code] = (bool)on;
399: UIMessage::Post(UIMessage::KEYBOARD);
400: if (loglevel >= 1) {
401: const auto name = GetKeyName(LED2Keycode(code));
1.1.1.13! root 402: putlogn("Command $%02x LED $%x(%s) %s",
! 403: data, code, name.c_str(), (on ? "ON" : "OFF"));
1.1.1.12 root 404: }
405: break;
406: }
1.1.1.4 root 407:
1.1.1.12 root 408: case 0x40: // ブザーコマンド
409: {
410: // 7 6 5 4 3 2 1 0
411: // +---+---+---+---+---+---+---+---+
412: // | 0 1 0 |T2 T1 |F3 F2 F1 |
413: // +---+---+---+---+---+---+---+---+
414: // | +------- 周波数
415: // +----------------- 時間
416: uint t = (data >> 3) & 3;
417: uint f = data & 7;
418: buzzer_msec = buzzer_msec_table[t];
419: buzzer_freq = buzzer_freq_table[f];
1.1.1.13! root 420: putlog(1, "Command $%02x Buzzer %dmsec, %dHz",
! 421: data, buzzer_msec, buzzer_freq);
1.1.1.12 root 422:
1.1.1.13! root 423: uint64 now = gScheduler->GetVirtTime();
1.1.1.12 root 424: buzzer_end = now + buzzer_msec * 1_msec;
425: buzzer_on = true;
426: Acquire();
427: Start(2_msec);
428: break;
429: }
430:
431: case 0x20: // マウス OFF コマンド
432: // 7 6 5 4 3 2 1 0
433: // +---+---+---+---+---+---+---+---+
434: // | 0 0 1 | x x x x x |
435: // +---+---+---+---+---+---+---+---+
1.1.1.13! root 436: putlog(1, "Command $%02x Mouse Sampling Off", data);
1.1.1.12 root 437: MouseOff();
438: break;
439:
440: case 0x60: // マウス ON コマンド
441: // 7 6 5 4 3 2 1 0
442: // +---+---+---+---+---+---+---+---+
443: // | 0 1 1 | x x x x x |
444: // +---+---+---+---+---+---+---+---+
1.1.1.13! root 445: putlog(1, "Command $%02x Mouse Sampling On", data);
1.1.1.12 root 446: MouseOn();
447: break;
448:
449: default:
1.1.1.13! root 450: putlog(1, "Command $%02x Undefined", data);
1.1.1.12 root 451: break;
452: }
453: }
1.1 root 454:
455: // キーコード変換表
456: // 共通キーコードから LUNA キーコードに変換する。
457: // ぶっちゃけた話共通キーコードは LUNA キーコードをベースにしているので、
458: // 穴がある以外は全部透過。
459: /*static*/ const uint
1.1.1.12 root 460: LunaKeyboard::keycode2lunakey_table[KC_max] = {
1.1 root 461: NoKey, // [00]
462: NoKey, // [01]
463: NoKey, // [02]
464: NoKey, // [03]
465: NoKey, // [04]
466: NoKey, // [05]
467: NoKey, // [06]
468: NoKey, // [07]
469: NoKey, // [08]
470: LunaKey_TAB, // [09]
471: LunaKey_CTRL, // [0a]
472: LunaKey_kana, // [0b]
473: LunaKey_SHIFT_L, // [0c]
474: LunaKey_SHIFT_R, // [0d]
475: LunaKey_CAPS, // [0e]
476: LunaKey_SF, // [0f]
477:
478: LunaKey_ESC, // [10]
479: LunaKey_BS, // [11]
480: LunaKey_enter, // [12]
481: NoKey, // [13]
482: LunaKey_space, // [14]
483: LunaKey_DEL, // [15]
484: LunaKey_XFER, // [16]
485: LunaKey_VALID, // [17]
486: LunaKey_PF11, // [18]
487: LunaKey_PF12, // [19]
488: LunaKey_PF13, // [1a]
489: LunaKey_PF14, // [1b]
490: LunaKey_up, // [1c]
491: LunaKey_left, // [1d]
492: LunaKey_right, // [1e]
493: LunaKey_down, // [1f]
494:
495: NoKey, // [20]
496: NoKey, // [21]
497: LunaKey_1, // [22]
498: LunaKey_2, // [23]
499: LunaKey_3, // [24]
500: LunaKey_4, // [25]
501: LunaKey_5, // [26]
502: LunaKey_6, // [27]
503: LunaKey_7, // [28]
504: LunaKey_8, // [29]
505: LunaKey_9, // [2a]
506: LunaKey_0, // [2b]
507: LunaKey_minus, // [2c]
508: LunaKey_circum, // [2d]
509: LunaKey_backslash, // [2e]
510: NoKey, // [2f]
511:
512: NoKey, // [30]
513: NoKey, // [31]
514: LunaKey_Q, // [32]
515: LunaKey_W, // [33]
516: LunaKey_E, // [34]
517: LunaKey_R, // [35]
518: LunaKey_T, // [36]
519: LunaKey_Y, // [37]
520: LunaKey_U, // [38]
521: LunaKey_I, // [39]
522: LunaKey_O, // [3a]
523: LunaKey_P, // [3b]
524: LunaKey_at, // [3c]
525: LunaKey_bracketleft, // [3d]
526: NoKey, // [3e]
527: NoKey, // [3f]
528:
529: NoKey, // [40]
530: NoKey, // [41]
531: LunaKey_A, // [42]
532: LunaKey_S, // [43]
533: LunaKey_D, // [44]
534: LunaKey_F, // [45]
535: LunaKey_G, // [46]
536: LunaKey_H, // [47]
537: LunaKey_J, // [48]
538: LunaKey_K, // [49]
539: LunaKey_L, // [4a]
540: LunaKey_semicolon, // [4b]
541: LunaKey_colon, // [4c]
542: LunaKey_bracketright, // [4d]
543: NoKey, // [4e]
544: NoKey, // [4f]
545:
546: NoKey, // [50]
547: NoKey, // [51]
548: LunaKey_Z, // [52]
549: LunaKey_X, // [53]
550: LunaKey_C, // [54]
551: LunaKey_V, // [55]
552: LunaKey_B, // [56]
553: LunaKey_N, // [57]
554: LunaKey_M, // [58]
555: LunaKey_comma, // [59]
556: LunaKey_period, // [5a]
557: LunaKey_slash, // [5b]
558: LunaKey_underscore, // [5c]
559: NoKey, // [5d]
560: NoKey, // [5e]
561: NoKey, // [5f]
562:
563: NoKey, // [60]
564: LunaKey_PAD_plus, // [61]
565: LunaKey_PAD_minus, // [62]
566: LunaKey_PAD_7, // [63]
567: LunaKey_PAD_8, // [64]
568: LunaKey_PAD_9, // [65]
569: LunaKey_PAD_4, // [66]
570: LunaKey_PAD_5, // [67]
571: LunaKey_PAD_6, // [68]
572: LunaKey_PAD_1, // [69]
573: LunaKey_PAD_2, // [6a]
574: LunaKey_PAD_3, // [6b]
575: LunaKey_PAD_0, // [6c]
576: LunaKey_PAD_decimal, // [6d]
577: LunaKey_PAD_enter, // [6e]
578: NoKey, // [6f]
579:
580: NoKey, // [70]
581: NoKey, // [71]
582: LunaKey_F1, // [72]
583: LunaKey_F2, // [73]
584: LunaKey_F3, // [74]
585: LunaKey_F4, // [75]
586: LunaKey_F5, // [76]
587: LunaKey_F6, // [77]
588: LunaKey_F7, // [78]
589: LunaKey_F8, // [79]
590: LunaKey_F9, // [7a]
591: LunaKey_F10, // [7b]
592: LunaKey_PAD_multiply, // [7c]
593: LunaKey_PAD_divide, // [7d]
594: LunaKey_PAD_equal, // [7e]
595: LunaKey_PAD_comma, // [7f]
596: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.