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