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

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"
1.1.1.2   root       18: #include "mystring.h"
1.1       root       19: #include "sio.h"
                     20: 
                     21: // コンストラクタ
                     22: LunaKeyboard::LunaKeyboard()
                     23: {
1.1.1.5   root       24:        monitor_size = nnSize(30, 1);
1.1.1.2   root       25: 
1.1       root       26:        memset(reptable, 0, sizeof(reptable));
1.1.1.4   root       27:        led.resize(2);
1.1       root       28: 
1.1.1.2   root       29:        key_event.dev = this;
                     30:        key_event.func = (DeviceCallback_t)&LunaKeyboard::KeyboardCallback;
                     31:        key_event.time = 0;
                     32:        key_event.SetName("KeyInput");
                     33: 
                     34:        // マウスイベント#0 はサンプリング用も兼ねているので常にオン
                     35:        mouse_event[0].dev = this;
                     36:        mouse_event[0].func =
                     37:                (DeviceCallback_t)&LunaKeyboard::MouseSamplingCallback;
                     38:        mouse_event[0].time = 20_msec;
                     39:        mouse_event[0].SetName("Mouse Sampling");
                     40: 
                     41:        for (int i = 1; i < 3; i++) {
                     42:                mouse_event[i].dev = this;
                     43:                mouse_event[i].func = (DeviceCallback_t)&LunaKeyboard::MouseCallback;
1.1.1.6 ! root       44:                mouse_event[i].time = 2_msec * i;
1.1.1.2   root       45:                mouse_event[i].SetName(string_format("Mouse Slot%d", i));
                     46:        }
1.1       root       47: }
                     48: 
                     49: // デストラクタ
                     50: LunaKeyboard::~LunaKeyboard()
                     51: {
                     52: }
                     53: 
1.1.1.2   root       54: // リセット
                     55: void
                     56: LunaKeyboard::ResetHard()
                     57: {
1.1.1.6 ! root       58:        // 動作中のタイマーは一旦とめる
        !            59:        key_event.Stop();
        !            60:        for (int i = 0; i < countof(mouse_event); i++) {
        !            61:                mouse_event[i].Stop();
        !            62:        }
        !            63: 
        !            64:        // で、マウスサンプリングは電源オン時から有効らしい
1.1.1.3   root       65:        mouse_event[0].Start();
1.1.1.2   root       66: }
                     67: 
                     68: // モニター
1.1.1.5   root       69: void
                     70: LunaKeyboard::MonitorUpdate(TextScreen& monitor)
1.1.1.2   root       71: {
                     72:        int x, y;
                     73:        monitor.Clear();
                     74: 
                     75:        x = mouse_x;
                     76:        y = mouse_y;
                     77:        if (x < -999)
                     78:                x = -999;
                     79:        if (x > 999)
                     80:                x = 999;
                     81:        if (y < -999)
                     82:                y = -999;
                     83:        if (y > 999)
                     84:                y = 999;
                     85:        monitor.Print(0, 0, "Mouse: x=%-4d y=%-4d %c %c %c",
                     86:                x, y,
                     87:                (mouse_l ? 'L' : '-'),
                     88:                (mouse_m ? 'M' : '-'),
                     89:                (mouse_r ? 'R' : '-'));
                     90: }
                     91: 
1.1.1.4   root       92: // LUNA キーコードから LED 番号を返す。LED キーでなければ -1 を返す。
                     93: int
                     94: LunaKeyboard::LunaKey2LED(uint lunakey) const
                     95: {
                     96:        // 2つしかないのでこのくらいでいいか
                     97:        if (lunakey == LunaKey_kana)
                     98:                return 0;
                     99:        if (lunakey == LunaKey_CAPS)
                    100:                return 1;
                    101: 
                    102:        return -1;
                    103: }
                    104: 
1.1       root      105: // キーを押した
                    106: void
                    107: LunaKeyboard::MakeKey(uint keycode)
                    108: {
                    109:        uint lunakey;
                    110: 
                    111:        // 共通キーコードから LUNA キーコードに
                    112:        lunakey = keycode2lunakey(keycode);
                    113: 
                    114:        // LUNA にないキーは無視
                    115:        if (lunakey == NoKey) {
                    116:                return;
                    117:        }
                    118: 
                    119:        // すでにこのキーが押されていれば送らない
                    120:        if (reptable[lunakey]) {
                    121:                return;
                    122:        }
                    123: 
1.1.1.4   root      124:        // LED はトグル?
                    125:        int n = LunaKey2LED(lunakey);
                    126:        if (n >= 0) {
                    127:                led[n] = !led[n];
                    128:        }
                    129: 
1.1       root      130:        // キーが押された
                    131:        putlog(1, "MakeKey  %d(%s)", lunakey, keyname[lunakey]);
                    132:        reptable[lunakey] = 1;
                    133: 
1.1.1.2   root      134:        // イベントを登録
1.1.1.4   root      135:        // (LED キーの自動 Break はイベントコールバック側で処理する)
1.1.1.2   root      136:        SetKeyEvent(lunakey);
1.1       root      137: }
                    138: 
                    139: // キーを離した
                    140: void
                    141: LunaKeyboard::BreakKey(uint keycode)
                    142: {
                    143:        uint lunakey;
                    144: 
                    145:        // 共通キーコードから LUNA キーコードに
                    146:        lunakey = keycode2lunakey(keycode);
                    147: 
                    148:        // LUNA にないキーは無視
                    149:        if (lunakey == NoKey) {
                    150:                return;
                    151:        }
                    152: 
1.1.1.4   root      153:        // LED キーはここでは処理しない (MakeKey() で処理してある)
                    154:        if (LunaKey2LED(lunakey) >= 0) {
                    155:                return;
                    156:        }
                    157: 
                    158:        BreakKeyCommon(lunakey);
                    159: }
                    160: 
                    161: // キーを離した (通常キーと LED キーの場合の両方から呼ばれる)
                    162: void
                    163: LunaKeyboard::BreakKeyCommon(uint lunakey)
                    164: {
1.1       root      165:        // キーが離された
                    166:        putlog(2, "BreakKey %d(%s)", lunakey, keyname[lunakey]);
                    167:        reptable[lunakey] = 0;
                    168: 
1.1.1.2   root      169:        // イベントを登録
                    170:        SetKeyEvent(lunakey | 0x80);
                    171: }
                    172: 
                    173: // キー入力用の空きスロットにイベントをセット
                    174: void
                    175: LunaKeyboard::SetKeyEvent(uint code)
                    176: {
                    177:        uint64 now = gScheduler->GetVirtTime();
                    178: 
                    179:        // t は現在の仮想時刻に対応するスロット
                    180:        uint64 t = (now / 2_msec) % 10;
                    181:        // n はその次のスロット
                    182:        uint64 n = (t + 1) % 10;
                    183: 
                    184:        // マウススロットなら避ける
                    185:        if (n < 3)
                    186:                n = 3;
                    187: 
                    188:        // このイベントが起きる時間を再計算
                    189:        uint64 target = (now / 20_msec) * 20_msec + n * 2_msec;
                    190:        if (n < t) {
                    191:                // n が折り返している場合は n は次の20msec 枠内
                    192:                target += 20_msec;
                    193:        }
                    194: 
                    195:        // イベントを登録。
                    196:        if (key_sending == false) {
                    197:                key_sending = true;
                    198:                key_event.time = target - now;
                    199:                key_event.code = code;
1.1.1.3   root      200:                key_event.Start();
1.1.1.2   root      201:        }
                    202: }
                    203: 
                    204: // マウス入力
                    205: void
                    206: LunaKeyboard::MouseInput(int x, int y, bool rb, bool lb, bool mb)
                    207: {
                    208:        // ホストからマウスイベントのたびに呼ばれるので、ここで積算。
                    209:        // 20msec ごとのサンプリングのタイミングで積算結果を処理する。
                    210:        // LUNA のマウスの Y 方向は上に動く方向がプラスなので、ホスト入力とは逆。
                    211:        mouse_x += x;
                    212:        mouse_y -= y;
                    213:        mouse_r = rb;
                    214:        mouse_l = lb;
                    215:        mouse_m = mb;
                    216: }
                    217: 
                    218: // キー入力コールバック
                    219: // SIO に送信するタイミングで呼ばれる。
                    220: void
1.1.1.6 ! root      221: LunaKeyboard::KeyboardCallback(Event& ev)
1.1.1.2   root      222: {
1.1.1.6 ! root      223:        int& code = ev.code;
        !           224: 
1.1.1.2   root      225:        gSIO->Rx(1, code);
                    226:        key_sending = false;
1.1.1.4   root      227: 
                    228:        // かなと CAP キーの押下なら、続けてキーの復旧も送る。
                    229:        if (LunaKey2LED(code) >= 0) {
                    230:                BreakKeyCommon(code);
                    231:        }
1.1.1.2   root      232: }
                    233: 
                    234: // マウスサンプリングコールバック
                    235: // 20msec ごとに呼ばれる。
                    236: void
1.1.1.6 ! root      237: LunaKeyboard::MouseSamplingCallback(Event& ev)
1.1.1.2   root      238: {
                    239:        int reset_x = 0;
                    240:        int reset_y = 0;
                    241: 
                    242:        // 移動量±1は送信しないが次回に向けた積算は続けるそうだ。
                    243:        if (mouse_x == -1 || mouse_x == 1) {
                    244:                reset_x = mouse_x;
                    245:                mouse_x = 0;
                    246:        }
                    247:        if (mouse_y == -1 || mouse_y == 1) {
                    248:                reset_y = mouse_y;
                    249:                mouse_y = 0;
                    250:        }
                    251: 
                    252:        // 移動量が±1 を超えるかボタンがどれかでも変化すれば送信。
                    253:        if (mouse_x != 0 ||
                    254:            mouse_y != 0 ||
                    255:            mouse_r != prev_r ||
                    256:            mouse_l != prev_l ||
                    257:            mouse_m != prev_m)
                    258:        {
1.1.1.3   root      259:                putlog(2, "Mouse Sampling x=%d y=%d %c%c%c",
                    260:                        mouse_x, mouse_y,
                    261:                        (mouse_r ? 'L' : '-'),
                    262:                        (mouse_m ? 'M' : '-'),
                    263:                        (mouse_l ? 'R' : '-'));
                    264: 
1.1.1.2   root      265:                // 1バイト目、ボタン状態。
                    266:                // mouse_[rlm] 変数は押し下げが true、LUNA のマウスは押し下げが %0
                    267:                uint8 b = 0x80 |
                    268:                        (mouse_l ? 0 : 0x04) |
                    269:                        (mouse_m ? 0 : 0x02) |
                    270:                        (mouse_r ? 0 : 0x01);
                    271: 
                    272:                // 2バイト目が X、3バイト目が Y。
                    273:                // 移動量は絶対値 0x7f でサチる (signed char ではない)。
                    274:                if (mouse_x < -127)
                    275:                        mouse_x = -127;
                    276:                if (mouse_x > 127)
                    277:                        mouse_x = 127;
                    278: 
                    279:                if (mouse_y < -127)
                    280:                        mouse_y = -127;
                    281:                if (mouse_y > 127)
                    282:                        mouse_y = 127;
                    283: 
                    284:                // 1バイト目はここで送信
                    285:                gSIO->Rx(1, b);
                    286: 
1.1.1.6 ! root      287:                // 2バイト目は 2msec 秒後に送信
1.1.1.2   root      288:                mouse_event[1].code = (uint8)mouse_x;
1.1.1.3   root      289:                mouse_event[1].Start();
1.1.1.2   root      290: 
1.1.1.6 ! root      291:                // 3バイト目は 4msec 秒後に送信
1.1.1.2   root      292:                mouse_event[2].code = (uint8)mouse_y;
1.1.1.3   root      293:                mouse_event[2].Start();
                    294:        } else {
                    295:                putlog(3, "Mouse Sampling inactive");
1.1.1.2   root      296:        }
                    297: 
                    298:        // 積算リセット
                    299:        mouse_x = reset_x;
                    300:        mouse_y = reset_y;
                    301:        prev_r = mouse_r;
                    302:        prev_l = mouse_l;
                    303:        prev_m = mouse_m;
                    304: 
                    305:        // 20msec 後に再び自分を呼び出す
1.1.1.6 ! root      306:        ev.Start();
1.1.1.2   root      307: }
                    308: 
                    309: // マウスの後続バイトを送出するイベントコールバック
                    310: void
1.1.1.6 ! root      311: LunaKeyboard::MouseCallback(Event& ev)
1.1.1.2   root      312: {
1.1.1.6 ! root      313:        gSIO->Rx(1, ev.code);
1.1       root      314: }
                    315: 
1.1.1.4   root      316: // ホストからの制御
                    317: void
                    318: LunaKeyboard::Command(uint32 data)
                    319: {
                    320: }
                    321: 
1.1       root      322: // 共通キーコードを LUNA キーコードに変換して返す。
                    323: // LUNA キーがなければ NoKey を返す。
                    324: uint
                    325: LunaKeyboard::keycode2lunakey(uint keycode)
                    326: {
                    327:        if (keycode >= countof(keycode2lunakey_table)) {
                    328:                return NoKey;
                    329:        }
                    330: 
                    331:        return keycode2lunakey_table[keycode];
                    332: }
                    333: 
                    334: // キーコード変換表
                    335: // 共通キーコードから LUNA キーコードに変換する。
                    336: // ぶっちゃけた話共通キーコードは LUNA キーコードをベースにしているので、
                    337: // 穴がある以外は全部透過。
                    338: /*static*/ const uint
                    339: LunaKeyboard::keycode2lunakey_table[128] = {
                    340:        NoKey,                                  // [00]
                    341:        NoKey,                                  // [01]
                    342:        NoKey,                                  // [02]
                    343:        NoKey,                                  // [03]
                    344:        NoKey,                                  // [04]
                    345:        NoKey,                                  // [05]
                    346:        NoKey,                                  // [06]
                    347:        NoKey,                                  // [07]
                    348:        NoKey,                                  // [08]
                    349:        LunaKey_TAB,                    // [09]
                    350:        LunaKey_CTRL,                   // [0a]
                    351:        LunaKey_kana,                   // [0b]
                    352:        LunaKey_SHIFT_L,                // [0c]
                    353:        LunaKey_SHIFT_R,                // [0d]
                    354:        LunaKey_CAPS,                   // [0e]
                    355:        LunaKey_SF,                             // [0f]
                    356: 
                    357:        LunaKey_ESC,                    // [10]
                    358:        LunaKey_BS,                             // [11]
                    359:        LunaKey_enter,                  // [12]
                    360:        NoKey,                                  // [13]
                    361:        LunaKey_space,                  // [14]
                    362:        LunaKey_DEL,                    // [15]
                    363:        LunaKey_XFER,                   // [16]
                    364:        LunaKey_VALID,                  // [17]
                    365:        LunaKey_PF11,                   // [18]
                    366:        LunaKey_PF12,                   // [19]
                    367:        LunaKey_PF13,                   // [1a]
                    368:        LunaKey_PF14,                   // [1b]
                    369:        LunaKey_up,                             // [1c]
                    370:        LunaKey_left,                   // [1d]
                    371:        LunaKey_right,                  // [1e]
                    372:        LunaKey_down,                   // [1f]
                    373: 
                    374:        NoKey,                                  // [20]
                    375:        NoKey,                                  // [21]
                    376:        LunaKey_1,                              // [22]
                    377:        LunaKey_2,                              // [23]
                    378:        LunaKey_3,                              // [24]
                    379:        LunaKey_4,                              // [25]
                    380:        LunaKey_5,                              // [26]
                    381:        LunaKey_6,                              // [27]
                    382:        LunaKey_7,                              // [28]
                    383:        LunaKey_8,                              // [29]
                    384:        LunaKey_9,                              // [2a]
                    385:        LunaKey_0,                              // [2b]
                    386:        LunaKey_minus,                  // [2c]
                    387:        LunaKey_circum,                 // [2d]
                    388:        LunaKey_backslash,              // [2e]
                    389:        NoKey,                                  // [2f]
                    390: 
                    391:        NoKey,                                  // [30]
                    392:        NoKey,                                  // [31]
                    393:        LunaKey_Q,                              // [32]
                    394:        LunaKey_W,                              // [33]
                    395:        LunaKey_E,                              // [34]
                    396:        LunaKey_R,                              // [35]
                    397:        LunaKey_T,                              // [36]
                    398:        LunaKey_Y,                              // [37]
                    399:        LunaKey_U,                              // [38]
                    400:        LunaKey_I,                              // [39]
                    401:        LunaKey_O,                              // [3a]
                    402:        LunaKey_P,                              // [3b]
                    403:        LunaKey_at,                             // [3c]
                    404:        LunaKey_bracketleft,    // [3d]
                    405:        NoKey,                                  // [3e]
                    406:        NoKey,                                  // [3f]
                    407: 
                    408:        NoKey,                                  // [40]
                    409:        NoKey,                                  // [41]
                    410:        LunaKey_A,                              // [42]
                    411:        LunaKey_S,                              // [43]
                    412:        LunaKey_D,                              // [44]
                    413:        LunaKey_F,                              // [45]
                    414:        LunaKey_G,                              // [46]
                    415:        LunaKey_H,                              // [47]
                    416:        LunaKey_J,                              // [48]
                    417:        LunaKey_K,                              // [49]
                    418:        LunaKey_L,                              // [4a]
                    419:        LunaKey_semicolon,              // [4b]
                    420:        LunaKey_colon,                  // [4c]
                    421:        LunaKey_bracketright,   // [4d]
                    422:        NoKey,                                  // [4e]
                    423:        NoKey,                                  // [4f]
                    424: 
                    425:        NoKey,                                  // [50]
                    426:        NoKey,                                  // [51]
                    427:        LunaKey_Z,                              // [52]
                    428:        LunaKey_X,                              // [53]
                    429:        LunaKey_C,                              // [54]
                    430:        LunaKey_V,                              // [55]
                    431:        LunaKey_B,                              // [56]
                    432:        LunaKey_N,                              // [57]
                    433:        LunaKey_M,                              // [58]
                    434:        LunaKey_comma,                  // [59]
                    435:        LunaKey_period,                 // [5a]
                    436:        LunaKey_slash,                  // [5b]
                    437:        LunaKey_underscore,             // [5c]
                    438:        NoKey,                                  // [5d]
                    439:        NoKey,                                  // [5e]
                    440:        NoKey,                                  // [5f]
                    441: 
                    442:        NoKey,                                  // [60]
                    443:        LunaKey_PAD_plus,               // [61]
                    444:        LunaKey_PAD_minus,              // [62]
                    445:        LunaKey_PAD_7,                  // [63]
                    446:        LunaKey_PAD_8,                  // [64]
                    447:        LunaKey_PAD_9,                  // [65]
                    448:        LunaKey_PAD_4,                  // [66]
                    449:        LunaKey_PAD_5,                  // [67]
                    450:        LunaKey_PAD_6,                  // [68]
                    451:        LunaKey_PAD_1,                  // [69]
                    452:        LunaKey_PAD_2,                  // [6a]
                    453:        LunaKey_PAD_3,                  // [6b]
                    454:        LunaKey_PAD_0,                  // [6c]
                    455:        LunaKey_PAD_decimal,    // [6d]
                    456:        LunaKey_PAD_enter,              // [6e]
                    457:        NoKey,                                  // [6f]
                    458: 
                    459:        NoKey,                                  // [70]
                    460:        NoKey,                                  // [71]
                    461:        LunaKey_F1,                             // [72]
                    462:        LunaKey_F2,                             // [73]
                    463:        LunaKey_F3,                             // [74]
                    464:        LunaKey_F4,                             // [75]
                    465:        LunaKey_F5,                             // [76]
                    466:        LunaKey_F6,                             // [77]
                    467:        LunaKey_F7,                             // [78]
                    468:        LunaKey_F8,                             // [79]
                    469:        LunaKey_F9,                             // [7a]
                    470:        LunaKey_F10,                    // [7b]
                    471:        LunaKey_PAD_multiply,   // [7c]
                    472:        LunaKey_PAD_divide,             // [7d]
                    473:        LunaKey_PAD_equal,              // [7e]
                    474:        LunaKey_PAD_comma,              // [7f]
                    475: };
                    476: 
                    477: /*static*/ const char * const
                    478: LunaKeyboard::keyname[] =
                    479: {
                    480:        "",                     // 00
                    481:        "",                     // 01
                    482:        "",                     // 02
                    483:        "",                     // 03
                    484:        "",                     // 04
                    485:        "",                     // 05
                    486:        "",                     // 06
                    487:        "",                     // 07
                    488:        "",                     // 08
                    489:        "TAB",          // 09
                    490:        "CTRL",         // 0a
                    491:        "かな",               // 0b
                    492:        "SHIFT",        // 0c
                    493:        "SHIFT",        // 0d
                    494:        "CAPS",         // 0e
                    495:        "S.F",          // 0f
                    496: 
                    497:        "ESC",          // 10
                    498:        "BS",           // 11
                    499:        "Enter",        // 12
                    500:        "",                     // 13
                    501:        "Space",        // 14
                    502:        "DEL",          // 15
                    503:        "XFER",         // 16
                    504:        "VALID",        // 17
                    505:        "PF11",         // 18
                    506:        "PF12",         // 19
                    507:        "PF13",         // 1a
                    508:        "PF14",         // 1b
                    509:        "↑",          // 1c
                    510:        "←",          // 1d
                    511:        "→",          // 1e
                    512:        "↓",          // 1f
                    513: 
                    514:        "",                     // 20
                    515:        "",                     // 21
                    516:        "1!",           // 22
                    517:        "2\"",          // 23
                    518:        "3#",           // 24
                    519:        "4$",           // 25
                    520:        "5%",           // 26
                    521:        "6&",           // 27
                    522:        "7'",           // 28
                    523:        "8(",           // 29
                    524:        "9)",           // 2a
                    525:        "0",            // 2b
                    526:        "-=",           // 2c
                    527:        "^~",           // 2d
                    528:        "\\|",          // 2e
                    529:        "",                     // 2f
                    530: 
                    531:        "",                     // 30
                    532:        "",                     // 31
                    533:        "Q",            // 32
                    534:        "W",            // 33
                    535:        "E",            // 34
                    536:        "R",            // 35
                    537:        "T",            // 36
                    538:        "Y",            // 37
                    539:        "U",            // 38
                    540:        "I",            // 39
                    541:        "O",            // 3a
                    542:        "P",            // 3b
                    543:        "@`",           // 3c
                    544:        "[{",           // 3d
                    545:        "",                     // 3e
                    546:        "",                     // 3f
                    547: 
                    548:        "",                     // 40
                    549:        "",                     // 41
                    550:        "A",            // 42
                    551:        "S",            // 43
                    552:        "D",            // 44
                    553:        "F",            // 45
                    554:        "G",            // 46
                    555:        "H",            // 47
                    556:        "J",            // 48
                    557:        "K",            // 49
                    558:        "L",            // 4a
                    559:        ";+",           // 4b
                    560:        ":*",           // 4c
                    561:        "]}",           // 4d
                    562:        "",                     // 4e
                    563:        "",                     // 4f
                    564: 
                    565:        "",                     // 50
                    566:        "",                     // 51
                    567:        "Z",            // 52
                    568:        "X",            // 53
                    569:        "C",            // 54
                    570:        "V",            // 55
                    571:        "B",            // 56
                    572:        "N",            // 57
                    573:        "M",            // 58
                    574:        ",<",           // 59
                    575:        ".>",           // 5a
                    576:        "/?",           // 5b
                    577:        " _",           // 5c
                    578:        "",                     // 5d
                    579:        "",                     // 5e
                    580:        "",                     // 5f
                    581: 
                    582:        "",                     // 60
                    583:        "PAD+",         // 61
                    584:        "PAD-",         // 62
                    585:        "PAD7",         // 63
                    586:        "PAD8",         // 64
                    587:        "PAD9",         // 65
                    588:        "PAD4",         // 66
                    589:        "PAD5",         // 67
                    590:        "PAD6",         // 68
                    591:        "PAD1",         // 69
                    592:        "PAD2",         // 6a
                    593:        "PAD3",         // 6b
                    594:        "PAD0",         // 6c
                    595:        "PAD.",         // 6d
                    596:        "PADEn",        // 6e
                    597:        "",                     // 6f
                    598: 
                    599:        "",                     // 70
                    600:        "",                     // 71
                    601:        "F1",           // 72
                    602:        "F2",           // 73
                    603:        "F3",           // 74
                    604:        "F4",           // 75
                    605:        "F5",           // 76
                    606:        "F6",           // 77
                    607:        "F7",           // 78
                    608:        "F8",           // 79
                    609:        "F9",           // 7a
                    610:        "F10",          // 7b
                    611:        "PAD*",         // 7c
                    612:        "PAD/",         // 7d
                    613:        "PAD=",         // 7e
                    614:        "PAD,",         // 7f
                    615: };

unix.superglobalmegacorp.com

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