|
|
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.10 root 7: //
8: // X68k キーボード
9: //
10:
1.1.1.5 root 11: // 送信タイミングについて
12: // キーボードは MFP の USART に繋がっている。
13: // MFP USART の RR 線 (Receiver Ready) は受信可能なら 'H'、受信中は 'L' に
14: // なっている。キーボードは RR が 'H' の時だけデータを送信する。また、
15: // システムポート#4 の KEY CTRL = 0 (キーデータ送信不可) はこの RR を
16: // 'L' に落とす AND 回路になっている。キーボードからの送信は 2400bps、
17: // ストップビット1、パリティなしなので、1バイトの送信に 3.75 msec かかる。
18: // 実装では、キーボードは MFP の RR が 'H' なら MFP にキーデータを送信。
19: // MFP 側で RR を 'L' にして 3.75 msec をイベントで待った後、キーを処理
20: // して RR を 'H' に戻すことにする。
21:
22: // SHIFT キーについては keyboard.cpp のコメントを参照。
1.1.1.4 root 23:
1.1 root 24: #include "x68kkbd.h"
25: #include "mfp.h"
1.1.1.16 root 26: #include "monitor.h"
1.1.1.7 root 27: #include "scc.h"
1.1.1.10 root 28: #include "scheduler.h"
1.1.1.5 root 29: #include "sysport.h"
1.1.1.18! root 30: #include "uimessage.h"
1.1 root 31:
32: // コンストラクタ
33: X68030Keyboard::X68030Keyboard()
34: {
1.1.1.4 root 35: led.resize(7);
1.1.1.6 root 36:
1.1.1.16 root 37: monitor = gMonitorManager->Regist(ID_MONITOR_KEYBOARD, this);
38: monitor->func = ToMonitorCallback(&X68030Keyboard::MonitorUpdate);
39: monitor->SetSize(47, 5);
1.1.1.3 root 40: }
41:
42: // デストラクタ
43: X68030Keyboard::~X68030Keyboard()
44: {
45: }
46:
1.1.1.12 root 47: // 初期化
48: bool
49: X68030Keyboard::Init()
50: {
51: if (inherited::Init() == false) {
52: return false;
53: }
54:
55: mfp = GetMFPDevice();
56: scc = GetSCCDevice();
57: sysport = GetSysportDevice();
58:
1.1.1.15 root 59: rept_event.func = ToEventCallback(&X68030Keyboard::ReptCallback);
60: rept_event.time = 0;
61: rept_event.SetName("Keyboard Repeat");
62: scheduler->RegistEvent(rept_event);
63:
64: mouse_event.func = ToEventCallback(&X68030Keyboard::MouseCallback);
65: mouse_event.SetName("Mouse");
66: scheduler->RegistEvent(mouse_event);
67:
1.1.1.12 root 68: return true;
69: }
70:
1.1.1.10 root 71: // キーボード接続時の MD 固有処理
1.1.1.4 root 72: void
1.1.1.10 root 73: X68030Keyboard::MDConnect()
1.1.1.3 root 74: {
1.1.1.11 root 75: rept_delay_data = 3;
1.1.1.6 root 76: rept_delay = 500_msec;
1.1.1.11 root 77: rept_time_data = 4;
1.1.1.6 root 78: rept_time = 110_msec;
79: rept_key = KC_none;
1.1.1.12 root 80: scheduler->StopEvent(rept_event);
1.1.1.4 root 81:
82: led_darkness = 0;
1.1.1.7 root 83:
1.1.1.10 root 84: // XXX マウスの接続取り外しは未定
1.1.1.12 root 85: scheduler->StopEvent(mouse_event);
1.1.1.10 root 86: mouse_event.code = 0;
87: }
88:
89: // キーボード取り外し時の MD 固有処理
90: void
91: X68030Keyboard::MDDisconnect()
92: {
1.1.1.12 root 93: scheduler->StopEvent(rept_event);
94: scheduler->StopEvent(mouse_event);
1.1.1.10 root 95: mouse_event.code = 0;
1.1 root 96: }
97:
1.1.1.11 root 98: // モニター
99: void
100: X68030Keyboard::MonitorUpdate(Monitor *, TextScreen& screen)
101: {
102: int y;
103:
104: screen.Clear();
105: y = 0;
106:
107: // 0 1 2 3 4
108: // 01234567890123456789012345678901234567890123456
109: // Key Enable: % MSCTRL: %
110: // Ctrl Enable: OPT.2 Enable: %
111: // Key Repeat: Delay $x(????msec)
112: // Repeat $x(????msec)
1.1.1.13 root 113: // LED: $xx Zen Hira INS CAPS Code Roma Kana
1.1.1.11 root 114: // LED Darkness: x
115:
116: // KEY_EN, CTRL_EN, OPT2_EN, MSCTRL は未実装
117:
118: // キーリピート
119: screen.Puts(0, y, "Key Repeat:");
1.1.1.15 root 120: screen.Print(12, y++, "Delay $%x(%4umsec)",
121: rept_delay_data, (uint)(rept_delay / 1_msec));
122: screen.Print(12, y++, "Repeat $%x(%4umsec)",
123: rept_time_data, (uint)(rept_time / 1_msec));
1.1.1.11 root 124:
125: // マウス
126: int mx = mouse_x;
127: int my = mouse_y;
128: if (mx < -999)
129: mx = -999;
130: if (mx > 999)
131: mx = 999;
132: if (my < -999)
133: my = -999;
134: if (my > 999)
135: my = 999;
136:
137: screen.Puts(0, y, "Mouse:");
138: screen.Print(12, y, "x=%-4d y=%-4d", mx, my);
139: screen.Print(27, y, TA::OnOff(mouse_l), "L");
140: screen.Print(29, y, TA::OnOff(mouse_r), "R");
141: y++;
142:
143: // LED
144: screen.Puts(0, y, "LED:");
145: static const char * const ledname[] = {
146: "Zen", "Hira", "INS", "CAPS", "Code", "Roma", "Kana"
147: };
148: uint val = 0x80;
149: for (int i = 0; i < 7; i++) {
150: int n = 6 - i;
1.1.1.13 root 151: screen.Puts(12 + i * 5, y, TA::OnOff(led[n]), ledname[i]);
1.1.1.11 root 152: if (led[n] == 0) {
153: val |= 1 << n;
154: }
155: }
1.1.1.13 root 156: screen.Print(5, y, "$%02x", val);
1.1.1.11 root 157: y++;
158:
159: // LED の明るさ (というより暗さ)
1.1.1.15 root 160: screen.Print(0, y++, "LED Darkness: %u", led_darkness);
1.1.1.11 root 161: }
162:
1.1.1.9 root 163: // 共通 keystat を X680x0 キーコードに変換して返す。
1.1.1.5 root 164: // 対応する X680x0 のキーがなければ 0 を返す。
165: uint
1.1.1.9 root 166: X68030Keyboard::KeyToMDKey(uint keystat) const
1.1 root 167: {
1.1.1.9 root 168: uint keycode = KC_CODE(keystat);
1.1.1.5 root 169: if (keycode >= countof(keycode2x68kkey_table)) {
170: return 0;
171: }
1.1 root 172:
1.1.1.9 root 173: uint mdkey = keycode2x68kkey_table[keycode];
174: if (mdkey && KC_IS_BREAK(keystat)) {
175: mdkey |= 0x80;
176: }
177: return mdkey;
1.1.1.5 root 178: }
179:
180: // シフト状態なら true を返す
181: bool
182: X68030Keyboard::IsShift() const
183: {
184: return pressed[KC_SHIFT];
185: }
1.1 root 186:
1.1.1.6 root 187: // キー入力を1つ処理する
188: void
189: X68030Keyboard::KeyInput(uint keystat)
1.1.1.5 root 190: {
1.1.1.6 root 191: uint keycode = KC_CODE(keystat);
192: bool ismake = KC_IS_MAKE(keystat);
193:
194: assert(keycode < KC_max);
195:
1.1.1.5 root 196: // X68k のキーボードは左右の [SHIFT] の区別がない。
197: // KC_SHIFT_L はホストの物理キー左 [SHIFT] に対応、
198: // KC_SHIFT_R はホストの物理キー右 [SHIFT] に対応、
199: // KC_SHIFT はソフトウェアキーボードからの左右のない [SHIFT] に対応。
200: // どのキーコードで問い合わせをされても KC_SHIFT_L と KC_SHIFT_R の OR が
201: // [SHIFT] キーの状態である。
202: if (keycode == KC_SHIFT_L || keycode == KC_SHIFT_R) {
1.1.1.17 root 203: // それぞれのシフトキーが押されたことは覚えておく。
204: SetPressed(keycode, ismake);
205: // 反対側のキーが押されていたら、いま押した・離したほうは無視する
206: if (IsPressed(keycode ^ 1)) {
1.1.1.6 root 207: return;
1.1.1.5 root 208: }
1.1.1.6 root 209: keycode = KC_SHIFT;
1.1.1.8 root 210:
1.1.1.6 root 211: // keycode を変更したので keystat も更新
1.1.1.8 root 212: keystat = (keystat & 0xff00) | keycode;
1.1 root 213: }
1.1.1.5 root 214:
1.1.1.6 root 215: // 共通処理へ
216: if (KeyInputCommon(keystat) == false) {
217: return;
218: }
1.1 root 219:
1.1.1.4 root 220: // LED は MPU 側から点灯/消灯指示が来るのでここでは何もしなくてよい
1.1 root 221:
1.1.1.6 root 222: // ここでキーリピートのイベント開始処理
223: if (ismake) {
224: // いま起きているリピートは中止
225: rept_key = keycode;
226: rept_event.time = rept_delay;
1.1.1.12 root 227: scheduler->RestartEvent(rept_event);
1.1.1.6 root 228: } else {
229: if (keycode == rept_key) {
230: // 同じキーのブレークでのみリピートを終了する
1.1.1.12 root 231: scheduler->StopEvent(rept_event);
1.1.1.6 root 232: rept_key = KC_none;
233: }
234: }
235: }
1.1.1.5 root 236:
1.1.1.6 root 237: void
238: X68030Keyboard::ReptCallback(Event& ev)
239: {
240: // リピート
1.1.1.9 root 241: sendqueue.Enqueue(KeyToMDKey(rept_key));
1.1.1.6 root 242: SendStart();
243:
244: // 二回目以降のリピートは rept_time 間隔で発生
245: rept_event.time = rept_time;
1.1.1.12 root 246: scheduler->StartEvent(rept_event);
1.1 root 247: }
1.1.1.5 root 248:
249: // MFP、システムポートと、キーボードの関係。
250: //
251: // キーボードの Ready 信号は MFP の RR とシステムポートの KeyCtrl の
252: // AND で作られているが、この AND 部分はキーボードが担当することにする。
253: // そのほうが都合がいいため。
254: //
255: // <- 本体 || キーボード ->
256: // MFP ||
257: // --------+ : || +-----
1.1.1.10 root 258: // | : |& || |
259: // RR|o-------|& || |
260: // --------+ : |&---------|T0 (Ready)
261: // +-----|& || |
262: // Sysport | : |& || |
1.1.1.5 root 263: // --------+ | : || |
264: // KeyCtrl|--+ : || +-----
265: // | : ||
266: // :エミュレータでは点線から右をキーボードが担当
1.1 root 267:
1.1.1.5 root 268: // キーデータを送信
1.1 root 269: void
1.1.1.5 root 270: X68030Keyboard::SendStart()
1.1 root 271: {
1.1.1.12 root 272: if (mfp->RxIsReady()) {
1.1.1.5 root 273: // 本体が Ready ならここで送信
274: Ready();
275: } else {
276: // そうでない場合、ここでは処理は不要。
277: // MFP 側が受信可能になると Ready() がコールされ、そっちで処理される
1.1 root 278: }
279: }
280:
1.1.1.5 root 281: // MFP からの Ready 通知
282: // 実際にはキーボード側が MFP (を含む本体側) が Ready になるのを待っている
283: // のだが、待っているを作るのは大変なので。
1.1.1.2 root 284: void
1.1.1.5 root 285: X68030Keyboard::Ready()
1.1.1.2 root 286: {
1.1.1.12 root 287: if (sysport->GetKeyCtrl()) {
1.1.1.5 root 288: // KEYCTRL が有効なら処理する
289:
1.1.1.9 root 290: // ここで取り出せるのは MDKey。
291: uint x68kkey;
292: if (sendqueue.Dequeue(&x68kkey)) {
1.1.1.5 root 293: // あれば送信
294:
295: // 呼ばれたからには送信できるはず
1.1.1.12 root 296: assert(mfp->RxIsReady() == true);
1.1.1.5 root 297:
298: assert(x68kkey != 0);
299:
300: // 送信
1.1.1.12 root 301: mfp->Rx(x68kkey);
1.1.1.5 root 302: } else {
303: // なければ何もせず終了
304: }
305: } else {
306: // KEYCTRL が無効なら何もしないだけでなく、キューをクリア。
307: // KEYCTRL が無効から有効になった時に、無効だった期間のキーデータを
308: // 吐き出すのはおかしいので。
309: sendqueue.Clear();
310: }
1.1.1.2 root 311: }
312:
1.1.1.5 root 313: // マウス入力
1.1.1.4 root 314: void
1.1.1.5 root 315: X68030Keyboard::MouseInput(int x, int y, bool rb, bool lb, bool mb)
1.1.1.4 root 316: {
1.1.1.7 root 317: // ホストからマウスイベントのたびに呼ばれるので、ここで積算。
318: // 20msec ごとのサンプリングのタイミングで積算結果を処理する。
319: // X68k のマウスの Y 方向は下に動く方向がプラス。
320: mouse_x += x;
321: mouse_y += y;
322: mouse_r = rb;
323: mouse_l = lb;
324: }
325:
326: // マウスデータを VM に送信
327: void
328: X68030Keyboard::MouseSendStart()
329: {
330: uint8 status = 0;
331:
1.1.1.10 root 332: // 最後のバイトを送るまでは、次は受け付けられない。
333: // 送信中かどうかは mouse_event.code で判断している。
334: if (mouse_event.code != 0) {
1.1.1.7 root 335: return;
336: }
337:
338: if (mouse_x > 127) {
339: status |= XOVFL;
340: mouse_x = 127;
341: }
342: if (mouse_x < -128) {
343: status |= XUNFL;
344: mouse_x = -128;
345: }
346: if (mouse_y > 127) {
347: status |= YOVFL;
348: mouse_y = 127;
349: }
350: if (mouse_y < -128) {
351: status |= YUNFL;
352: mouse_y = -128;
353: }
354: status |= mouse_l ? SW_L : 0;
355: status |= mouse_r ? SW_R : 0;
356:
1.1.1.10 root 357: // この時点でラッチしてみる(?)
358: mouse_data[0] = status;
359: mouse_data[1] = mouse_x;
360: mouse_data[2] = mouse_y;
1.1.1.7 root 361:
362: mouse_x = 0;
363: mouse_y = 0;
364:
1.1.1.10 root 365: // 1バイト目は MSCTRL が立ち下がってから 700us 以上後から送信。
1.1.1.14 root 366: // さらに1バイトの送信に 2.3msec かかる(このすぐ下参照)。
367: mouse_event.time = 700_usec + 2300_usec;
1.1.1.10 root 368: mouse_event.code = 1;
1.1.1.12 root 369: scheduler->RestartEvent(mouse_event);
1.1.1.7 root 370: }
371:
1.1.1.10 root 372: // マウスデータのイベントコールバック
1.1.1.7 root 373: void
374: X68030Keyboard::MouseCallback(Event& ev)
375: {
1.1.1.10 root 376: // マウスは 4800bps で、ストップビット 2 なので11ビット。
377: // 1/4800 * 11 = 2.29166 msec なので、1バイトあたり 2.3 msec にしておく。
378:
1.1.1.14 root 379: // code 1 なら1バイト目 (mouse_data[0]) の送信完了時刻が来た。
380: // code 2 なら2バイト目 (mouse_data[1]) の送信完了時刻が来た。
381: // code 3 なら3バイト目 (mouse_data[2]) の送信完了時刻が来た。
382: // 3バイト目を送信してイベントループ終了。
1.1.1.10 root 383:
1.1.1.14 root 384: scc->Rx(1, mouse_data[mouse_event.code - 1]);
385:
386: if (mouse_event.code < 3) {
1.1.1.10 root 387: // 次のイベント
388: mouse_event.time = 2300_usec;
389: mouse_event.code++;
1.1.1.12 root 390: scheduler->StartEvent(mouse_event);
1.1.1.10 root 391: } else {
1.1.1.14 root 392: // 3 バイト目の送信が終わった。
1.1.1.10 root 393: mouse_event.code = 0;
394: }
1.1.1.4 root 395: }
396:
397: // ホストからの制御
398: void
399: X68030Keyboard::Command(uint32 data)
400: {
401: if (data < 0x40) {
402: // $00-$3f TV 制御
403: // (実装不要)
1.1.1.11 root 404: putlog(2, "Command TV control $%02x", (data & 0x1f));
1.1.1.4 root 405:
406: } else if (data < 0x48) {
407: // $40-$47 MSCTRL 信号制御
408: // こいつは頻度が高いのでログレベルを上げておく
1.1.1.15 root 409: putlog(3, "Command MSCTRL control %u", (data & 1));
1.1.1.4 root 410:
411: } else if (data < 0x50) {
412: // $48-$4f キーデータ送出許可
1.1.1.15 root 413: putlog(1, "Command Key send enable %u (NOT IMPLEMENTED)", (data & 1));
1.1.1.4 root 414:
415: } else if (data < 0x54) {
416: // $50-$53 ディスプレイ制御モード選択
417: // (実装不要)
1.1.1.15 root 418: putlog(2, "Command Display control mode %u", (data & 1));
1.1.1.4 root 419:
420: } else if (data < 0x58) {
421: // $54-$57 LED 明るさ選択
422: // 0 が明るく 3 が暗いので、明るさというより暗さ。
423: led_darkness = (data & 3);
1.1.1.15 root 424: putlog(1, "Command LED brightness %u", led_darkness);
1.1.1.18! root 425: UIMessage::Post(UIMessage::KEYBOARD);
1.1.1.4 root 426:
427: } else if (data < 0x5c) {
428: // $58-$5b 本体からのディスプレイ制御許可
429: // (実装不要)
1.1.1.15 root 430: putlog(2, "Command Display control enable %u", (data & 1));
1.1.1.4 root 431:
432: } else if (data < 0x60) {
433: // $5c-$5f OPT.2 によるディスプレイ制御許可
434: // (実装不要)
1.1.1.15 root 435: putlog(2, "Command OPT2 control enable %u", (data & 1));
1.1.1.4 root 436:
437: } else if (data < 0x70) {
438: // $60-$6f リピートまでの時間
1.1.1.11 root 439: rept_delay_data = data & 15;
440: rept_delay = 200_msec + rept_delay_data * 100_msec;
1.1.1.15 root 441: putlog(1, "Command Repeat Delay %u (%u msec)", rept_delay_data,
442: (uint)(rept_delay / 1_msec));
1.1.1.4 root 443:
444: } else if (data < 0x80) {
445: // $70-$7f リピート間隔
1.1.1.11 root 446: rept_time_data = data & 15;
447: rept_time = 30_msec + rept_time_data * rept_time_data * 5_msec;
1.1.1.15 root 448: putlog(1, "Command Repeat time %d (%u msec)", rept_time_data,
449: (uint)(rept_time / 1_msec));
1.1.1.4 root 450:
451: } else {
452: // $80-$ff LED 制御
453: data &= 0x7f;
1.1.1.11 root 454: putlog(1, "Command LED control $%02x", data);
1.1.1.4 root 455: uint32 b = 0x01;
456: for (int i = 0; i < led.size(); i++) {
457: // data は %0 で点灯、led[] は true で点灯
458: led[i] = ((data & b) == 0);
459: b <<= 1;
460: }
1.1.1.18! root 461: UIMessage::Post(UIMessage::KEYBOARD);
1.1.1.4 root 462: }
463: }
464:
1.1 root 465: // キーコード変換表
466: // 共通キーコードから X680x0 キーコードに変換する。
467: /*static*/ const uint
1.1.1.5 root 468: X68030Keyboard::keycode2x68kkey_table[KC_max] = {
1.1 root 469: NoKey, // [00]
470: X68kKey_BREAK, // [01]
471: X68kKey_COPY, // [02]
472: X68kKey_romaji, // [03]
1.1.1.4 root 473: X68kKey_code, // [04]
1.1 root 474: X68kKey_kigou, // [05]
475: X68kKey_touroku, // [06]
476: X68kKey_HELP, // [07]
1.1.1.9 root 477: X68kKey_SHIFT, // [08]
1.1 root 478: X68kKey_TAB, // [09]
479: X68kKey_CTRL, // [0a]
480: X68kKey_kana, // [0b]
481: X68kKey_SHIFT, // [0c]
1.1.1.5 root 482: X68kKey_SHIFT, // [0d]
1.1 root 483: X68kKey_CAPS, // [0e]
484: NoKey, // [0f]
485:
486: X68kKey_ESC, // [10]
487: X68kKey_BS, // [11]
488: X68kKey_enter, // [12]
489: X68kKey_INS, // [13]
490: X68kKey_space, // [14]
491: X68kKey_DEL, // [15]
492: NoKey, // [16]
493: NoKey, // [17]
494: NoKey, // [18]
495: NoKey, // [19]
496: NoKey, // [1a]
497: NoKey, // [1b]
498: X68kKey_up, // [1c]
499: X68kKey_left, // [1d]
500: X68kKey_right, // [1e]
501: X68kKey_down, // [1f]
502:
503: X68kKey_ROLLUP, // [20]
504: X68kKey_ROLLDOWN, // [21]
505: X68kKey_1, // [22]
506: X68kKey_2, // [23]
507: X68kKey_3, // [24]
508: X68kKey_4, // [25]
509: X68kKey_5, // [26]
510: X68kKey_6, // [27]
511: X68kKey_7, // [28]
512: X68kKey_8, // [29]
513: X68kKey_9, // [2a]
514: X68kKey_0, // [2b]
515: X68kKey_minus, // [2c]
516: X68kKey_circum, // [2d]
517: X68kKey_backslash, // [2e]
1.1.1.9 root 518: NoKey, // [2f]
1.1 root 519:
520: X68kKey_OPT1, // [30]
521: X68kKey_OPT2, // [31]
522: X68kKey_Q, // [32]
523: X68kKey_W, // [33]
524: X68kKey_E, // [34]
525: X68kKey_R, // [35]
526: X68kKey_T, // [36]
527: X68kKey_Y, // [37]
528: X68kKey_U, // [38]
529: X68kKey_I, // [39]
530: X68kKey_O, // [3a]
531: X68kKey_P, // [3b]
532: X68kKey_at, // [3c]
533: X68kKey_bracketleft, // [3d]
534: X68kKey_hira, // [3e]
535: X68kKey_zenkaku, // [3f]
536:
1.1.1.9 root 537: X68kKey_HOME, // [40]
538: X68kKey_UNDO, // [41]
1.1 root 539: X68kKey_A, // [42]
540: X68kKey_S, // [43]
541: X68kKey_D, // [44]
542: X68kKey_F, // [45]
543: X68kKey_G, // [46]
544: X68kKey_H, // [47]
545: X68kKey_J, // [48]
546: X68kKey_K, // [49]
547: X68kKey_L, // [4a]
548: X68kKey_semicolon, // [4b]
549: X68kKey_colon, // [4c]
550: X68kKey_bracketright, // [4d]
551: NoKey, // [4e]
552: NoKey, // [4f]
553:
1.1.1.9 root 554: X68kKey_XF1, // [50]
555: X68kKey_XF2, // [51]
1.1 root 556: X68kKey_Z, // [52]
557: X68kKey_X, // [53]
558: X68kKey_C, // [54]
559: X68kKey_V, // [55]
560: X68kKey_B, // [56]
1.1.1.5 root 561: X68kKey_N, // [57]
562: X68kKey_M, // [58]
1.1 root 563: X68kKey_comma, // [59]
564: X68kKey_period, // [5a]
565: X68kKey_slash, // [5b]
566: X68kKey_underscore, // [5c]
1.1.1.9 root 567: X68kKey_XF3, // [5d]
568: X68kKey_XF4, // [5e]
569: X68kKey_XF5, // [5f]
1.1 root 570:
571: NoKey, // [60]
572: X68kKey_PAD_plus, // [61]
573: X68kKey_PAD_minus, // [62]
574: X68kKey_PAD_7, // [63]
575: X68kKey_PAD_8, // [64]
576: X68kKey_PAD_9, // [65]
577: X68kKey_PAD_4, // [66]
578: X68kKey_PAD_5, // [67]
579: X68kKey_PAD_6, // [68]
580: X68kKey_PAD_1, // [69]
581: X68kKey_PAD_2, // [6a]
582: X68kKey_PAD_3, // [6b]
583: X68kKey_PAD_0, // [6c]
584: X68kKey_PAD_decimal, // [6d]
585: X68kKey_PAD_enter, // [6e]
586: X68kKey_PAD_CLR, // [6f]
587:
588: NoKey, // [70]
589: NoKey, // [71]
590: X68kKey_F1, // [72]
591: X68kKey_F2, // [73]
592: X68kKey_F3, // [74]
593: X68kKey_F4, // [75]
594: X68kKey_F5, // [76]
595: X68kKey_F6, // [77]
596: X68kKey_F7, // [78]
597: X68kKey_F8, // [79]
598: X68kKey_F9, // [7a]
599: X68kKey_F10, // [7b]
600: X68kKey_PAD_multiply, // [7c]
601: X68kKey_PAD_divide, // [7d]
602: X68kKey_PAD_equal, // [7e]
603: X68kKey_PAD_comma, // [7f]
604: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.