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