|
|
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:
7: #include "wxsoftkey.h"
1.1.1.4 root 8: #include "wxcolor.h"
1.1.1.6 root 9: #include "wxmainview.h"
1.1 root 10: #include "wxtextscreen.h"
1.1.1.8 ! root 11: #include "wxuimessage.h"
1.1.1.4 root 12: #include "sram.h"
1.1 root 13:
14: //
1.1.1.4 root 15: // ソフトウェアキーボード (パネル) 共通部分
1.1 root 16: //
17:
1.1.1.4 root 18: // エンター記号。
19: // 描画の際にキー刻印文字列の半角文字数から描画幅を決定しており、
20: // エンター記号は半角2文字幅で描いているので実際の文字列も2文字にしておく。
21: // そうすると "\\n" が意味的にもちょうどいい。
22: // これは幅を算出するのに使うだけで表示はされない。
23: #define EnterMark "\\n"
24:
1.1 root 25: // イベントテーブル
1.1.1.4 root 26: wxBEGIN_EVENT_TABLE(WXSoftKeyPanel, inherited)
27: EVT_LEFT_DOWN(WXSoftKeyPanel::OnLeftDown)
28: EVT_LEFT_UP(WXSoftKeyPanel::OnLeftUp)
29: EVT_LEFT_DCLICK(WXSoftKeyPanel::OnLeftDClick)
30: EVT_RIGHT_DOWN(WXSoftKeyPanel::OnRightDown)
31: EVT_PAINT(WXSoftKeyPanel::OnPaint)
1.1 root 32: wxEND_EVENT_TABLE()
33:
34: // コンストラクタ
1.1.1.4 root 35: WXSoftKeyPanel::WXSoftKeyPanel(wxWindow *parent,
1.1.1.6 root 36: const std::vector<keydata_t>& keydata_, int u_width_, int u_height_)
1.1 root 37: : inherited(parent)
1.1.1.6 root 38: , keydata(keydata_)
1.1 root 39: {
1.1.1.4 root 40: u_width = u_width_;
41: u_height = u_height_;
1.1.1.6 root 42:
43: // 比較用のバッファ (初回更新させるため true で埋めておく)
44: const std::vector<bool>& pressed = gKeyboard->GetPressed();
45: last_pressed.resize(pressed.size());
46: std::fill(last_pressed.begin(), last_pressed.end(), true);
47: last_modifier = (Modifier)-1;
48:
1.1.1.7 root 49: DoSize();
50:
1.1.1.6 root 51: // このパネルへのキー入力はメインビューへのキー入力と同じ。
52: Connect(wxEVT_KEY_UP, wxKeyEventHandler(WXMainView::OnKeyUp), NULL,
53: gMainView);
54: Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(WXMainView::OnKeyDown), NULL,
55: gMainView);
56:
1.1.1.8 ! root 57: // VM からの通知を受け取る
! 58: WXUIMessage::Connect(UIMessage::KEYBOARD, this,
! 59: wxCommandEventHandler(WXSoftKeyPanel::OnKeyChanged));
1.1 root 60: }
61:
62: // デストラクタ
1.1.1.4 root 63: WXSoftKeyPanel::~WXSoftKeyPanel()
1.1 root 64: {
1.1.1.8 ! root 65: WXUIMessage::Disconnect(UIMessage::KEYBOARD,
! 66: wxCommandEventHandler(WXSoftKeyPanel::OnKeyChanged));
1.1 root 67: }
68:
69: // フォントサイズ変更 (外部インタフェース)
70: void
1.1.1.5 root 71: WXSoftKeyPanel::SetFontSize(FontId new_fontid)
1.1 root 72: {
73: // 同じなら何もしない
1.1.1.5 root 74: if (fontid == new_fontid) {
1.1 root 75: return;
76: }
77:
78: // フォントを更新
1.1.1.5 root 79: UpdateFont(new_fontid);
1.1 root 80:
81: // サイズ変更処理
82: DoSize();
83: }
84:
85: // サイズ変更処理
86: // サイズを変更したい時に呼ぶ (サイズが変更されたらではない)。
87: // ここではサイズは fontsize にのみ依存しているので、フォントサイズが
88: // 変化/確定した時に呼び出すこと。
89: void
1.1.1.4 root 90: WXSoftKeyPanel::DoSize()
1.1 root 91: {
1.1.1.5 root 92: assert(fontid != FontId::None);
1.1 root 93:
94: // このパネル内の描画の基本単位
95: unit = font_height / 4;
96:
97: // エンターキーだけ矩形でないのでここでリージョンを計算。
98: // unit が確定したところで一回行う。
1.1.1.6 root 99: // ただし SHIFT_R のキーコードはちょっと使いづらいので、ここでは SHIFT_R
100: // を使わず [_] キーで代用する。
101: //
102: // | ^ | \ | BS |
103: // | | | |
104: // --+---+---+--(A)--+------(B)
105: // | | |
106: // | [ | |
107: // | | Enter |
108: // --+---+---+--(F)-(E) |
109: // | | | |
110: // | : | ] | |
111: // | | | |
112: // --+---+---+------(D)-----(C)
113: // | |
114: // _ | SHIFT |
1.1 root 115: //
116: const keydata_t& keybs = FindKeydata(KC_BS);
117: const keydata_t& keyleft = FindKeydata(KC_bracketleft);
118: const keydata_t& keyright = FindKeydata(KC_bracketright);
1.1.1.6 root 119: const keydata_t& keyscore = FindKeydata(KC_underscore);
1.1 root 120: // 各点のピクセル座標
121: enter_points = {
122: { keyleft.right() * unit, keyleft.y * unit }, // A
123: { keybs.right() * unit, keyleft.y * unit }, // B
1.1.1.6 root 124: { keybs.right() * unit, keyscore.y * unit }, // C
125: { keyright.right() * unit, keyscore.y * unit }, // D
1.1 root 126: { keyright.right() * unit, keyright.y * unit }, // E
127: { keyleft.right() * unit, keyright.y * unit }, // F
128: };
129: // 当たり判定用のリージョン
130: enter_region = wxRegion(enter_points.size(), enter_points.data());
131:
132: // コントロールの大きさを変更
1.1.1.4 root 133: wxSize size(u_width * unit, u_height * unit);
1.1 root 134: SetClientSize(size);
1.1.1.6 root 135: SetMinClientSize(size);
1.1 root 136:
137: // ビットマップ作成
1.1.1.6 root 138: bitmap.Create(size.x, size.y);
1.1 root 139:
140: // 再描画を指示
141: Refresh();
142: }
143:
1.1.1.8 ! root 144: // キー状態変更イベント (UIMessage)
1.1.1.6 root 145: void
1.1.1.8 ! root 146: WXSoftKeyPanel::OnKeyChanged(wxCommandEvent& event)
1.1.1.6 root 147: {
148: // 更新があれば再描画を指示
149: const std::vector<bool>& pressed = gKeyboard->GetPressed();
150: UpdateModifier();
151: if (pressed != last_pressed || modifier != last_modifier) {
152: Refresh();
153: }
154: }
155:
1.1 root 156: // 描画イベント (UI スレッドから呼ばれる)
157: void
1.1.1.4 root 158: WXSoftKeyPanel::OnPaint(wxPaintEvent& event)
1.1 root 159: {
160: // メモリ DC に描画
161: wxMemoryDC memDC;
1.1.1.6 root 162: memDC.SelectObject(bitmap);
1.1 root 163: Draw(memDC);
164:
165: // 実画面 DC にコピー
166: wxPaintDC dstDC(this);
1.1.1.6 root 167: wxSize size = bitmap.GetSize();
168: dstDC.Blit(0, 0, size.x, size.y, &memDC, 0, 0);
1.1 root 169: }
170:
171: // 描画本体
172: void
1.1.1.4 root 173: WXSoftKeyPanel::Draw(wxDC& dc)
1.1 root 174: {
1.1.1.4 root 175: dc.SetPen(wxPen(color.Background));
176: dc.SetBrush(wxBrush(color.Background));
1.1 root 177: dc.DrawRectangle(wxPoint(0, 0), GetSize());
178:
1.1.1.4 root 179: dc.SetPen(color.Text);
180: SetTextForeColor(color.Text);
1.1.1.6 root 181: for (const auto& key : keydata) {
182: bool is_pressed = gKeyboard->IsPressed(key.keycode);
183: if (is_pressed) {
1.1 root 184: // 押されている
1.1.1.4 root 185: SetTextBackColor(color.KeyPressed);
186: dc.SetBrush(color.KeyPressed);
1.1 root 187: } else {
188: // 押されていない
1.1.1.4 root 189: SetTextBackColor(color.Keytop[key.coltype]);
190: dc.SetBrush(wxBrush(color.Keytop[key.coltype]));
1.1 root 191: }
192:
193: // エンターキーだけ枠の描き方が違うので別処理
194: if (__predict_false(key.x < 0)) {
195: DrawEnterKey(dc);
196: } else {
197: DrawKey(dc, key);
198: }
1.1.1.6 root 199:
200: // 次回更新チェック用に現状を保存
201: last_pressed[key.keycode] = is_pressed;
1.1 root 202: }
203:
1.1.1.6 root 204: // 次回更新チェック用に現状を保存
205: last_modifier = modifier;
206:
1.1.1.4 root 207: #if 0
208: // X68k キーボードだとどこに表示するか
209: SetTextBackColor(color.Background);
1.1.1.2 root 210: wxString utfstr(wxT("右クリックで長押し"));
1.1 root 211: const char *sjis = (const char *)utfstr.mb_str(conv);
212: DrawStringSJIS(dc, 190 * unit, 2 * unit, sjis, TA::Disable);
1.1.1.4 root 213: #endif
1.1 root 214: }
215:
216: // 指定のキーを一つ (枠から刻印まで) 描画する。
217: void
1.1.1.4 root 218: WXSoftKeyPanel::DrawKey(wxDC& dc, const keydata_t& key)
1.1 root 219: {
220: // 枠
221: wxPoint pt(key.x * unit, key.y * unit);
222: wxSize sz(key.w * unit + 1, key.h * unit + 1);
223: dc.DrawRectangle(pt, sz);
224:
225: // 刻印を選択
226: const char *disp = key.disp[modifier];
227: if (disp == NULL) {
228: disp = key.disp[0];
229: }
230:
231: // Shift_JIS に変換
232: wxString utfstr(disp, wxConvUTF8);
233: const char *sjis = (const char *)utfstr.mb_str(conv);
1.1.1.4 root 234: // 改行があれば2行に分割
235: char sjis1[8] {};
236: char sjis2[8] {};
237: int sjislen;
238: int row;
239: const char *lf = strchr(sjis, '\n');
240: if (lf == NULL) {
241: // 1行なら、Shift_JIS での文字数は半角換算の文字数と一致する。
242: sjislen = strlen(sjis);
243: row = 1;
244: } else {
245: // 2行に分割。センタリングは1行目の長さだけで調べる。
246: strncpy(sjis1, sjis, lf - sjis);
247: strcpy(sjis2, lf + 1);
248: sjislen = strlen(sjis1);
249: row = 2;
250: }
1.1 root 251:
252: // センタリング
253: int x = key.x + (key.w - sjislen * 2) / 2;
1.1.1.4 root 254: int y = key.y + (key.h - row * 4) / 2;
1.1 root 255:
1.1.1.4 root 256: // LED を描画 (機種によって色々違うので個別クラス側で処理)
257: if (key.led >= 0) {
1.1 root 258: const wxPen oldpen = dc.GetPen();
259: const wxBrush oldbrush = dc.GetBrush();
1.1.1.4 root 260:
261: y += DrawLED(dc, key);
262:
1.1 root 263: dc.SetPen(oldpen);
264: dc.SetBrush(oldbrush);
265: }
266:
267: // 文字を描画
268: pt = wxPoint(x * unit + 1, y * unit + 1);
1.1.1.4 root 269: if (strcmp(disp, EnterMark) == 0) {
1.1 root 270: DrawEnterMark(dc, pt);
271: } else {
1.1.1.4 root 272: if (lf == NULL) {
273: // 1行の場合
274: DrawStringSJIS(dc, pt.x, pt.y, sjis);
275: } else {
276: // 2行の場合
277: DrawStringSJIS(dc, pt.x, pt.y, sjis1);
278: pt.y += 4 * unit;
279: DrawStringSJIS(dc, pt.x, pt.y, sjis2);
280: }
1.1 root 281: }
282: }
283:
284: // エンターキー
285: void
1.1.1.4 root 286: WXSoftKeyPanel::DrawEnterKey(wxDC& dc)
1.1 root 287: {
288: // エンターキーを描画
289: dc.DrawPolygon(enter_points.size(), enter_points.data());
290:
291: // エンター記号を描画
292: DrawEnterMark(dc, wxPoint(
293: (enter_points[0].x + enter_points[1].x) / 2 - (4 / 2),
294: (enter_points[1].y + enter_points[2].y) / 2 - (4 / 2)));
295: }
296:
297: // 指定の位置にエンター記号を描画する (エンターキー全体の描画ではない)。
298: // メインキーとテンキーの両方で同じ図柄を使う。
299: // 大きさは (3unit, 4unit) なので実質全角1文字分くらい。
300: void
1.1.1.4 root 301: WXSoftKeyPanel::DrawEnterMark(wxDC& dc, const wxPoint& basep)
1.1 root 302: {
303: // エンター記号は幅 3 unit、高さ 4 unit。
304: // +0 +1 +2 +3
305: // +0 .. .. .. 1.
306: // .. .. .. 1.
307: // +1 .. .. .. 1.
308: // .. .. .. 1.
309: // +2 .. 1. .. 1.
310: // .1 .. .. 1.
311: // +3 11 11 11 1.
312: // .1 .. .. ..
313: // +4 .. 1. .. ..
314: // .. .. .. ..
315: static const std::vector<std::pair<int,int>> entermark {
316: { 3, 0 },
317: { 3, 3 }, // │
318: { 0, 3 }, // ─
319: { 1, 2 }, // /
320: { 0, 3 }, // (一筆書きなので戻る)
321: { 1, 4 }, // \
322: };
323: for (int i = 1; i < entermark.size(); i++) {
324: auto start = entermark[i - 1];
325: auto end = entermark[i];
326: wxPoint startp(start.first * unit, start.second * unit);
327: wxPoint endp(end.first * unit, end.second * unit);
328: dc.DrawLine(basep + startp, basep + endp);
329: }
330: }
331:
332: // keycode に対応する keydata を返す
333: const keydata_t&
1.1.1.4 root 334: WXSoftKeyPanel::FindKeydata(uint keycode) const
1.1 root 335: {
1.1.1.6 root 336: for (const auto& key : keydata) {
1.1 root 337: if (key.keycode == keycode) {
338: return key;
339: }
340: }
341: // 見付からないはずはない
1.1.1.3 root 342: assertmsg(0, "keycode %d not found", keycode);
1.1 root 343: }
344:
345: // マウス左クリック (Down) イベント
346: void
1.1.1.4 root 347: WXSoftKeyPanel::OnLeftDown(wxMouseEvent& event)
1.1 root 348: {
1.1.1.5 root 349: const wxPoint& pt = event.GetPosition();
1.1.1.4 root 350: const keydata_t *key = GetKeydataFromPoint(pt);
1.1 root 351:
1.1.1.4 root 352: DoLeftDown(key);
1.1 root 353: }
354:
355: // マウス左クリック (Down) 処理
356: void
1.1.1.4 root 357: WXSoftKeyPanel::DoLeftDown(const keydata_t *key)
1.1 root 358: {
1.1.1.4 root 359: if (key != NULL) {
1.1.1.6 root 360: // 押下
361: KeyDown(*key);
362: // LeftUp のために覚えておく
363: leftdown_key = key;
1.1 root 364: }
365: }
366:
367: // マウス左クリック (Up) イベント
368: void
1.1.1.4 root 369: WXSoftKeyPanel::OnLeftUp(wxMouseEvent& event)
1.1 root 370: {
371: // Up 時は、これが起きた地点のキーコードではなく
372: // 直近に LeftDown したキーコードをターゲットにする。
1.1.1.4 root 373: const keydata_t *key = leftdown_key;
1.1 root 374:
1.1.1.4 root 375: DoLeftUp(key);
1.1 root 376: }
377:
378: // マウス左クリック (Up) 処理
379: void
1.1.1.4 root 380: WXSoftKeyPanel::DoLeftUp(const keydata_t *key)
1.1 root 381: {
1.1.1.4 root 382: if (key != NULL) {
1.1.1.6 root 383: // 開放
384: KeyUp(*key);
1.1 root 385: }
1.1.1.4 root 386: leftdown_key = NULL;
1.1 root 387: }
388:
389: // マウス左ダブルクリックイベント
390: // ダブルクリックという操作に特別何かを割り当ててはいないが、
391: // キーを連打するとその間隔によってはダブルクリックと扱われるため、
392: // 受け取ってここで処理する。
393: //
394: // DClick イベントは LeftDown、LeftUp、LeftDClick、LeftUp の順で
395: // 飛んでくるので、ここでは2回目の押下だけ処理すればよい。というか
396: // 処理自体は LeftDown とまったく同じになるので、イベントテーブルで
397: // 直接 EVT_LEFT_DCLICK => OnLeftDown に割り付けることも出来そうだが
398: // デバッグが紛らわしくなりそうなので独立したイベントとしておく。
399: void
1.1.1.4 root 400: WXSoftKeyPanel::OnLeftDClick(wxMouseEvent& event)
1.1 root 401: {
1.1.1.5 root 402: const wxPoint& pt = event.GetPosition();
1.1.1.4 root 403: const keydata_t *key = GetKeydataFromPoint(pt);
1.1 root 404:
1.1.1.4 root 405: DoLeftDown(key);
1.1 root 406: }
407:
408: // マウス右クリック (Down) イベント
409: // 長押し開始/解除。
410: // 右クリックのほうは Down だけで Up は使わない。
411: void
1.1.1.4 root 412: WXSoftKeyPanel::OnRightDown(wxMouseEvent& event)
1.1 root 413: {
1.1.1.5 root 414: const wxPoint& pt = event.GetPosition();
1.1.1.4 root 415: const keydata_t *key = GetKeydataFromPoint(pt);
1.1 root 416:
1.1.1.4 root 417: if (key != NULL) {
418: uint code = key->keycode;
1.1.1.6 root 419: if (gKeyboard->IsPressed(code)) {
1.1 root 420: // 押されていたら開放
1.1.1.4 root 421: KeyUp(*key);
1.1 root 422: } else {
423: // 押されてなければ長押し開始
1.1.1.4 root 424: KeyDown(*key);
1.1 root 425: }
426: }
427: }
428:
1.1.1.4 root 429: // 座標からキーデータを返す。
430: // キーに当たっていなければ NULL を返す。
431: const keydata_t *
432: WXSoftKeyPanel::GetKeydataFromPoint(const wxPoint& pt) const
1.1 root 433: {
1.1.1.4 root 434: // エンターキーだけ先に別判定
435: if (enter_region.Contains(pt) == wxInRegion) {
436: return &FindKeydata(KC_enter);
437: }
1.1 root 438:
1.1.1.6 root 439: for (const auto& key : keydata) {
1.1.1.4 root 440: if (key.x < 0) {
441: continue;
1.1 root 442: }
1.1.1.4 root 443: // 始点と幅の +1/-1 は罫線の分
444: wxRect rect(
445: (key.x * unit) + 1,
446: (key.y * unit) + 1,
447: (key.w * unit) - 1,
448: (key.h * unit) - 1);
449: if (rect.Contains(pt)) {
450: return &key;
1.1 root 451: }
1.1.1.4 root 452: }
453: return NULL;
454: }
455:
1.1.1.6 root 456: // 修飾キーなら true を返す
457: // (今は SHIFT しかないから修飾キーならなのか SHIFT ならなのか曖昧)
458: bool
459: WXSoftKeyPanel::IsModifier(uint code) const
460: {
461: if (code == KC_SHIFT_L || code == KC_SHIFT_R || code == KC_SHIFT) {
462: return true;
463: } else {
464: return false;
465: }
466: }
467:
468: // 修飾キーの状態を更新。今は SHIFT かどうかしかない
469: void
470: WXSoftKeyPanel::UpdateModifier()
471: {
472: if (gKeyboard->IsShift()) {
473: modifier = ModShift;
474: } else {
475: modifier = ModNormal;
476: }
477: }
478:
479: // このキーが押された処理
480: void
481: WXSoftKeyPanel::KeyDown(const keydata_t& key)
482: {
483: uint code = key.keycode;
484:
485: // VM に通知 (Keyboard がそれをホストに通知するかはまた別)
486: gKeyboard->MakeKey(code);
487:
488: // 修飾キー
489: if (IsModifier(code)) {
490: UpdateModifier();
491: }
492:
493: // キー状態が変わった(かも知れない)ので再描画
494: // 押した時にはタイマーを待たずに再描画したほうがよかろう
495: Refresh();
496: }
497:
498: // このキーが放された処理
499: void
500: WXSoftKeyPanel::KeyUp(const keydata_t& key)
501: {
502: uint code = key.keycode;
503:
504: // VM に通知 (Keyboard がそれをホストに通知するかはまた別)
505: gKeyboard->BreakKey(code);
506:
507: // 修飾キー
508: if (IsModifier(code)) {
509: UpdateModifier();
510: }
511:
512: // キー状態が変わった(かも知れない)が、
513: // 解放時はタイマーに任せた再描画でよかろう
514: //Refresh();
515: }
516:
517:
1.1.1.4 root 518: //
519: // LUNA ソフトウェアキーボード (パネル)
520: //
521:
522: // コンストラクタ
523: WXLunaSoftKeyPanel::WXLunaSoftKeyPanel(wxWindow *parent)
1.1.1.6 root 524: : inherited(parent, keydata, 226, 54)
1.1.1.4 root 525: {
526: // LUNA では
527: // BS キーの左隣 (0x5c) は円記号ではなくバックスラッシュ。
528: // それを SHIFT したやつ(0x7c) は破線でないパイプ。
529: // そのもう一つ左隣 (0x7e) はオーバーラインではなくチルダ。
530: SetGlyph5C(true);
531: SetGlyph7E(true);
532:
533: // キートップの濃淡はユニバーサルデザインの推奨色ではないけど
534: // ここは見分けを付けるためではなくただのデザインなので。
535: if (1) {
536: // 白モデル
537: color = {
538: .Background = UD_LIGHT_GREY, // 現物新品は何色だったんだろう
539: .Text = *wxBLACK,
540: .Keytop = { *wxWHITE, wxColour(200, 200, 203) },
541: // 白黒共通
542: .KeyPressed = UD_BLUE,
543: .Border = *wxBLACK,
544: .LED = { UD_RED },
545: };
546: } else {
547: // 黒モデル
548: color = {
549: .Background = *wxBLACK,
550: .Text = *wxWHITE,
551: .Keytop = { wxColour(50, 50, 53), *wxBLACK },
552: // 白黒共通
553: .KeyPressed = UD_BLUE,
554: .Border = *wxBLACK,
555: .LED = { UD_RED },
556: };
557: }
558: }
559:
560: // デストラクタ
561: WXLunaSoftKeyPanel::~WXLunaSoftKeyPanel()
562: {
563: }
564:
565: // LED を描画して刻印描画のための y offset を返す。
566: int
567: WXLunaSoftKeyPanel::DrawLED(wxDC& dc, const keydata_t& key)
568: {
569: const std::vector<bool>& led = gKeyboard->GetLED();
570:
571: if (led[key.led]) {
572: // 点灯時は赤、枠は黒
573: dc.SetPen(color.Border);
574: dc.SetBrush(color.LED[0]);
1.1 root 575: } else {
1.1.1.4 root 576: // 消灯時は元のキートップの色で、枠は薄めにしたい
1.1.1.6 root 577: // (枠の色は今の所全モデル共通なので ColorPalette に含めていない)
578: dc.SetPen(UD_GREY);
1.1.1.4 root 579: dc.SetBrush(color.Keytop[key.coltype]);
1.1 root 580: }
581:
1.1.1.4 root 582: // LED を左肩に描く
583: wxPoint pt = wxPoint(key.x * unit + 2, key.y * unit + 2);
584: wxSize sz = wxSize(4 * unit - 2, 3 * unit - 2);
585: dc.DrawRectangle(pt, sz);
586:
587: // そのため文字は少し下げる
588: return +1;
589: }
590:
1.1 root 591: // キーデータ
592: #define H (8) // キーの高さ
593: #define L0 (2) // ファンクションキーの行
594: #define L1 (12) // ESC の行
595: #define L2 (20) // TAB の行
596: #define L3 (28) // CTRL の行
597: #define L4 (36) // SHIFT の行
598: #define L5 (44) // space の行
599: /*static*/ std::vector<keydata_t>
600: WXLunaSoftKeyPanel::keydata {
1.1.1.4 root 601: // +---- キートップの色(1:濃)
602: // | +- 0 以上なら LED 番号
603: // X Y W H C L KeyCode 通常 SHIFT
604: { 2, L0, 15, H, 1,-1, KC_F1, { "PF1" } },
605: { 17, L0, 15, H, 1,-1, KC_F2, { "PF2" } },
606: { 32, L0, 15, H, 1,-1, KC_F3, { "PF3" } },
607: { 47, L0, 15, H, 1,-1, KC_F4, { "PF4" } },
608: { 62, L0, 15, H, 1,-1, KC_F5, { "PF5" } },
609: { 81, L0, 15, H, 1,-1, KC_F6, { "PF6" } },
610: { 96, L0, 15, H, 1,-1, KC_F7, { "PF7" } },
611: { 111, L0, 15, H, 1,-1, KC_F8, { "PF8" } },
612: { 126, L0, 15, H, 1,-1, KC_F9, { "PF9" } },
613: { 141, L0, 15, H, 1,-1, KC_F10, { "PF10" } },
614:
615: { 2, L1, 12, H, 1,-1, KC_ESC, { "ESC" } },
616: { 14, L1, 10, H, 0,-1, KC_1, { "1", "!" } },
617: { 24, L1, 10, H, 0,-1, KC_2, { "2", "\"" } },
618: { 34, L1, 10, H, 0,-1, KC_3, { "3", "#" } },
619: { 44, L1, 10, H, 0,-1, KC_4, { "4", "$" } },
620: { 54, L1, 10, H, 0,-1, KC_5, { "5", "%" } },
621: { 64, L1, 10, H, 0,-1, KC_6, { "6", "&" } },
622: { 74, L1, 10, H, 0,-1, KC_7, { "7", "'" } },
623: { 84, L1, 10, H, 0,-1, KC_8, { "8", "(" } },
624: { 94, L1, 10, H, 0,-1, KC_9, { "9", ")" } },
625: { 104, L1, 10, H, 0,-1, KC_0, { "0", " " } },
626: { 114, L1, 10, H, 0,-1, KC_minus, { "-", "=" } },
627: { 124, L1, 10, H, 0,-1, KC_circum, { "^", "~" } },
628: { 134, L1, 10, H, 0,-1, KC_backslash, { "\\", "|" } },
629: { 144, L1, 12, H, 1,-1, KC_BS, { "BS" } },
630:
631: { 2, L2, 17, H, 1,-1, KC_TAB, { "TAB" } },
632: { 19, L2, 10, H, 0,-1, KC_Q, { "q", "Q" } },
633: { 29, L2, 10, H, 0,-1, KC_W, { "w", "W" } },
634: { 39, L2, 10, H, 0,-1, KC_E, { "e", "E" } },
635: { 49, L2, 10, H, 0,-1, KC_R, { "r", "R" } },
636: { 59, L2, 10, H, 0,-1, KC_T, { "t", "T" } },
637: { 69, L2, 10, H, 0,-1, KC_Y, { "y", "Y" } },
638: { 79, L2, 10, H, 0,-1, KC_U, { "u", "U" } },
639: { 89, L2, 10, H, 0,-1, KC_I, { "i", "I" } },
640: { 99, L2, 10, H, 0,-1, KC_O, { "o", "O" } },
641: { 109, L2, 10, H, 0,-1, KC_P, { "p", "P" } },
642: { 119, L2, 10, H, 0,-1, KC_at, { "@", "`" } },
643: { 129, L2, 10, H, 0,-1, KC_bracketleft, { "[", "{" } },
644:
645: { 2, L3, 20, H, 1,-1, KC_CTRL, { "CTRL" } },
646: { 22, L3, 10, H, 0,-1, KC_A, { "a", "A" } },
647: { 32, L3, 10, H, 0,-1, KC_S, { "s", "S" } },
648: { 42, L3, 10, H, 0,-1, KC_D, { "d", "D" } },
649: { 52, L3, 10, H, 0,-1, KC_F, { "f", "F" } },
650: { 62, L3, 10, H, 0,-1, KC_G, { "g", "G" } },
651: { 72, L3, 10, H, 0,-1, KC_H, { "h", "H" } },
652: { 82, L3, 10, H, 0,-1, KC_J, { "j", "J" } },
653: { 92, L3, 10, H, 0,-1, KC_K, { "k", "K" } },
654: { 102, L3, 10, H, 0,-1, KC_L, { "l", "L" } },
655: { 112, L3, 10, H, 0,-1, KC_semicolon, { ";", "+" } },
656: { 122, L3, 10, H, 0,-1, KC_colon, { ":", "*" } },
657: { 132, L3, 10, H, 0,-1, KC_bracketright, { "]", "}" } },
658:
659: { 2, L4, 25, H, 1,-1, KC_SHIFT_L, { "SHIFT" } },
660: { 27, L4, 10, H, 0,-1, KC_Z, { "z", "Z" } },
661: { 37, L4, 10, H, 0,-1, KC_X, { "x", "X" } },
662: { 47, L4, 10, H, 0,-1, KC_C, { "c", "C" } },
663: { 57, L4, 10, H, 0,-1, KC_V, { "v", "V" } },
664: { 67, L4, 10, H, 0,-1, KC_B, { "b", "B" } },
665: { 77, L4, 10, H, 0,-1, KC_N, { "n", "N" } },
666: { 87, L4, 10, H, 0,-1, KC_M, { "m", "M" } },
667: { 97, L4, 10, H, 0,-1, KC_comma, { ",", "<" } },
668: { 107, L4, 10, H, 0,-1, KC_period, { ".", ">" } },
669: { 117, L4, 10, H, 0,-1, KC_slash, { "/", "?" } },
670: { 127, L4, 10, H, 0,-1, KC_underscore, { " ", "_" } },
671: { 137, L4, 19, H, 1,-1, KC_SHIFT_R, { "SHIFT" } },
672:
673: { 2, L5, 20, H, 1,-1, KC_VALID, { "確定" } },
674: { 22, L5, 10, H, 1,-1, KC_SF, { "前面" } },
675: { 32, L5, 10, H, 1, 1, KC_CAPS, { "CAP" } },
676: { 42, L5, 80, H, 0,-1, KC_space, { " " } },
677: { 122, L5, 10, H, 1, 0, KC_kana, { "かな" } },
678: { 132, L5, 24, H, 1,-1, KC_XFER, { "変換" } },
1.1 root 679:
680: // カーソルキー島
1.1.1.4 root 681: { 160, L1, 10, H, 1,-1, KC_PF11, { "消去" } },
682: { 170, L1, 10, H, 1,-1, KC_PF12, { "呼出" } },
683: { 160, L2, 10, H, 1,-1, KC_PF13, { "文節\n←" } },
684: { 170, L2, 10, H, 1,-1, KC_PF14, { "文節\n→" } },
685: { 160, L3, 20, H, 1,-1, KC_up, { "↑" } },
686: { 160, L4, 10, H, 1,-1, KC_left, { "←" } },
687: { 170, L4, 10, H, 1,-1, KC_right, { "→" } },
688: { 160, L5, 20, H, 1,-1, KC_down, { "↓" } },
1.1 root 689:
690: // テンキー島
1.1.1.4 root 691: { 184, L1, 10, H, 1,-1, KC_DEL, { "DEL" } },
692: { 194, L1, 10, H, 1,-1, KC_PAD_plus, { "+" } },
693: { 204, L1, 10, H, 1,-1, KC_PAD_minus, { "-" } },
694: { 214, L1, 10, H, 1,-1, KC_PAD_multiply, { "*" } },
695:
696: { 184, L2, 10, H, 0,-1, KC_PAD_7, { "7" } },
697: { 194, L2, 10, H, 0,-1, KC_PAD_8, { "8" } },
698: { 204, L2, 10, H, 0,-1, KC_PAD_9, { "9" } },
699: { 214, L2, 10, H, 1,-1, KC_PAD_divide, { "/" } },
700:
701: { 184, L3, 10, H, 0,-1, KC_PAD_4, { "4" } },
702: { 194, L3, 10, H, 0,-1, KC_PAD_5, { "5" } },
703: { 204, L3, 10, H, 0,-1, KC_PAD_6, { "6" } },
704: { 214, L3, 10, H, 1,-1, KC_PAD_equal, { "=" } },
705:
706: { 184, L4, 10, H, 0,-1, KC_PAD_1, { "1" } },
707: { 194, L4, 10, H, 0,-1, KC_PAD_2, { "2" } },
708: { 204, L4, 10, H, 0,-1, KC_PAD_3, { "3" } },
709: { 214, L4, 10, H, 1,-1, KC_PAD_comma, { "," } },
710:
711: { 184, L5, 10, H, 0,-1, KC_PAD_0, { "0" } },
712: { 194, L5, 10, H, 0,-1, KC_PAD_decimal, { "." } },
713: { 204, L5, 20, H, 1,-1, KC_PAD_enter, { EnterMark } },
1.1 root 714:
715: // Enter だけ矩形でないので別処理するが
716: // この構造体には全部のキー情報が統一的に並んでいるほうがよかろう。
1.1.1.4 root 717: { -1, -1, -1, -1, 1,-1, KC_enter, { EnterMark } },
1.1 root 718: };
719:
720:
721: //
1.1.1.4 root 722: // X68k ソフトウェアキーボード (パネル)
723: //
724:
725: // コンストラクタ
726: WXX68kSoftKeyPanel::WXX68kSoftKeyPanel(wxWindow *parent)
1.1.1.6 root 727: : inherited(parent, keydata, 235, 54)
1.1.1.4 root 728: {
729: // X68k では SRAM 設定に同期させる。
730: uint8 sw = gSRAM->Peek8(0xed0059);
731: SetGlyph5C((sw & 0x01));
732: SetGlyph7E((sw & 0x02));
733: SetGlyph7C((sw & 0x04));
734:
735: // とりあえず黒のみ
736: color = {
737: .Background = wxColour(50, 50, 53),
738: .Text = *wxWHITE,
739: .Keytop = { *wxBLACK },
740: .KeyPressed = UD_BLUE,
741: .Border = *wxBLACK,
742: .LED = { UD_RED, UD_YELLOW_GREEN },
743: };
744: }
745:
746: // デストラクタ
747: WXX68kSoftKeyPanel::~WXX68kSoftKeyPanel()
748: {
749: }
750:
751: // LED を描画して刻印描画のための y offset を返す。
752: int
753: WXX68kSoftKeyPanel::DrawLED(wxDC& dc, const keydata_t& key)
754: {
755: const std::vector<bool>& led = gKeyboard->GetLED();
756:
757: // 色を選択
758: // idx 刻印 色
759: // ----------------
760: // 0 かな 赤
761: // 1 ローマ 赤
762: // 2 コード 赤
763: // 3 CAPS 赤
764: // 4 INS 赤
765: // 5 ひら 緑
766: // 6 全角 緑
767: if (led[key.led]) {
768: int n = (key.led < 5) ? 0 : 1;
769: dc.SetPen(color.LED[n]);
770: dc.SetBrush(color.LED[n]);
771: } else {
772: // 消灯時は元のキートップの色で、枠は薄めにしたい
1.1.1.6 root 773: // (枠の色は今の所全モデル共通なので ColorPalette に含めていない)
774: dc.SetPen(UD_GREY);
1.1.1.4 root 775: dc.SetBrush(color.Keytop[key.coltype]);
776: }
777:
778: // LED は中央前方(画面でいうと下)
779: wxPoint pt = wxPoint((key.x + 3) * unit, (key.y + key.h - 2) * unit);
780: wxSize sz = wxSize(4 * unit, 2 * unit);
781: dc.DrawRectangle(pt, sz);
782:
783: // そのため文字は少し上げる
784: return -1;
785: }
786:
787: #define LF (L0 + 2) // ファンクションキーは少し低い(横長い)
788: #define HT (H * 2) // 縦2倍角のキー
789: /*static*/ std::vector<keydata_t>
790: WXX68kSoftKeyPanel::keydata {
791: // +- 0以上なら LED 番号
792: // X Y W H C L KeyCode 通常 SHIFT
1.1.1.7 root 793: { 2, L0, 10, H, 0,-1, KC_BREAK, { "\x4\x5\x6\x7" } },
1.1.1.4 root 794: { 15, L0, 10, H, 0,-1, KC_COPY, { "COPY" } },
795: { 29, LF, 12, 6, 0,-1, KC_F1, { "F1" } },
796: { 41, LF, 12, 6, 0,-1, KC_F2, { "F2" } },
797: { 53, LF, 12, 6, 0,-1, KC_F3, { "F3" } },
798: { 65, LF, 12, 6, 0,-1, KC_F4, { "F4" } },
799: { 77, LF, 13, 6, 0,-1, KC_F5, { "F5" } },
800: { 94, LF, 13, 6, 0,-1, KC_F6, { "F6" } },
801: { 106, LF, 12, 6, 0,-1, KC_F7, { "F7" } },
802: { 118, LF, 12, 6, 0,-1, KC_F8, { "F8" } },
803: { 130, LF, 12, 6, 0,-1, KC_F9, { "F9" } },
804: { 142, LF, 13, 6, 0,-1, KC_F10, { "F10" } },
805:
806: { 2, L1, 10, H, 0,-1, KC_ESC, { "ESC" } },
807: { 12, L1, 10, H, 0,-1, KC_1, { "1", "!" } },
808: { 22, L1, 10, H, 0,-1, KC_2, { "2", "\"" } },
809: { 32, L1, 10, H, 0,-1, KC_3, { "3", "#" } },
810: { 42, L1, 10, H, 0,-1, KC_4, { "4", "$" } },
811: { 52, L1, 10, H, 0,-1, KC_5, { "5", "%" } },
812: { 62, L1, 10, H, 0,-1, KC_6, { "6", "&" } },
813: { 72, L1, 10, H, 0,-1, KC_7, { "7", "'" } },
814: { 82, L1, 10, H, 0,-1, KC_8, { "8", "(" } },
815: { 92, L1, 10, H, 0,-1, KC_9, { "9", ")" } },
816: { 102, L1, 10, H, 0,-1, KC_0, { "0", " " } },
817: { 112, L1, 10, H, 0,-1, KC_minus, { "-", "=" } },
818: { 122, L1, 10, H, 0,-1, KC_circum, { "^", "~" } },
819: { 132, L1, 10, H, 0,-1, KC_backslash, { "\\", "|" } },
820: { 142, L1, 13, H, 0,-1, KC_BS, { "BS" } },
821:
822: { 2, L2, 16, H, 0,-1, KC_TAB, { "TAB" } },
823: { 18, L2, 10, H, 0,-1, KC_Q, { "q", "Q" } },
824: { 28, L2, 10, H, 0,-1, KC_W, { "w", "W" } },
825: { 38, L2, 10, H, 0,-1, KC_E, { "e", "E" } },
826: { 48, L2, 10, H, 0,-1, KC_R, { "r", "R" } },
827: { 58, L2, 10, H, 0,-1, KC_T, { "t", "T" } },
828: { 68, L2, 10, H, 0,-1, KC_Y, { "y", "Y" } },
829: { 78, L2, 10, H, 0,-1, KC_U, { "u", "U" } },
830: { 88, L2, 10, H, 0,-1, KC_I, { "i", "I" } },
831: { 98, L2, 10, H, 0,-1, KC_O, { "o", "O" } },
832: { 108, L2, 10, H, 0,-1, KC_P, { "p", "P" } },
833: { 118, L2, 10, H, 0,-1, KC_at, { "@", "`" } },
834: { 128, L2, 10, H, 0,-1, KC_bracketleft, { "[", "{" } },
835:
836: { 2, L3, 19, H, 0,-1, KC_CTRL, { "CTRL" } },
837: { 21, L3, 10, H, 0,-1, KC_A, { "a", "A" } },
838: { 31, L3, 10, H, 0,-1, KC_S, { "s", "S" } },
839: { 41, L3, 10, H, 0,-1, KC_D, { "d", "D" } },
840: { 51, L3, 10, H, 0,-1, KC_F, { "f", "F" } },
841: { 61, L3, 10, H, 0,-1, KC_G, { "g", "G" } },
842: { 71, L3, 10, H, 0,-1, KC_H, { "h", "H" } },
843: { 81, L3, 10, H, 0,-1, KC_J, { "j", "J" } },
844: { 91, L3, 10, H, 0,-1, KC_K, { "k", "K" } },
845: { 101, L3, 10, H, 0,-1, KC_L, { "l", "L" } },
846: { 111, L3, 10, H, 0,-1, KC_semicolon, { ";", "+" } },
847: { 121, L3, 10, H, 0,-1, KC_colon, { ":", "*" } },
848: { 131, L3, 10, H, 0,-1, KC_bracketright, { "]", "}" } },
849:
1.1.1.6 root 850: { 2, L4, 24, H, 0,-1, KC_SHIFT, { "SHIFT" } },
1.1.1.4 root 851: { 26, L4, 10, H, 0,-1, KC_Z, { "z", "Z" } },
852: { 36, L4, 10, H, 0,-1, KC_X, { "x", "X" } },
853: { 46, L4, 10, H, 0,-1, KC_C, { "c", "C" } },
854: { 56, L4, 10, H, 0,-1, KC_V, { "v", "V" } },
855: { 66, L4, 10, H, 0,-1, KC_B, { "b", "B" } },
856: { 76, L4, 10, H, 0,-1, KC_N, { "n", "N" } },
857: { 86, L4, 10, H, 0,-1, KC_M, { "m", "M" } },
858: { 96, L4, 10, H, 0,-1, KC_comma, { ",", "<" } },
859: { 106, L4, 10, H, 0,-1, KC_period, { ".", ">" } },
860: { 116, L4, 10, H, 0,-1, KC_slash, { "/", "?" } },
861: { 126, L4, 10, H, 0,-1, KC_underscore, { " ", "_" } },
1.1.1.6 root 862: { 136, L4, 19, H, 0,-1, KC_SHIFT, { "SHIFT" } },
1.1.1.4 root 863:
864: { 21, L5, 10, H, 0, 5, KC_hira, { "ひら" } },
865: { 31, L5, 12, H, 0,-1, KC_XF1, { "XF1" } },
866: { 43, L5, 13, H, 0,-1, KC_XF2, { "XF2" } },
867: { 56, L5, 36, H, 0,-1, KC_space, { " " } },
868: { 92, L5, 12, H, 0,-1, KC_XF3, { "XF3" } },
869: { 104, L5, 12, H, 0,-1, KC_XF4, { "XF4" } },
870: { 116, L5, 12, H, 0,-1, KC_XF5, { "XF5" } },
871: { 128, L5, 10, H, 0, 6, KC_zenkaku, { "全角" } },
872:
873: // カーソルキー島
874: { 159, L0, 10, H, 0, 0, KC_kana, { "かな" } },
875: { 169, L0, 10, H, 0, 1, KC_romaji, { "ローマ" } },
876: { 179, L0, 10, H, 0, 2, KC_code, { "コード" } },
877: { 159, L1, 10, H, 0,-1, KC_HOME, { "HOME" } },
878: { 169, L1, 10, H, 0, 4, KC_INS, { "INS" } },
879: { 179, L1, 10, H, 0,-1, KC_DEL, { "DEL" } },
880: { 159, L2, 10, H, 0,-1, KC_ROLLUP, { "ROLL\n UP" } },
881: { 169, L2, 10, H, 0,-1, KC_ROLLDOWN, { "ROLL\nDOWN" } },
882: { 179, L2, 10, H, 0,-1, KC_UNDO, { "UNDO" } },
883: { 169, L3, 10, H, 0,-1, KC_up, { "↑" } },
884: { 159, L3, 10, HT,0,-1, KC_left, { "←" } },
885: { 179, L3, 10, HT,0,-1, KC_right, { "→" } },
886: { 169, L4, 10, H, 0,-1, KC_down, { "↓" } },
887: { 159, L5, 15, H, 0,-1, KC_OPT1, { "OPT.1" } },
888: { 174, L5, 15, H, 0,-1, KC_OPT2, { "OPT.2" } },
889:
890: // テンキー島
891: { 193, L0, 10, H, 0, 3, KC_CAPS, { "CAPS" } },
892: { 203, L0, 10, H, 0,-1, KC_kigou, { "記号" } },
893: { 213, L0, 10, H, 0,-1, KC_touroku, { "登録" } },
894: { 223, L0, 10, H, 0,-1, KC_HELP, { "HELP" } },
895: { 193, L1, 10, H, 0,-1, KC_PAD_CLR, { "CLR" } },
896: { 203, L1, 10, H, 0,-1, KC_PAD_divide, { "/" } },
897: { 213, L1, 10, H, 0,-1, KC_PAD_multiply, { "*" } },
898: { 223, L1, 10, H, 0,-1, KC_PAD_minus, { "-" } },
899: { 193, L2, 10, H, 0,-1, KC_PAD_7, { "7" } },
900: { 203, L2, 10, H, 0,-1, KC_PAD_8, { "8" } },
901: { 213, L2, 10, H, 0,-1, KC_PAD_9, { "9" } },
902: { 223, L2, 10, H, 0,-1, KC_PAD_plus, { "+" } },
903: { 193, L3, 10, H, 0,-1, KC_PAD_4, { "4" } },
904: { 203, L3, 10, H, 0,-1, KC_PAD_5, { "5" } },
905: { 213, L3, 10, H, 0,-1, KC_PAD_6, { "6" } },
906: { 223, L3, 10, H, 0,-1, KC_PAD_equal, { "=" } },
907: { 193, L4, 10, H, 0,-1, KC_PAD_1, { "1" } },
908: { 203, L4, 10, H, 0,-1, KC_PAD_2, { "2" } },
909: { 213, L4, 10, H, 0,-1, KC_PAD_3, { "3" } },
1.1.1.7 root 910: { 223, L4, 10, HT,0,-1, KC_PAD_enter, { "\xb\xc\xd\xe" } },
1.1.1.4 root 911: { 193, L5, 10, H, 0,-1, KC_PAD_0, { "0" } },
912: { 203, L5, 10, H, 0,-1, KC_PAD_comma, { "," } },
913: { 213, L5, 10, H, 0,-1, KC_PAD_decimal, { "." } },
914:
915: // Enter だけ矩形でないので別処理するが
916: // この構造体には全部のキー情報が統一的に並んでいるほうがよかろう。
917: { -1, -1, -1, -1, 0,-1, KC_enter, { EnterMark } },
918: };
919:
920: //
1.1.1.6 root 921: // ソフトウェアキーボード (ウィンドウ)
1.1.1.4 root 922: //
923:
924: // コンストラクタ
1.1.1.7 root 925: WXSoftKeyWindow::WXSoftKeyWindow(wxWindow *parent, vmtype_t vmtype)
926: : inherited(parent, wxID_ANY, _("Software Keyboard"))
1.1.1.4 root 927: {
1.1.1.7 root 928: wxBoxSizer *topsizer = new wxBoxSizer(wxVERTICAL);
929:
1.1.1.6 root 930: if (vmtype == VMTYPE_X68030) {
931: panel = new WXX68kSoftKeyPanel(this);
932: } else {
933: panel = new WXLunaSoftKeyPanel(this);
934: }
1.1.1.4 root 935:
1.1.1.7 root 936: topsizer->Add(panel, 0, wxEXPAND);
937:
938: SetSizer(topsizer);
1.1.1.4 root 939: // 大きさをそれに固定
940: Fit();
941: }
942:
943: // デストラクタ
1.1.1.6 root 944: WXSoftKeyWindow::~WXSoftKeyWindow()
1.1.1.4 root 945: {
946: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.