Annotation of nono/vm/keyboard.cpp, revision 1.1.1.8

1.1       root        1: //
                      2: // nono
1.1.1.3   root        3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
1.1       root        5: //
                      6: 
1.1.1.5   root        7: // 物理キーボードとソフトウェアキーボードについて
                      8: //
                      9: //       物理キーボード入力 ---------->+
                     10: //                                     OR --> VM Keyboard ---> VM (MFP/SIO)
                     11: //       ソフトウェアキーボード 入力 ->+           |
                     12: //                                                 |
                     13: //       ソフトウェアキーボード 表示 <-------------+
                     14: //
                     15: //     物理キーボードとソフトウェアキーボードからの入力は並列で対等とする。
                     16: //     つまり優劣を付けず後から成立したイベントで現在の状態を上書きする。
                     17: //     これは特に物理キーボードから [ALT]+[TAB] でウィンドウを切り替えた際に
                     18: //     [TAB] の Make は発生するが Break が VM に届かない (そのため高速モード
                     19: //     が抑制されたままになる) という事態をソフトウェアキーボードから復旧する
                     20: //     ために必要。
                     21: //
                     22: //     例えば、ソフトウェアキーボードであるキーを(右クリックで)長押ししたまま
                     23: //     (A)、物理キーボードで同じキーを押して(B)離す(C)と、まず A で Make が
                     24: //     成立、B は無視して (この時点ですでに Make 状態なので)、C で Break が
                     25: //     成立、となる。
                     26: //     Break が成立したのでソフトウェアキーボードの描画上もキー開放になる。
                     27: //     逆に物理キーボードであるキーを押したまま(A)、ソフトウェアキーボードで
                     28: //     同じキーをクリックする、つまり押して(B)離す(C) と、まず A で Make が
                     29: //     成立、B は無視され、C で Break が成立までは同じだが、引き続き物理キー
                     30: //     が押されたままならおそらくホストの動作によってもう一度 Make が入ること
                     31: //     になる。この動作は(望ましいかどうかはともかく)仕様として許容する。
                     32: //
                     33: //     また、ソフトウェアキーボードの表示は上図の通り、ソフトウェアキーボード
                     34: //     自身(のみ)の状態ではなく VM Keyboard 全体の現状を表示する表示器とする。
                     35: 
                     36: // SHIFT キーについて
                     37: //     物理キーボード層、ソフトウェアキーボード層、VM の Keyboard クラスは
                     38: //     いずれも左右の [SHIFT] キーは別個のキーとして管理しているが、X680x0 の
                     39: //     キーボードは左右の [SHIFT] キーが独立しておらず一つのキーのように
                     40: //     振る舞っている(はず)。
                     41: //
                     42: //     ヒューマンインタフェース的には例えば、
                     43: //     物理キーボードで 左[SHIFT]押下(A) -> 右[SHIFT]押下(B) -> 右[SHIFT]開放
                     44: //     (C) -> 左[SHIFT]開放(D) の順で操作すると、A で Make が成立、B は無視
                     45: //     ([SHIFT] はすでに押されているので)、C は無視([SHIFT] はまだ押されてる
                     46: //     ので)、D で Break が成立、となってほしい。これは明らかに人間がそのように
                     47: //     キーを操作しているため。
                     48: //     一方、ソフトウェアキーボードでは、右[SHIFT]を右クリック(押下維持)する
                     49: //     と両方の [SHIFT] キーが点灯する。この状態で左[SHIFT] を左クリック
                     50: //     (押下後即開放)すると、両方の [SHIFT] が開放されてほしい。これは、
                     51: //     ユーザからはどちらのキーが押下維持で点灯していて、どちらが押されてない
                     52: //     のに付随点灯しているかは区別できないため。
                     53: //
                     54: //     このことから、
                     55: //     o 物理キー入力は左右 [SHIFT] を区別する
                     56: //     o ソフトウェアキーボードは左右どちらのキーに対する操作でも、内部では
                     57: //       左右両方の [SHIFT] を押下開放する
                     58: //     o この結果、右 [SHIFT] と左 [SHIFT] の OR を代表値とし、
                     59: //       MFP への通知や表示(左右の [SHIFT] は常に連動) を行う。
                     60: //     でどうか。
                     61: //
                     62: //     物理 [SHIFT] キーを押し続けたまま、ソフトウェアキーボードから左クリック
                     63: //     (押下後即開放) すると、物理キーを押しているにも関わらず [SHIFT] キーは
                     64: //     開放される。これは上述の通り仕様である。
                     65: 
                     66: // LUNA のキーボードは左右の SHIFT キーの区別がある。このため、 LUNA は
                     67: // 特別処理をする必要はない。
                     68: // ただしゲスト上の入力ルーチンがこの区別をしているかは別問題である。
                     69: 
1.1       root       70: #include "keyboard.h"
1.1.1.5   root       71: #include "scheduler.h"
1.1.1.7   root       72: #include "uimessage.h"
1.1       root       73: 
1.1.1.2   root       74: std::unique_ptr<Keyboard> gKeyboard;
1.1       root       75: 
                     76: // コンストラクタ
                     77: Keyboard::Keyboard()
1.1.1.6   root       78:        : inherited("Keyboard")
1.1       root       79: {
1.1.1.5   root       80:        pressed.resize(KC_max);
                     81: 
                     82:        keyinput_event.func = (DeviceCallback_t)&Keyboard::KeyInputCallback;
                     83:        keyinput_event.time = 0;
                     84:        keyinput_event.SetName("Keyboard Input");
1.1       root       85: }
                     86: 
                     87: // デストラクタ
                     88: Keyboard::~Keyboard()
                     89: {
                     90: }
                     91: 
1.1.1.5   root       92: // リセット
                     93: void
                     94: Keyboard::ResetHard()
                     95: {
                     96:        // 内部状態を全部リセット
                     97: 
                     98:        inputqueue.Clear();
                     99:        sendqueue.Clear();
                    100:        std::fill(pressed.begin(), pressed.end(), false);
                    101:        num_of_pressed = 0;
                    102:        // キーが全部解放されたので通知
                    103:        gScheduler->RequestKeyPressed(false);
                    104: }
                    105: 
                    106: // キーを押した (外部から、共通キーコードで呼ばれる)
                    107: void
                    108: Keyboard::MakeKey(uint keycode)
                    109: {
                    110:        // ここは UI スレッドからも呼ばれるのでキューに突っ込むだけ
                    111:        {
                    112:                std::unique_lock<std::mutex> lock(mtx);
                    113:                inputqueue.Enqueue(keycode | KC_FLAG_MAKE);
                    114:        }
                    115:        keyinput_event.Start();
                    116: }
                    117: 
                    118: // キーを離した (外部から、共通キーコードで呼ばれる)
                    119: void
                    120: Keyboard::BreakKey(uint keycode)
                    121: {
                    122:        // ここは UI スレッドからも呼ばれるのでキューに突っ込むだけ
                    123:        {
                    124:                std::unique_lock<std::mutex> lock(mtx);
                    125:                inputqueue.Enqueue(keycode | KC_FLAG_BREAK);
                    126:        }
                    127:        keyinput_event.Start();
                    128: }
                    129: 
1.1.1.8 ! root      130: // 文字による入力
        !           131: // WX での文字入力モード、CLI からの入力、ターミナルエミュレーションでの
        !           132: // 入力によりキーボードの押し下げをエミュレートする。
        !           133: void
        !           134: Keyboard::CharInput(uint charcode)
        !           135: {
        !           136:        if (charcode >= char_key.size()) {
        !           137:                return;
        !           138:        }
        !           139: 
        !           140:        uint key = char_key[charcode];
        !           141:        uint code = KC_CODE(key);
        !           142:        if ((key & KM_SHIFT)) {
        !           143:                MakeKey(KC_SHIFT_L | KC_FLAG_POST);
        !           144:                MakeKey(KC_SHIFT_R | KC_FLAG_POST);
        !           145:        } else {
        !           146:                BreakKey(KC_SHIFT_L);
        !           147:                BreakKey(KC_SHIFT_R);
        !           148:        }
        !           149:        if ((key & KM_CTRL)) {
        !           150:                MakeKey(KC_CTRL | KC_FLAG_POST);
        !           151:        } else {
        !           152:                BreakKey(KC_CTRL);
        !           153:        }
        !           154:        MakeKey(code | KC_FLAG_POST);
        !           155:        BreakKey(code);
        !           156:        if ((key & KM_CTRL)) {
        !           157:                BreakKey(KC_CTRL);
        !           158:        }
        !           159:        if ((key & KM_SHIFT)) {
        !           160:                BreakKey(KC_SHIFT_L);
        !           161:                BreakKey(KC_SHIFT_R);
        !           162:        }
        !           163: }
        !           164: 
1.1.1.5   root      165: // キー入力コールバック
                    166: void
                    167: Keyboard::KeyInputCallback(Event& ev)
                    168: {
                    169:        for (;;) {
                    170:                uint keystat;
                    171:                {
                    172:                        std::unique_lock<std::mutex> lock(mtx);
                    173:                        if (inputqueue.Empty()) {
                    174:                                return;
                    175:                        }
                    176:                        keystat = inputqueue.Dequeue();
                    177:                }
                    178:                KeyInput(keystat);
                    179:        }
                    180: }
                    181: 
                    182: // キー入力を1つ処理する
1.1.1.6   root      183: // キーを送信したら true を返す
                    184: bool
                    185: Keyboard::KeyInputCommon(uint keystat)
1.1.1.5   root      186: {
                    187:        uint keycode = KC_CODE(keystat);
                    188:        bool ismake = KC_IS_MAKE(keystat);
                    189: 
                    190:        // 対応する機種別キーコードがなければ無視。
                    191:        // (ここでは調べるだけでまだ変換はしない)
                    192:        if (KeyToMDKey(keycode) == 0) {
1.1.1.6   root      193:                return false;
1.1.1.5   root      194:        }
                    195: 
                    196:        // このキーの状態が変化しないのなら何もしない。
                    197:        if (IsPressed(keycode) == ismake) {
1.1.1.6   root      198:                return false;
1.1.1.5   root      199:        }
                    200: 
                    201:        // 処理することが確定したのでログ
                    202:        // (離すほうは押すほうよりログレベルを1つ上げてある)
                    203:        if (ismake) {
1.1.1.6   root      204:                putlog(1, "MakeKey  %d(%s)", keycode, GetKeyName(keycode).c_str());
1.1.1.5   root      205:        } else {
1.1.1.6   root      206:                putlog(2, "BreakKey %d(%s)", keycode, GetKeyName(keycode).c_str());
1.1.1.5   root      207:        }
                    208: 
                    209:        // キーが押されてる間は VM の高速実行を抑制する
                    210:        // すべてのキーが離されたら高速モードを許可する
                    211:        pressed[keycode] = ismake;
                    212:        if (ismake) {
                    213:                if (num_of_pressed++ == 0) {
                    214:                        gScheduler->RequestKeyPressed(true);
                    215:                }
                    216:        } else {
                    217:                if (--num_of_pressed == 0) {
                    218:                        gScheduler->RequestKeyPressed(false);
                    219:                }
                    220:        }
                    221: 
1.1.1.8 ! root      222:        // UI に状態変更を通知。
        !           223:        // KC_FLAG_POST が立っていればキーコードも送信 (char 入力モード用)。
        !           224:        // 通知を受け取った UI 側が IsPressed() などでキーの現状を調べることが
        !           225:        // あるため pressed[] 更新後に通知する。
        !           226:        uint arg;
        !           227:        if (KC_IS_POST(keystat)) {
        !           228:                arg = keycode;
        !           229:        } else {
        !           230:                arg = 0;
        !           231:        }
        !           232:        UIMessage::Post(UIMessage::KEYBOARD, arg);
        !           233: 
1.1.1.5   root      234:        // 送信キューに登録
                    235:        sendqueue.Enqueue(keystat);
                    236: 
                    237:        // 機種依存のキー送信処理
                    238:        SendStart();
1.1.1.6   root      239:        return true;
1.1.1.5   root      240: }
                    241: 
1.1       root      242: // キー名を返す (主にデバッグ用)
                    243: const std::string
1.1.1.6   root      244: Keyboard::GetKeyName(uint keycode)
1.1       root      245: {
1.1.1.5   root      246:        if (keycode >= keyname.size()) {
                    247:                return string_format("(keycode=0x%x, out of range)", keycode);
1.1       root      248:        }
1.1.1.5   root      249:        if (keyname[keycode] == NULL) {
                    250:                return string_format("(keycode=0x%x)", keycode);
1.1       root      251:        }
1.1.1.5   root      252:        return std::string(keyname[keycode]);
1.1       root      253: }
                    254: 
                    255: /*static*/ std::vector<const char *>
                    256: Keyboard::keyname {
                    257:        "(none)",               // 00
                    258:        "BREAK",                // 01
                    259:        "COPY",                 // 02
                    260:        "romaji",               // 03
                    261:        "code",                 // 04
                    262:        "kigou",                // 05
                    263:        "touroku",              // 06
                    264:        "HELP",                 // 07
                    265:        "HOME",                 // 08
                    266:        "TAB",                  // 09
                    267:        "CTRL",                 // 0a
                    268:        "kana",                 // 0b
                    269:        "SHIFT_L",              // 0c
                    270:        "SHIFT_R",              // 0d
                    271:        "CAPS",                 // 0e
                    272:        "SF",                   // 0f
                    273: 
                    274:        "ESC",                  // 10
                    275:        "BS",                   // 11
                    276:        "enter",                // 12
                    277:        "INS",                  // 13
                    278:        "space",                // 14
                    279:        "DEL",                  // 15
                    280:        "XFER",                 // 16
                    281:        "VALID",                // 17
                    282:        "PF11",                 // 18
                    283:        "PF12",                 // 19
                    284:        "PF13",                 // 1a
                    285:        "PF14",                 // 1b
                    286:        "up",                   // 1c
                    287:        "left",                 // 1d
                    288:        "right",                // 1e
                    289:        "down",                 // 1f
                    290: 
                    291:        "ROLLUP",               // 20
                    292:        "ROLLDOWN",             // 21
                    293:        "1",                    // 22
                    294:        "2",                    // 23
                    295:        "3",                    // 24
                    296:        "4",                    // 25
                    297:        "5",                    // 26
                    298:        "6",                    // 27
                    299:        "7",                    // 28
                    300:        "8",                    // 29
                    301:        "9",                    // 2a
                    302:        "0",                    // 2b
                    303:        "minus",                // 2c
                    304:        "circum",               // 2d
                    305:        "backslash",    // 2e
                    306:        "UNDO",                 // 2f
                    307: 
                    308:        "OPT1",                 // 30
                    309:        "OPT2",                 // 31
                    310:        "Q",                    // 32
                    311:        "W",                    // 33
                    312:        "E",                    // 34
                    313:        "R",                    // 35
                    314:        "T",                    // 36
                    315:        "Y",                    // 37
                    316:        "U",                    // 38
                    317:        "I",                    // 39
                    318:        "O",                    // 3a
                    319:        "P",                    // 3b
                    320:        "at",                   // 3c
                    321:        "bracketleft",  // 3d
                    322:        "hira",                 // 3e
                    323:        "zenkaku",              // 3f
                    324: 
                    325:        NULL,                   // 40
                    326:        NULL,                   // 41
                    327:        "A",                    // 42
                    328:        "S",                    // 43
                    329:        "D",                    // 44
                    330:        "F",                    // 45
                    331:        "G",                    // 46
                    332:        "H",                    // 47
                    333:        "J",                    // 48
                    334:        "K",                    // 49
                    335:        "L",                    // 4a
                    336:        "semicolon",    // 4b
                    337:        "colon",                // 4c
                    338:        "bracketright", // 4d
                    339:        NULL,                   // 4e
                    340:        NULL,                   // 4f
                    341: 
                    342:        NULL,                   // 50
                    343:        NULL,                   // 51
                    344:        "Z",                    // 52
                    345:        "X",                    // 53
                    346:        "C",                    // 54
                    347:        "V",                    // 55
                    348:        "B",                    // 56
                    349:        "N",                    // 57
                    350:        "M",                    // 58
                    351:        "comma",                // 59
                    352:        "period",               // 5a
                    353:        "slash",                // 5b
                    354:        "underscore",   // 5c
                    355:        NULL,                   // 5d
                    356:        NULL,                   // 5e
                    357:        NULL,                   // 5f
                    358: 
                    359:        NULL,                   // 60
                    360:        "PAD_plus",             // 61
                    361:        "PAD_minus",    // 62
                    362:        "PAD_7",                // 63
                    363:        "PAD_8",                // 64
                    364:        "PAD_9",                // 65
                    365:        "PAD_4",                // 66
                    366:        "PAD_5",                // 67
                    367:        "PAD_6",                // 68
                    368:        "PAD_1",                // 69
                    369:        "PAD_2",                // 6a
                    370:        "PAD_3",                // 6b
                    371:        "PAD_0",                // 6c
                    372:        "PAD_decimal",  // 6d
                    373:        "PAD_enter",    // 6e
                    374:        "PAD_CLR",              // 6f
                    375: 
                    376:        NULL,                   // 70
                    377:        NULL,                   // 71
                    378:        "F1",                   // 72
                    379:        "F2",                   // 73
                    380:        "F3",                   // 74
                    381:        "F4",                   // 75
                    382:        "F5",                   // 76
                    383:        "F6",                   // 77
                    384:        "F7",                   // 78
                    385:        "F8",                   // 79
                    386:        "F9",                   // 7a
                    387:        "F10",                  // 7b
                    388:        "PAD_multiply", // 7c
                    389:        "PAD_divide",   // 7d
                    390:        "PAD_equal",    // 7e
                    391:        "PAD_comma",    // 7f
                    392: 
                    393:        "XF1",                  // 80
                    394:        "XF2",                  // 81
                    395:        "XF3",                  // 82
                    396:        "XF4",                  // 83
                    397:        "XF5",                  // 84
1.1.1.5   root      398:        "SHIFT",                // 85
1.1       root      399: };
1.1.1.8 ! root      400: 
        !           401: // 文字対キーストローク表
        !           402: // 文字による入力エミュレーションで使用。
        !           403: /*static*/ std::vector<uint>
        !           404: Keyboard::char_key = {
        !           405:        0,                                                      // NONE
        !           406:        KC_A                    + KM_CTRL,      // 0x01 ^A
        !           407:        KC_B                    + KM_CTRL,      // 0x02 ^B
        !           408:        KC_C                    + KM_CTRL,      // 0x03 ^C
        !           409:        KC_D                    + KM_CTRL,      // 0x04 ^D
        !           410:        KC_E                    + KM_CTRL,      // 0x05 ^E
        !           411:        KC_F                    + KM_CTRL,      // 0x06 ^F
        !           412:        KC_G                    + KM_CTRL,      // 0x07 ^G
        !           413:        KC_BS,                                          // 0x08 ^H
        !           414:        KC_TAB,                                         // 0x09 ^I
        !           415:        KC_J                    + KM_CTRL,      // 0x0a ^J
        !           416:        KC_K                    + KM_CTRL,      // 0x0b ^K
        !           417:        KC_L                    + KM_CTRL,      // 0x0c ^L
        !           418:        KC_enter,                                       // 0x0d ^M
        !           419:        KC_N                    + KM_CTRL,      // 0x0e ^N
        !           420:        KC_O                    + KM_CTRL,      // 0x0f ^O
        !           421:        KC_P                    + KM_CTRL,      // 0x10 ^P
        !           422:        KC_Q                    + KM_CTRL,      // 0x11 ^Q
        !           423:        KC_R                    + KM_CTRL,      // 0x12 ^R
        !           424:        KC_S                    + KM_CTRL,      // 0x13 ^S
        !           425:        KC_T                    + KM_CTRL,      // 0x14 ^T
        !           426:        KC_U                    + KM_CTRL,      // 0x15 ^U
        !           427:        KC_V                    + KM_CTRL,      // 0x16 ^V
        !           428:        KC_W                    + KM_CTRL,      // 0x17 ^W
        !           429:        KC_X                    + KM_CTRL,      // 0x18 ^X
        !           430:        KC_Y                    + KM_CTRL,      // 0x19 ^Y
        !           431:        KC_Z                    + KM_CTRL,      // 0x1a ^Z
        !           432: 
        !           433:        KC_ESC,                                         // 0x1b ^[
        !           434:        KC_backslash    + KM_CTRL,      // 0x1c ^'\'
        !           435:        KC_bracketright + KM_CTRL,      // 0x1d ^]
        !           436:        KC_circum               + KM_CTRL,      // 0x1e ^^
        !           437:        KC_underscore   + KM_CTRL,      // 0x1f ^_
        !           438: 
        !           439:        KC_space,                                       // 0x20 ' '
        !           440:        KC_1                    + KM_SHIFT,     // 0x21 !
        !           441:        KC_2                    + KM_SHIFT,     // 0x22 "
        !           442:        KC_3                    + KM_SHIFT,     // 0x23 #
        !           443:        KC_4                    + KM_SHIFT,     // 0x24 $
        !           444:        KC_5                    + KM_SHIFT,     // 0x25 %
        !           445:        KC_6                    + KM_SHIFT,     // 0x26 &
        !           446:        KC_7                    + KM_SHIFT,     // 0x27 '
        !           447:        KC_8                    + KM_SHIFT,     // 0x28 (
        !           448:        KC_9                    + KM_SHIFT,     // 0x29 )
        !           449:        KC_colon                + KM_SHIFT,     // 0x2a *
        !           450:        KC_semicolon    + KM_SHIFT,     // 0x2b +
        !           451:        KC_comma,                                       // 0x2c ,
        !           452:        KC_minus,                                       // 0x2d -
        !           453:        KC_period,                                      // 0x2e .
        !           454:        KC_slash,                                       // 0x2f /
        !           455: 
        !           456:        KC_0,                                           // 0x30 0
        !           457:        KC_1,                                           // 0x31 1
        !           458:        KC_2,                                           // 0x32 2
        !           459:        KC_3,                                           // 0x33 3
        !           460:        KC_4,                                           // 0x34 4
        !           461:        KC_5,                                           // 0x35 5
        !           462:        KC_6,                                           // 0x36 6
        !           463:        KC_7,                                           // 0x37 7
        !           464:        KC_8,                                           // 0x38 8
        !           465:        KC_9,                                           // 0x39 9
        !           466:        KC_colon,                                       // 0x3a :
        !           467:        KC_semicolon,                           // 0x3b ;
        !           468:        KC_comma                + KM_SHIFT,     // 0x3c <
        !           469:        KC_minus                + KM_SHIFT,     // 0x3d =
        !           470:        KC_period               + KM_SHIFT,     // 0x3e >
        !           471:        KC_slash                + KM_SHIFT,     // 0x3f ?
        !           472: 
        !           473:        KC_at,                                          // 0x40 @
        !           474:        KC_A                    + KM_SHIFT,     // 0x41 A
        !           475:        KC_B                    + KM_SHIFT,     // 0x42 B
        !           476:        KC_C                    + KM_SHIFT,     // 0x43 C
        !           477:        KC_D                    + KM_SHIFT,     // 0x44 D
        !           478:        KC_E                    + KM_SHIFT,     // 0x45 E
        !           479:        KC_F                    + KM_SHIFT,     // 0x46 F
        !           480:        KC_G                    + KM_SHIFT,     // 0x47 G
        !           481:        KC_H                    + KM_SHIFT,     // 0x48 H
        !           482:        KC_I                    + KM_SHIFT,     // 0x49 I
        !           483:        KC_J                    + KM_SHIFT,     // 0x4a J
        !           484:        KC_K                    + KM_SHIFT,     // 0x4b K
        !           485:        KC_L                    + KM_SHIFT,     // 0x4c L
        !           486:        KC_M                    + KM_SHIFT,     // 0x4d M
        !           487:        KC_N                    + KM_SHIFT,     // 0x4e N
        !           488:        KC_O                    + KM_SHIFT,     // 0x4f O
        !           489:        KC_P                    + KM_SHIFT,     // 0x50 P
        !           490:        KC_Q                    + KM_SHIFT,     // 0x51 Q
        !           491:        KC_R                    + KM_SHIFT,     // 0x52 R
        !           492:        KC_S                    + KM_SHIFT,     // 0x53 S
        !           493:        KC_T                    + KM_SHIFT,     // 0x54 T
        !           494:        KC_U                    + KM_SHIFT,     // 0x55 U
        !           495:        KC_V                    + KM_SHIFT,     // 0x56 V
        !           496:        KC_W                    + KM_SHIFT,     // 0x57 W
        !           497:        KC_X                    + KM_SHIFT,     // 0x58 X
        !           498:        KC_Y                    + KM_SHIFT,     // 0x59 Y
        !           499:        KC_Z                    + KM_SHIFT,     // 0x5a Z
        !           500: 
        !           501:        KC_bracketleft,                         // 0x5b [
        !           502:        KC_backslash,                           // 0x5c '\'
        !           503:        KC_bracketright,                        // 0x5d ]
        !           504:        KC_circum,                                      // 0x5e ^
        !           505:        KC_underscore   + KM_SHIFT,     // 0x5f _
        !           506: 
        !           507:        KC_at                   + KM_SHIFT,     // 0x60 `
        !           508:        KC_A,                                           // 0x61 a
        !           509:        KC_B,                                           // 0x62 b
        !           510:        KC_C,                                           // 0x63 c
        !           511:        KC_D,                                           // 0x64 d
        !           512:        KC_E,                                           // 0x65 e
        !           513:        KC_F,                                           // 0x66 f
        !           514:        KC_G,                                           // 0x67 g
        !           515:        KC_H,                                           // 0x68 h
        !           516:        KC_I,                                           // 0x69 i
        !           517:        KC_J,                                           // 0x6a j
        !           518:        KC_K,                                           // 0x6b k
        !           519:        KC_L,                                           // 0x6c l
        !           520:        KC_M,                                           // 0x6d m
        !           521:        KC_N,                                           // 0x6e n
        !           522:        KC_O,                                           // 0x6f o
        !           523:        KC_P,                                           // 0x70 p
        !           524:        KC_Q,                                           // 0x71 q
        !           525:        KC_R,                                           // 0x72 r
        !           526:        KC_S,                                           // 0x73 s
        !           527:        KC_T,                                           // 0x74 t
        !           528:        KC_U,                                           // 0x75 u
        !           529:        KC_V,                                           // 0x76 v
        !           530:        KC_W,                                           // 0x77 w
        !           531:        KC_X,                                           // 0x78 x
        !           532:        KC_Y,                                           // 0x79 y
        !           533:        KC_Z,                                           // 0x7a z
        !           534: 
        !           535:        KC_bracketleft  + KM_SHIFT,     // 0x7b {
        !           536:        KC_backslash    + KM_SHIFT,     // 0x7c |
        !           537:        KC_bracketright + KM_SHIFT,     // 0x7d }
        !           538:        KC_circum               + KM_SHIFT,     // 0x7e ~
        !           539:        KC_none,                                        // 0x7f DEL
        !           540: 
        !           541:        KC_at                   + KM_CTRL,      // 0x80 CC_NUL
        !           542:        KC_F1,                                          // 0x81 CC_F1
        !           543:        KC_F2,                                          // 0x82 CC_F2
        !           544:        KC_F3,                                          // 0x83 CC_F3
        !           545:        KC_F4,                                          // 0x84 CC_F4
        !           546:        KC_F5,                                          // 0x85 CC_F5
        !           547:        KC_F6,                                          // 0x86 CC_F6
        !           548:        KC_F7,                                          // 0x87 CC_F7
        !           549:        KC_F8,                                          // 0x88 CC_F8
        !           550:        KC_F9,                                          // 0x89 CC_F9
        !           551:        KC_F10,                                         // 0x8a CC_Fa
        !           552:        0,                                                      // 0x8b
        !           553:        KC_up,                                          // 0x8c CC_up
        !           554:        KC_left,                                        // 0x8d CC_left
        !           555:        KC_right,                                       // 0x8e CC_right
        !           556:        KC_down,                                        // 0x8f CC_down
        !           557: };

unix.superglobalmegacorp.com

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