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

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: };

unix.superglobalmegacorp.com

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