Annotation of nono/vm/lunakbd.cpp, revision 1.1.1.10

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: 
                     36:        for (int i = 1; i < 3; i++) {
                     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();
                     79:        for (int i = 0; i < countof(mouse_event); i++) {
                     80:                mouse_event[i].Stop();
                     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:        int reset_x = 0;
                    273:        int reset_y = 0;
                    274: 
                    275:        // 移動量±1は送信しないが次回に向けた積算は続けるそうだ。
                    276:        if (mouse_x == -1 || mouse_x == 1) {
                    277:                reset_x = mouse_x;
                    278:                mouse_x = 0;
                    279:        }
                    280:        if (mouse_y == -1 || mouse_y == 1) {
                    281:                reset_y = mouse_y;
                    282:                mouse_y = 0;
                    283:        }
                    284: 
                    285:        // 移動量が±1 を超えるかボタンがどれかでも変化すれば送信。
                    286:        if (mouse_x != 0 ||
                    287:            mouse_y != 0 ||
                    288:            mouse_r != prev_r ||
                    289:            mouse_l != prev_l ||
                    290:            mouse_m != prev_m)
                    291:        {
1.1.1.3   root      292:                putlog(2, "Mouse Sampling x=%d y=%d %c%c%c",
                    293:                        mouse_x, mouse_y,
                    294:                        (mouse_r ? 'L' : '-'),
                    295:                        (mouse_m ? 'M' : '-'),
                    296:                        (mouse_l ? 'R' : '-'));
                    297: 
1.1.1.2   root      298:                // 1バイト目、ボタン状態。
                    299:                // mouse_[rlm] 変数は押し下げが true、LUNA のマウスは押し下げが %0
                    300:                uint8 b = 0x80 |
                    301:                        (mouse_l ? 0 : 0x04) |
                    302:                        (mouse_m ? 0 : 0x02) |
                    303:                        (mouse_r ? 0 : 0x01);
                    304: 
                    305:                // 2バイト目が X、3バイト目が Y。
                    306:                // 移動量は絶対値 0x7f でサチる (signed char ではない)。
                    307:                if (mouse_x < -127)
                    308:                        mouse_x = -127;
                    309:                if (mouse_x > 127)
                    310:                        mouse_x = 127;
                    311: 
                    312:                if (mouse_y < -127)
                    313:                        mouse_y = -127;
                    314:                if (mouse_y > 127)
                    315:                        mouse_y = 127;
                    316: 
                    317:                // 1バイト目はここで送信
                    318:                gSIO->Rx(1, b);
                    319: 
1.1.1.6   root      320:                // 2バイト目は 2msec 秒後に送信
1.1.1.2   root      321:                mouse_event[1].code = (uint8)mouse_x;
1.1.1.3   root      322:                mouse_event[1].Start();
1.1.1.2   root      323: 
1.1.1.6   root      324:                // 3バイト目は 4msec 秒後に送信
1.1.1.2   root      325:                mouse_event[2].code = (uint8)mouse_y;
1.1.1.3   root      326:                mouse_event[2].Start();
                    327:        } else {
                    328:                putlog(3, "Mouse Sampling inactive");
1.1.1.2   root      329:        }
                    330: 
                    331:        // 積算リセット
                    332:        mouse_x = reset_x;
                    333:        mouse_y = reset_y;
                    334:        prev_r = mouse_r;
                    335:        prev_l = mouse_l;
                    336:        prev_m = mouse_m;
                    337: 
                    338:        // 20msec 後に再び自分を呼び出す
1.1.1.6   root      339:        ev.Start();
1.1.1.2   root      340: }
                    341: 
                    342: // マウスの後続バイトを送出するイベントコールバック
                    343: void
1.1.1.6   root      344: LunaKeyboard::MouseCallback(Event& ev)
1.1.1.2   root      345: {
1.1.1.6   root      346:        gSIO->Rx(1, ev.code);
1.1       root      347: }
                    348: 
1.1.1.4   root      349: // ホストからの制御
                    350: void
                    351: LunaKeyboard::Command(uint32 data)
                    352: {
                    353: }
                    354: 
1.1       root      355: 
                    356: // キーコード変換表
                    357: // 共通キーコードから LUNA キーコードに変換する。
                    358: // ぶっちゃけた話共通キーコードは LUNA キーコードをベースにしているので、
                    359: // 穴がある以外は全部透過。
                    360: /*static*/ const uint
1.1.1.9   root      361: LunaKeyboard::keycode2lunakey_table[0x80] = {
1.1       root      362:        NoKey,                                  // [00]
                    363:        NoKey,                                  // [01]
                    364:        NoKey,                                  // [02]
                    365:        NoKey,                                  // [03]
                    366:        NoKey,                                  // [04]
                    367:        NoKey,                                  // [05]
                    368:        NoKey,                                  // [06]
                    369:        NoKey,                                  // [07]
                    370:        NoKey,                                  // [08]
                    371:        LunaKey_TAB,                    // [09]
                    372:        LunaKey_CTRL,                   // [0a]
                    373:        LunaKey_kana,                   // [0b]
                    374:        LunaKey_SHIFT_L,                // [0c]
                    375:        LunaKey_SHIFT_R,                // [0d]
                    376:        LunaKey_CAPS,                   // [0e]
                    377:        LunaKey_SF,                             // [0f]
                    378: 
                    379:        LunaKey_ESC,                    // [10]
                    380:        LunaKey_BS,                             // [11]
                    381:        LunaKey_enter,                  // [12]
                    382:        NoKey,                                  // [13]
                    383:        LunaKey_space,                  // [14]
                    384:        LunaKey_DEL,                    // [15]
                    385:        LunaKey_XFER,                   // [16]
                    386:        LunaKey_VALID,                  // [17]
                    387:        LunaKey_PF11,                   // [18]
                    388:        LunaKey_PF12,                   // [19]
                    389:        LunaKey_PF13,                   // [1a]
                    390:        LunaKey_PF14,                   // [1b]
                    391:        LunaKey_up,                             // [1c]
                    392:        LunaKey_left,                   // [1d]
                    393:        LunaKey_right,                  // [1e]
                    394:        LunaKey_down,                   // [1f]
                    395: 
                    396:        NoKey,                                  // [20]
                    397:        NoKey,                                  // [21]
                    398:        LunaKey_1,                              // [22]
                    399:        LunaKey_2,                              // [23]
                    400:        LunaKey_3,                              // [24]
                    401:        LunaKey_4,                              // [25]
                    402:        LunaKey_5,                              // [26]
                    403:        LunaKey_6,                              // [27]
                    404:        LunaKey_7,                              // [28]
                    405:        LunaKey_8,                              // [29]
                    406:        LunaKey_9,                              // [2a]
                    407:        LunaKey_0,                              // [2b]
                    408:        LunaKey_minus,                  // [2c]
                    409:        LunaKey_circum,                 // [2d]
                    410:        LunaKey_backslash,              // [2e]
                    411:        NoKey,                                  // [2f]
                    412: 
                    413:        NoKey,                                  // [30]
                    414:        NoKey,                                  // [31]
                    415:        LunaKey_Q,                              // [32]
                    416:        LunaKey_W,                              // [33]
                    417:        LunaKey_E,                              // [34]
                    418:        LunaKey_R,                              // [35]
                    419:        LunaKey_T,                              // [36]
                    420:        LunaKey_Y,                              // [37]
                    421:        LunaKey_U,                              // [38]
                    422:        LunaKey_I,                              // [39]
                    423:        LunaKey_O,                              // [3a]
                    424:        LunaKey_P,                              // [3b]
                    425:        LunaKey_at,                             // [3c]
                    426:        LunaKey_bracketleft,    // [3d]
                    427:        NoKey,                                  // [3e]
                    428:        NoKey,                                  // [3f]
                    429: 
                    430:        NoKey,                                  // [40]
                    431:        NoKey,                                  // [41]
                    432:        LunaKey_A,                              // [42]
                    433:        LunaKey_S,                              // [43]
                    434:        LunaKey_D,                              // [44]
                    435:        LunaKey_F,                              // [45]
                    436:        LunaKey_G,                              // [46]
                    437:        LunaKey_H,                              // [47]
                    438:        LunaKey_J,                              // [48]
                    439:        LunaKey_K,                              // [49]
                    440:        LunaKey_L,                              // [4a]
                    441:        LunaKey_semicolon,              // [4b]
                    442:        LunaKey_colon,                  // [4c]
                    443:        LunaKey_bracketright,   // [4d]
                    444:        NoKey,                                  // [4e]
                    445:        NoKey,                                  // [4f]
                    446: 
                    447:        NoKey,                                  // [50]
                    448:        NoKey,                                  // [51]
                    449:        LunaKey_Z,                              // [52]
                    450:        LunaKey_X,                              // [53]
                    451:        LunaKey_C,                              // [54]
                    452:        LunaKey_V,                              // [55]
                    453:        LunaKey_B,                              // [56]
                    454:        LunaKey_N,                              // [57]
                    455:        LunaKey_M,                              // [58]
                    456:        LunaKey_comma,                  // [59]
                    457:        LunaKey_period,                 // [5a]
                    458:        LunaKey_slash,                  // [5b]
                    459:        LunaKey_underscore,             // [5c]
                    460:        NoKey,                                  // [5d]
                    461:        NoKey,                                  // [5e]
                    462:        NoKey,                                  // [5f]
                    463: 
                    464:        NoKey,                                  // [60]
                    465:        LunaKey_PAD_plus,               // [61]
                    466:        LunaKey_PAD_minus,              // [62]
                    467:        LunaKey_PAD_7,                  // [63]
                    468:        LunaKey_PAD_8,                  // [64]
                    469:        LunaKey_PAD_9,                  // [65]
                    470:        LunaKey_PAD_4,                  // [66]
                    471:        LunaKey_PAD_5,                  // [67]
                    472:        LunaKey_PAD_6,                  // [68]
                    473:        LunaKey_PAD_1,                  // [69]
                    474:        LunaKey_PAD_2,                  // [6a]
                    475:        LunaKey_PAD_3,                  // [6b]
                    476:        LunaKey_PAD_0,                  // [6c]
                    477:        LunaKey_PAD_decimal,    // [6d]
                    478:        LunaKey_PAD_enter,              // [6e]
                    479:        NoKey,                                  // [6f]
                    480: 
                    481:        NoKey,                                  // [70]
                    482:        NoKey,                                  // [71]
                    483:        LunaKey_F1,                             // [72]
                    484:        LunaKey_F2,                             // [73]
                    485:        LunaKey_F3,                             // [74]
                    486:        LunaKey_F4,                             // [75]
                    487:        LunaKey_F5,                             // [76]
                    488:        LunaKey_F6,                             // [77]
                    489:        LunaKey_F7,                             // [78]
                    490:        LunaKey_F8,                             // [79]
                    491:        LunaKey_F9,                             // [7a]
                    492:        LunaKey_F10,                    // [7b]
                    493:        LunaKey_PAD_multiply,   // [7c]
                    494:        LunaKey_PAD_divide,             // [7d]
                    495:        LunaKey_PAD_equal,              // [7e]
                    496:        LunaKey_PAD_comma,              // [7f]
                    497: };

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.