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