--- nono/wx/wxsoftkey.cpp 2026/04/29 17:04:59 1.1.1.8 +++ nono/wx/wxsoftkey.cpp 2026/04/29 17:05:57 1.1.1.17 @@ -4,10 +4,14 @@ // Licensed under nono-license.txt // +// +// ソフトウェアキーボード +// + #include "wxsoftkey.h" -#include "wxcolor.h" +#include "fontmanager.h" +#include "wxmainframe.h" #include "wxmainview.h" -#include "wxtextscreen.h" #include "wxuimessage.h" #include "sram.h" @@ -28,7 +32,7 @@ wxBEGIN_EVENT_TABLE(WXSoftKeyPanel, inhe EVT_LEFT_UP(WXSoftKeyPanel::OnLeftUp) EVT_LEFT_DCLICK(WXSoftKeyPanel::OnLeftDClick) EVT_RIGHT_DOWN(WXSoftKeyPanel::OnRightDown) - EVT_PAINT(WXSoftKeyPanel::OnPaint) + EVT_TIMER(wxID_ANY, WXSoftKeyPanel::OnTimer) wxEND_EVENT_TABLE() // コンストラクタ @@ -37,59 +41,109 @@ WXSoftKeyPanel::WXSoftKeyPanel(wxWindow : inherited(parent) , keydata(keydata_) { + // デバイスを取得 + keyboard = GetKeyboard(); + + timer.SetOwner(this); + u_width = u_width_; u_height = u_height_; - // 比較用のバッファ (初回更新させるため true で埋めておく) - const std::vector& pressed = gKeyboard->GetPressed(); - last_pressed.resize(pressed.size()); - std::fill(last_pressed.begin(), last_pressed.end(), true); - last_modifier = (Modifier)-1; + FontChanged(); - DoSize(); + // トグル動作にするキー + toggle.emplace(KC_SHIFT, 0); + toggle.emplace(KC_SHIFT_L, 0); + toggle.emplace(KC_SHIFT_R, 0); + toggle.emplace(KC_CTRL, 0); + + // 残光の初期化。 + // persistence は keydata 分の配列ではなく共通キーコード分の配列。 + persistence.resize(KC_max); + std::fill(persistence.begin(), persistence.end(), 0); // このパネルへのキー入力はメインビューへのキー入力と同じ。 - Connect(wxEVT_KEY_UP, wxKeyEventHandler(WXMainView::OnKeyUp), NULL, - gMainView); - Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(WXMainView::OnKeyDown), NULL, - gMainView); + auto mainframe = dynamic_cast(GetParent()->GetParent()); + auto mainview = mainframe->GetMainView(); + Bind(wxEVT_CHAR, &WXMainView::OnChar, mainview); + Bind(wxEVT_KEY_UP, &WXMainView::OnKeyUp, mainview); + Bind(wxEVT_KEY_DOWN, &WXMainView::OnKeyDown, mainview); // VM からの通知を受け取る WXUIMessage::Connect(UIMessage::KEYBOARD, this, wxCommandEventHandler(WXSoftKeyPanel::OnKeyChanged)); + + // 初期タイトルを保存しといて.. + title = dynamic_cast(parent)->GetTitle(); + // キーボードの接続状況でタイトルを更新する + UpdateTitle(); } // デストラクタ WXSoftKeyPanel::~WXSoftKeyPanel() { - WXUIMessage::Disconnect(UIMessage::KEYBOARD, + // ウィンドウクローズでトグルキーのワンショットは開放する + // (長押しは開放しない) + for (const auto& k : toggle) { + auto code = k.second; + if (code) { + KeyUp(code); + } + } + + timer.Stop(); + + WXUIMessage::Disconnect(UIMessage::KEYBOARD, this, wxCommandEventHandler(WXSoftKeyPanel::OnKeyChanged)); } -// フォントサイズ変更 (外部インタフェース) +// キーボードの接続状況によって親フレームのタイトルを更新する。 +// ついでにメンバ変数を更新する。 void -WXSoftKeyPanel::SetFontSize(FontId new_fontid) +WXSoftKeyPanel::UpdateTitle() { - // 同じなら何もしない - if (fontid == new_fontid) { - return; + auto parent = dynamic_cast(GetParent()); + assert(parent); + + // 次回比較用にメンバ変数に覚えておく + connected = keyboard->IsConnected(); + + if (connected) { + parent->SetTitle(title); + } else { + parent->SetTitle(title + _(" (disconnected)")); } +} + +// color.Keytop の初期化(補間)。 +// num はキートップの種類の数。1 か 2 +void +WXSoftKeyPanel::InitColorKeytop(int num) +{ + Color pressed = UD_BLUE; - // フォントを更新 - UpdateFont(new_fontid); + auto f = [](int a, int b, int x) { + return a * x / 100 + b * (100 - x) / 100; + }; - // サイズ変更処理 - DoSize(); + // Keytop[i][9] は押されたときの色 + // Keytop[i][0] は押されていないときの色 + for (int i = 0; i < num; i++) { + for (int j = 1; j < 10; j++) { + int n = j * 100 / 9; + color.Keytop[i][j] = Color( + f(pressed.r, color.Keytop[i][0].r, n), + f(pressed.g, color.Keytop[i][0].g, n), + f(pressed.b, color.Keytop[i][0].b, n)); + } + } } -// サイズ変更処理 -// サイズを変更したい時に呼ぶ (サイズが変更されたらではない)。 -// ここではサイズは fontsize にのみ依存しているので、フォントサイズが -// 変化/確定した時に呼び出すこと。 +// フォントサイズ変更 void -WXSoftKeyPanel::DoSize() +WXSoftKeyPanel::FontChanged() { - assert(fontid != FontId::None); + inherited::FontChanged(); // このパネル内の描画の基本単位 unit = font_height / 4; @@ -103,9 +157,9 @@ WXSoftKeyPanel::DoSize() // | | | | // --+---+---+--(A)--+------(B) // | | | - // | [ | | - // | | Enter | - // --+---+---+--(F)-(E) | + // | [ | Enter | + // | | | + // --+---+---+--(F)-(E) - - (G) // | | | | // | : | ] | | // | | | | @@ -113,114 +167,164 @@ WXSoftKeyPanel::DoSize() // | | // _ | SHIFT | // + // Enter キーの上半分 A-B-G-F を enter_top。F-G の線分を含む。 + // Enter キーの下半分 E-G-C-D を enter_btm。E-G の線分を含む。 const keydata_t& keybs = FindKeydata(KC_BS); const keydata_t& keyleft = FindKeydata(KC_bracketleft); const keydata_t& keyright = FindKeydata(KC_bracketright); const keydata_t& keyscore = FindKeydata(KC_underscore); - // 各点のピクセル座標 - enter_points = { - { keyleft.right() * unit, keyleft.y * unit }, // A - { keybs.right() * unit, keyleft.y * unit }, // B - { keybs.right() * unit, keyscore.y * unit }, // C - { keyright.right() * unit, keyscore.y * unit }, // D - { keyright.right() * unit, keyright.y * unit }, // E - { keyleft.right() * unit, keyright.y * unit }, // F - }; - // 当たり判定用のリージョン - enter_region = wxRegion(enter_points.size(), enter_points.data()); + enter_top.SetLTRB( + keyleft.right() * unit, keyleft.y * unit, + keybs.right() * unit, keyright.y * unit); + enter_btm.SetLTRB( + keyright.right() * unit, keyright.y * unit, + keybs.right() * unit, keyscore.y * unit); - // コントロールの大きさを変更 + // アイコンを変更。参照順序の関係で下のほうにおいてある…。 + InitIcon(); + + // バックバッファの下限を固定する wxSize size(u_width * unit, u_height * unit); - SetClientSize(size); - SetMinClientSize(size); + SetMinBitmapSize(size); - // ビットマップ作成 - bitmap.Create(size.x, size.y); + // コントロールの大きさを変更 + SetSize(size); + SetMinSize(size); +} - // 再描画を指示 +void +WXSoftKeyPanel::OnTimer(wxTimerEvent& event) +{ Refresh(); } // キー状態変更イベント (UIMessage) +// +// キー状態変更イベントは、キーの状態が変わるたびに都度通知される。 +// ソフトウェアキーボード入力とパススルーモードの入力では、どのキーに変化 +// (押下 or 開放)があったかの情報は付属しない。各キーの押下状態は全キーを +// 逐一調査することで判定する。人間時間で起きる事象なのでこの計算量は許容。 +// Char 入力モードの場合は、イベントのパラメータ引数 (GetInt() で取得可) に +// 入力のあったキーの共通キーコードが入っている (複数のキーが同時に押される +// 場合はキーの回数分のイベントが飛んでくる)。Char 入力モードにはキー開放 +// という概念はない。 void WXSoftKeyPanel::OnKeyChanged(wxCommandEvent& event) { - // 更新があれば再描画を指示 - const std::vector& pressed = gKeyboard->GetPressed(); - UpdateModifier(); - if (pressed != last_pressed || modifier != last_modifier) { - Refresh(); + // Char 入力モードでキーが押された場合は、共通キーコードが送られてくるので、 + // persistence[] をここでセットする。 + // Char 入力モードでは、キーの Make/Break が一瞬で終わるため、このイベント + // を受け取って Refresh() を発行 -> OnPaint() -> Draw() 内で IsPressed() + // を調べた頃にはタイミング問題でもうキーが離されている可能性があるので、 + // 描画時に全キーを調べる方法は使えない。 + uint keycode = event.GetInt(); + if (keycode != 0) { + assert(keycode < persistence.size()); + // 9 が減光時の初期値 (10 は減光しない点灯) + persistence[keycode] = 9; + } + + // トグルキーが開放されていたらトグル情報をクリアする。 + // ハードウェアキーボードを含む VM 側で開放された場合と、 + // ソフトウェアキーボードの KeyUp() で開放された場合のどちらも + // ここでクリア。 + for (auto& k : toggle) { + if (keyboard->IsPressed(k.first) == false) { + k.second = 0; + } } -} -// 描画イベント (UI スレッドから呼ばれる) -void -WXSoftKeyPanel::OnPaint(wxPaintEvent& event) -{ - // メモリ DC に描画 - wxMemoryDC memDC; - memDC.SelectObject(bitmap); - Draw(memDC); + // 接続状況が変わっていたらタイトルを更新。 + if (keyboard->IsConnected() != connected) { + UpdateTitle(); + } - // 実画面 DC にコピー - wxPaintDC dstDC(this); - wxSize size = bitmap.GetSize(); - dstDC.Blit(0, 0, size.x, size.y, &memDC, 0, 0); + Refresh(); } // 描画本体 void -WXSoftKeyPanel::Draw(wxDC& dc) +WXSoftKeyPanel::Draw() { - dc.SetPen(wxPen(color.Background)); - dc.SetBrush(wxBrush(color.Background)); - dc.DrawRectangle(wxPoint(0, 0), GetSize()); + bool timer_start = false; + + // キー刻印の表示更新用に修飾キーの状態を更新。 + // 本来は IsShift() だけで判定すべきだが、Char 入力モードでいずれかの + // SHIFT キーが減光中は SHIFT 刻印を継続してみるのはどうか。 + // 0 まで待つとうちの環境だと消灯した少し後に刻印が戻るように見えるため、 + // ある程度暗くなったところでもう切り替えてみる。閾値は適当。 + if ((2 < persistence[KC_SHIFT_L] && persistence[KC_SHIFT_L] < 10) || + (2 < persistence[KC_SHIFT_R] && persistence[KC_SHIFT_R] < 10) || + (2 < persistence[KC_SHIFT] && persistence[KC_SHIFT] < 10) || + keyboard->IsShift()) + { + modifier = ModShift; + } else { + modifier = ModNormal; + } + + auto text_color = color.Text; + + // キーボードが接続されていないときは刻印をグレーにしておく + if (keyboard->IsConnected() == false) { + text_color = UD_GREY; + } + SetTextForeColor(text_color); - dc.SetPen(color.Text); - SetTextForeColor(color.Text); for (const auto& key : keydata) { - bool is_pressed = gKeyboard->IsPressed(key.keycode); - if (is_pressed) { - // 押されている - SetTextBackColor(color.KeyPressed); - dc.SetBrush(color.KeyPressed); + int c = persistence[key.keycode]; + if (0 < c && c < 10) { + // Char 入力モードで減光中 + c--; + timer_start = true; } else { - // 押されていない - SetTextBackColor(color.Keytop[key.coltype]); - dc.SetBrush(wxBrush(color.Keytop[key.coltype])); + // そうでない場合に限り、現在の状態を問い合わせる + bool is_pressed = keyboard->IsPressed(key.keycode); + if (is_pressed) { + // 押されている + c = 10; + } else { + // 押されていない + c = 0; + } } + // persistence[] は 10 が(減光しない)点灯、9..1 が減光中を示す。 + persistence[key.keycode] = c; + // ただし色配列は 0..9 で 9 が最大点灯色 + if (c > 9) { + c = 9; + } + + SetTextBackColor(color.Keytop[key.coltype][c]); - // エンターキーだけ枠の描き方が違うので別処理 - if (__predict_false(key.x < 0)) { - DrawEnterKey(dc); + // エンターキーとブザー表示は描き方が違うので別処理 + if (__predict_false(key.keycode == KC_enter)) { + DrawEnterKey(); + } else if (__predict_false(key.keycode == KC_buzzer)) { + DrawBuzzer(key); } else { - DrawKey(dc, key); + DrawKey(key); } - - // 次回更新チェック用に現状を保存 - last_pressed[key.keycode] = is_pressed; } - // 次回更新チェック用に現状を保存 - last_modifier = modifier; - -#if 0 - // X68k キーボードだとどこに表示するか - SetTextBackColor(color.Background); - wxString utfstr(wxT("右クリックで長押し")); - const char *sjis = (const char *)utfstr.mb_str(conv); - DrawStringSJIS(dc, 190 * unit, 2 * unit, sjis, TA::Disable); -#endif + if (timer_start) { + timer.Start(25); + } else { + timer.Stop(); + } } // 指定のキーを一つ (枠から刻印まで) 描画する。 +// palette[FG] はテキスト色 (キーボード非接続ならグレー)。 +// palette[BG] はこのキーの背景色 (押されているか、減光中か、 +// 押されていない時の二色あるかも知れないキートップ色)。 void -WXSoftKeyPanel::DrawKey(wxDC& dc, const keydata_t& key) +WXSoftKeyPanel::DrawKey(const keydata_t& key) { + uint attr = TA::Normal; + // 枠 - wxPoint pt(key.x * unit, key.y * unit); - wxSize sz(key.w * unit + 1, key.h * unit + 1); - dc.DrawRectangle(pt, sz); + DrawKeyBox(key, palette[0], color.Text); // 刻印を選択 const char *disp = key.disp[modifier]; @@ -228,9 +332,19 @@ WXSoftKeyPanel::DrawKey(wxDC& dc, const disp = key.disp[0]; } + // トグルキーのワンショット押しは太字で表示を区別したい + const auto it = toggle.find(key.keycode); + if (it != toggle.end()) { + if (it->second) { + attr = TA::Em; + } + } + // Shift_JIS に変換 wxString utfstr(disp, wxConvUTF8); - const char *sjis = (const char *)utfstr.mb_str(conv); + // mb_str() をキャストせずに一度保持しておく必要がある (scan-build 対策) + auto mbstr = utfstr.mb_str(conv); + const char *sjis = (const char *)mbstr; // 改行があれば2行に分割 char sjis1[8] {}; char sjis2[8] {}; @@ -244,89 +358,210 @@ WXSoftKeyPanel::DrawKey(wxDC& dc, const } else { // 2行に分割。センタリングは1行目の長さだけで調べる。 strncpy(sjis1, sjis, lf - sjis); - strcpy(sjis2, lf + 1); + strlcpy(sjis2, lf + 1, sizeof(sjis2)); sjislen = strlen(sjis1); row = 2; } - // センタリング - int x = key.x + (key.w - sjislen * 2) / 2; - int y = key.y + (key.h - row * 4) / 2; + // X 方向のセンタリング。 + // unit 単位の計算では精度が足りないのでドット単位で計算する。 + int x = key.x * unit + (key.w - sjislen * 2) * unit / 2 + 1; + // Y 方向のセンタリングは、端数が出ないのと LED 用オフセットが + // unit 単位なので、unit 単位のまま計算して、後でドット単位にする。 + int y = key.y + (key.h - row * 4) / 2; // LED を描画 (機種によって色々違うので個別クラス側で処理) if (key.led >= 0) { - const wxPen oldpen = dc.GetPen(); - const wxBrush oldbrush = dc.GetBrush(); - - y += DrawLED(dc, key); - - dc.SetPen(oldpen); - dc.SetBrush(oldbrush); + y += DrawLED(key); } + y = y * unit + 1; // 文字を描画 - pt = wxPoint(x * unit + 1, y * unit + 1); if (strcmp(disp, EnterMark) == 0) { - DrawEnterMark(dc, pt); + bitmap.DrawBitmapI1(x, y, *enter_icon, palette); } else { if (lf == NULL) { // 1行の場合 - DrawStringSJIS(dc, pt.x, pt.y, sjis); + DrawStringSJIS(x, y, sjis, attr); } else { // 2行の場合 - DrawStringSJIS(dc, pt.x, pt.y, sjis1); - pt.y += 4 * unit; - DrawStringSJIS(dc, pt.x, pt.y, sjis2); + DrawStringSJIS(x, y, sjis1); + y += 4 * unit; + DrawStringSJIS(x, y, sjis2); } } } +// キーの枠と背景色を描画する。 +void +WXSoftKeyPanel::DrawKeyBox(const keydata_t& key, Color bg, Color bd) +{ + Rect rect( + key.x * unit, key.y * unit, + key.w * unit + 1, key.h * unit + 1); + bitmap.FillRect(bg, rect); + bitmap.DrawRect(bd, rect); +} + // エンターキー void -WXSoftKeyPanel::DrawEnterKey(wxDC& dc) +WXSoftKeyPanel::DrawEnterKey() { - // エンターキーを描画 - dc.DrawPolygon(enter_points.size(), enter_points.data()); + // 矩形の内側を背景色で塗りつぶす。 + bitmap.FillRect(palette[0], enter_top); + bitmap.FillRect(palette[0], enter_btm); + + // 周囲の線分 + // (A)-(B) + bitmap.DrawLineH(color.Text, + enter_top.x, enter_top.y, enter_top.GetRight()); + // (B)-(C) + bitmap.DrawLineV(color.Text, + enter_top.GetRight(), enter_top.y, enter_btm.GetBottom()); + // (C)-(D) + bitmap.DrawLineH(color.Text, + enter_btm.GetRight(), enter_btm.GetBottom(), enter_btm.x); + // (D)-(E) + bitmap.DrawLineV(color.Text, + enter_btm.x, enter_btm.GetBottom(), enter_btm.y); + // (E)-(F) + bitmap.DrawLineH(color.Text, + enter_btm.x, enter_top.GetBottom(), enter_top.x); + // (F)-(A) + bitmap.DrawLineV(color.Text, + enter_top.x, enter_top.GetBottom(), enter_top.y); // エンター記号を描画 - DrawEnterMark(dc, wxPoint( - (enter_points[0].x + enter_points[1].x) / 2 - (4 / 2), - (enter_points[1].y + enter_points[2].y) / 2 - (4 / 2))); -} - -// 指定の位置にエンター記号を描画する (エンターキー全体の描画ではない)。 -// メインキーとテンキーの両方で同じ図柄を使う。 -// 大きさは (3unit, 4unit) なので実質全角1文字分くらい。 -void -WXSoftKeyPanel::DrawEnterMark(wxDC& dc, const wxPoint& basep) -{ - // エンター記号は幅 3 unit、高さ 4 unit。 - // +0 +1 +2 +3 - // +0 .. .. .. 1. - // .. .. .. 1. - // +1 .. .. .. 1. - // .. .. .. 1. - // +2 .. 1. .. 1. - // .1 .. .. 1. - // +3 11 11 11 1. - // .1 .. .. .. - // +4 .. 1. .. .. - // .. .. .. .. - static const std::vector> entermark { - { 3, 0 }, - { 3, 3 }, // │ - { 0, 3 }, // ─ - { 1, 2 }, // / - { 0, 3 }, // (一筆書きなので戻る) - { 1, 4 }, // \ - }; - for (int i = 1; i < entermark.size(); i++) { - auto start = entermark[i - 1]; - auto end = entermark[i]; - wxPoint startp(start.first * unit, start.second * unit); - wxPoint endp(end.first * unit, end.second * unit); - dc.DrawLine(basep + startp, basep + endp); + bitmap.DrawBitmapI1( + (enter_top.x + enter_top.GetRight()) / 2 - (4 / 2), + (enter_top.y + enter_btm.GetBottom()) / 2 - (4 / 2), + *enter_icon, palette); +} + +// ブザー表示(キーに相当)を描画 +void +WXSoftKeyPanel::DrawBuzzer(const keydata_t& key) +{ + Color fg; + + // 枠。キーではないので薄くしておく。 + DrawKeyBox(key, palette[0], UD_GREY); + + // テキスト色は本来呼び出し元の DrawKey() で設定してあるが、 + // ここはキーではないので非発声時の文字色だけ薄くしたい。 + // 発声時はキー押下と同じにする。 + fg = GetTextForeColor(); + if (persistence[key.keycode] == 0) { + SetTextForeColor(UD_GREY); } + + // 刻印 (モディファイヤの影響を受けないと分かっているので常に [0]) + const char *disp = key.disp[0]; + assert(disp); + + // センタリング + int x = key.x + (key.w - strlen(disp) * 2) / 2; + int y = key.y + (key.h - 4) / 2; + + // 文字を描画 + x = x * unit + 1; + y = y * unit + 1; + DrawStringSJIS(x, y, disp, TA::Normal); + + // 前景色を元に戻す + SetTextForeColor(fg); +} + +#define B(x) (0b##x) +#define B2(x) (B(x) >> 8), (B(x) & 0xff) +#define B3(x) (B(x) >> 16), ((B(x) >> 8) & 0xff), (B(x) & 0xff) + +static const uint8 EnterIcon12[] = { // 12x12 + B2(000000000000'0000), // 0 + B2(000000001110'0000), // 1 + B2(000000001010'0000), // 2 + B2(000000001010'0000), // 3 + B2(000000001010'0000), // 4 + B2(001100001010'0000), // 5 + B2(010111110010'0000), // 6 + B2(100000000010'0000), // 7 + B2(010111111100'0000), // 8 + B2(001100000000'0000), // 9 + B2(000000000000'0000), // a + B2(000000000000'0000), // b +}; + +static const uint8 EnterIcon16[] = { // 16x16 + B2(0000000000111110), // 0 + B2(0000000000100010), // 1 + B2(0000000000100010), // 2 + B2(0000000000100010), // 3 + B2(0000000000100010), // 4 + B2(0000000000100010), // 5 + B2(0000000000100010), // 6 + B2(0000110000100010), // 7 + B2(0001010000100010), // 8 + B2(0010011111000010), // 9 + B2(0100000000000010), // a + B2(1000000000000010), // b + B2(0100000000000010), // c + B2(0010011111111100), // d + B2(0001010000000000), // e + B2(0000110000000000), // f +}; + +static const uint8 EnterIcon24[] = { // 24x24 + B3(00000000'00000001'11111100), // 0 + B3(00000000'00000001'11111100), // 1 + B3(00000000'00000001'10001100), // 2 + B3(00000000'00000001'10001100), // 3 + B3(00000000'00000001'10001100), // 4 + B3(00000000'00000001'10001100), // 5 + B3(00000000'00000001'10001100), // 6 + B3(00000000'00000001'10001100), // 7 + B3(00000000'00000001'10001100), // 8 + B3(00000000'11000001'10001100), // 9 + B3(00000001'11000001'10001100), // 10 + B3(00000011'11000001'10001100), // 11 + B3(00000110'11000001'10001100), // 12 + B3(00001100'11111111'10001100), // 13 + B3(00011000'11111111'10001100), // 14 + B3(00110000'00000000'00001100), // 15 + B3(01100000'00000000'00001100), // 16 + B3(00110000'00000000'00001100), // 17 + B3(00011000'11111111'11111100), // 18 + B3(00001100'11111111'11111000), // 19 + B3(00000110'11000000'00000000), // 20 + B3(00000011'11000000'00000000), // 21 + B3(00000001'11000000'00000000), // 22 + B3(00000000'11000000'00000000), // 23 +}; + +// アイコンを初期化する。FontChanged() から呼ばれる。 +// ソース先頭のほうにデータの羅列を置きたくないが、 +// 容量不詳の配列の解決が面倒なのでこれだけ下のほうのここに置いてある。 +void +WXSoftKeyPanel::InitIcon() +{ + const int width = font_width; + const int height = font_height; + const uint8 *icon; + + switch (height) { + case 12: + icon = EnterIcon12; + break; + case 16: + icon = EnterIcon16; + break; + case 24: + icon = EnterIcon24; + break; + default: + PANIC("Unexpected font_height=%d", height); + } + + enter_icon.reset(new BitmapI1(icon, width * 2, height)); } // keycode に対応する keydata を返す @@ -339,7 +574,7 @@ WXSoftKeyPanel::FindKeydata(uint keycode } } // 見付からないはずはない - assertmsg(0, "keycode %d not found", keycode); + PANIC("keycode %d not found", keycode); } // マウス左クリック (Down) イベント @@ -349,18 +584,31 @@ WXSoftKeyPanel::OnLeftDown(wxMouseEvent& const wxPoint& pt = event.GetPosition(); const keydata_t *key = GetKeydataFromPoint(pt); - DoLeftDown(key); + if (key != NULL) { + DoLeftDown(key->keycode); + } } // マウス左クリック (Down) 処理 void -WXSoftKeyPanel::DoLeftDown(const keydata_t *key) +WXSoftKeyPanel::DoLeftDown(uint code) { - if (key != NULL) { - // 押下 - KeyDown(*key); - // LeftUp のために覚えておく - leftdown_key = key; + auto it = toggle.find(code); + if (it != toggle.end()) { + // トグルキーはここで完結。LeftUp では何もしない。 + // second のクリアは KeyUp() からコールバックされる OnKeyChanged() + // で行っている。 + if (keyboard->IsPressed(code)) { + KeyUp(code); + } else { + KeyDown(code); + it->second = code; + } + leftdown_key = KC_none; + } else { + // トグルでない通常キーはここで押下して LeftUp のために覚えておく + KeyDown(code); + leftdown_key = code; } } @@ -370,20 +618,21 @@ WXSoftKeyPanel::OnLeftUp(wxMouseEvent& e { // Up 時は、これが起きた地点のキーコードではなく // 直近に LeftDown したキーコードをターゲットにする。 - const keydata_t *key = leftdown_key; + uint code = leftdown_key; - DoLeftUp(key); -} + if (code != KC_none) { + KeyUp(code); -// マウス左クリック (Up) 処理 -void -WXSoftKeyPanel::DoLeftUp(const keydata_t *key) -{ - if (key != NULL) { - // 開放 - KeyUp(*key); + // 通常キーが離されたら、トグルキーはすべて開放 + for (const auto& k : toggle) { + auto tcode = k.second; + if (tcode) { + KeyUp(tcode); + } + } } - leftdown_key = NULL; + + leftdown_key = KC_none; } // マウス左ダブルクリックイベント @@ -402,7 +651,9 @@ WXSoftKeyPanel::OnLeftDClick(wxMouseEven const wxPoint& pt = event.GetPosition(); const keydata_t *key = GetKeydataFromPoint(pt); - DoLeftDown(key); + if (key != NULL) { + DoLeftDown(key->keycode); + } } // マウス右クリック (Down) イベント @@ -416,12 +667,12 @@ WXSoftKeyPanel::OnRightDown(wxMouseEvent if (key != NULL) { uint code = key->keycode; - if (gKeyboard->IsPressed(code)) { + if (keyboard->IsPressed(code)) { // 押されていたら開放 - KeyUp(*key); + KeyUp(code); } else { // 押されてなければ長押し開始 - KeyDown(*key); + KeyDown(code); } } } @@ -432,7 +683,7 @@ const keydata_t * WXSoftKeyPanel::GetKeydataFromPoint(const wxPoint& pt) const { // エンターキーだけ先に別判定 - if (enter_region.Contains(pt) == wxInRegion) { + if (enter_top.Contains(pt.x, pt.y) || enter_btm.Contains(pt.x, pt.y)) { return &FindKeydata(KC_enter); } @@ -453,164 +704,144 @@ WXSoftKeyPanel::GetKeydataFromPoint(cons return NULL; } -// 修飾キーなら true を返す -// (今は SHIFT しかないから修飾キーならなのか SHIFT ならなのか曖昧) -bool -WXSoftKeyPanel::IsModifier(uint code) const -{ - if (code == KC_SHIFT_L || code == KC_SHIFT_R || code == KC_SHIFT) { - return true; - } else { - return false; - } -} - -// 修飾キーの状態を更新。今は SHIFT かどうかしかない -void -WXSoftKeyPanel::UpdateModifier() -{ - if (gKeyboard->IsShift()) { - modifier = ModShift; - } else { - modifier = ModNormal; - } -} - // このキーが押された処理 void -WXSoftKeyPanel::KeyDown(const keydata_t& key) +WXSoftKeyPanel::KeyDown(uint code) { - uint code = key.keycode; - - // VM に通知 (Keyboard がそれをホストに通知するかはまた別) - gKeyboard->MakeKey(code); - - // 修飾キー - if (IsModifier(code)) { - UpdateModifier(); - } - - // キー状態が変わった(かも知れない)ので再描画 - // 押した時にはタイマーを待たずに再描画したほうがよかろう - Refresh(); + // VM に通知 (Keyboard がホストに通知する) + keyboard->MakeKey(code); } // このキーが放された処理 void -WXSoftKeyPanel::KeyUp(const keydata_t& key) +WXSoftKeyPanel::KeyUp(uint code) { - uint code = key.keycode; - - // VM に通知 (Keyboard がそれをホストに通知するかはまた別) - gKeyboard->BreakKey(code); - - // 修飾キー - if (IsModifier(code)) { - UpdateModifier(); - } - - // キー状態が変わった(かも知れない)が、 - // 解放時はタイマーに任せた再描画でよかろう - //Refresh(); + // VM に通知 (Keyboard がホストに通知する) + keyboard->BreakKey(code); } - -// -// LUNA ソフトウェアキーボード (パネル) -// - -// コンストラクタ -WXLunaSoftKeyPanel::WXLunaSoftKeyPanel(wxWindow *parent) - : inherited(parent, keydata, 226, 54) +// LUNA-I、LUNA-88K のコンストラクタ共通部分。 +// クラス階層を増やすのも手間なので。 +void +WXSoftKeyPanel::InitLunaCommon() { // LUNA では // BS キーの左隣 (0x5c) は円記号ではなくバックスラッシュ。 // それを SHIFT したやつ(0x7c) は破線でないパイプ。 // そのもう一つ左隣 (0x7e) はオーバーラインではなくチルダ。 - SetGlyph5C(true); - SetGlyph7E(true); + gFontManager->SetGlyph5C(true); + gFontManager->SetGlyph7E(true); + + // 白黒モデル共通 + color.Border = UD_BLACK; + color.LED[0] = UD_RED; // キートップの濃淡はユニバーサルデザインの推奨色ではないけど // ここは見分けを付けるためではなくただのデザインなので。 if (1) { // 白モデル - color = { - .Background = UD_LIGHT_GREY, // 現物新品は何色だったんだろう - .Text = *wxBLACK, - .Keytop = { *wxWHITE, wxColour(200, 200, 203) }, - // 白黒共通 - .KeyPressed = UD_BLUE, - .Border = *wxBLACK, - .LED = { UD_RED }, - }; + color.Background = UD_LIGHT_GREY; // 現物新品は何色だったんだろう + color.Text = UD_BLACK; + color.Keytop[0][0] = UD_WHITE; + color.Keytop[1][0] = Color(200, 200, 203); } else { // 黒モデル - color = { - .Background = *wxBLACK, - .Text = *wxWHITE, - .Keytop = { wxColour(50, 50, 53), *wxBLACK }, - // 白黒共通 - .KeyPressed = UD_BLUE, - .Border = *wxBLACK, - .LED = { UD_RED }, - }; + color.Background = UD_BLACK; + color.Text = UD_WHITE; + color.Keytop[0][0] = Color(50, 50, 53); + color.Keytop[1][0] = UD_BLACK; } + InitColorKeytop(2); + + SetBitmapBGColor(color.Background); + Fill(); +} + + +// +// LUNA-I ソフトウェアキーボード (パネル) +// + +// コンストラクタ +WXLuna1SoftKeyPanel::WXLuna1SoftKeyPanel(wxWindow *parent) + : inherited(parent, keydata, 226, 54) +{ + InitLunaCommon(); } // デストラクタ -WXLunaSoftKeyPanel::~WXLunaSoftKeyPanel() +WXLuna1SoftKeyPanel::~WXLuna1SoftKeyPanel() { } // LED を描画して刻印描画のための y offset を返す。 int -WXLunaSoftKeyPanel::DrawLED(wxDC& dc, const keydata_t& key) +WXLuna1SoftKeyPanel::DrawLED(const keydata_t& key) { - const std::vector& led = gKeyboard->GetLED(); + const std::vector& led = keyboard->GetLED(); + Color fg; + Color bg; if (led[key.led]) { // 点灯時は赤、枠は黒 - dc.SetPen(color.Border); - dc.SetBrush(color.LED[0]); + fg = color.Border; + bg = color.LED[0]; } else { // 消灯時は元のキートップの色で、枠は薄めにしたい // (枠の色は今の所全モデル共通なので ColorPalette に含めていない) - dc.SetPen(UD_GREY); - dc.SetBrush(color.Keytop[key.coltype]); + fg = UD_GREY; + bg = color.Keytop[key.coltype][0]; } // LED を左肩に描く - wxPoint pt = wxPoint(key.x * unit + 2, key.y * unit + 2); - wxSize sz = wxSize(4 * unit - 2, 3 * unit - 2); - dc.DrawRectangle(pt, sz); + Rect rect(key.x * unit + 2, key.y * unit + 2, 4 * unit - 2, 3 * unit - 2); + bitmap.FillRect(bg, rect); + bitmap.DrawRect(fg, rect); // そのため文字は少し下げる return +1; } -// キーデータ +// LUNA-I のファンクションキーは ESC 行との間が少し空いている。 +// LUNA-88K のファンクションキー行は ESC 行とぴったりついていて、キーの +// 縦の長さも他のキーと同じ感じ。 +// X68030 のファンクションキーは ESC 行との間が空いていて、キーの長さは +// 他より短い。 +// +// 2 - +--------+ +// 4 - | LUNA-I | +-------+ +--------+ +// 6 - | | | 88K | | X68030 | +// 8 - | | | | | | +// 10 - +--------+ | | +--------+ +// 12 - +--------+ +-------+ +--------+ <- ESC 行の上辺 +// 14 - | ESC | | 1 | | 2 | +// #define H (8) // キーの高さ -#define L0 (2) // ファンクションキーの行 +#define LH (2) // ファンクションキーの行 (ESC 行との間に空き) +#define L0 (4) // ファンクションキーは少し低い(横長い) #define L1 (12) // ESC の行 #define L2 (20) // TAB の行 #define L3 (28) // CTRL の行 #define L4 (36) // SHIFT の行 #define L5 (44) // space の行 + +// キーデータ /*static*/ std::vector -WXLunaSoftKeyPanel::keydata { +WXLuna1SoftKeyPanel::keydata { // +---- キートップの色(1:濃) // | +- 0 以上なら LED 番号 // X Y W H C L KeyCode 通常 SHIFT - { 2, L0, 15, H, 1,-1, KC_F1, { "PF1" } }, - { 17, L0, 15, H, 1,-1, KC_F2, { "PF2" } }, - { 32, L0, 15, H, 1,-1, KC_F3, { "PF3" } }, - { 47, L0, 15, H, 1,-1, KC_F4, { "PF4" } }, - { 62, L0, 15, H, 1,-1, KC_F5, { "PF5" } }, - { 81, L0, 15, H, 1,-1, KC_F6, { "PF6" } }, - { 96, L0, 15, H, 1,-1, KC_F7, { "PF7" } }, - { 111, L0, 15, H, 1,-1, KC_F8, { "PF8" } }, - { 126, L0, 15, H, 1,-1, KC_F9, { "PF9" } }, - { 141, L0, 15, H, 1,-1, KC_F10, { "PF10" } }, + { 2, LH, 15, H, 1,-1, KC_F1, { "PF1" } }, + { 17, LH, 15, H, 1,-1, KC_F2, { "PF2" } }, + { 32, LH, 15, H, 1,-1, KC_F3, { "PF3" } }, + { 47, LH, 15, H, 1,-1, KC_F4, { "PF4" } }, + { 62, LH, 15, H, 1,-1, KC_F5, { "PF5" } }, + { 81, LH, 15, H, 1,-1, KC_F6, { "PF6" } }, + { 96, LH, 15, H, 1,-1, KC_F7, { "PF7" } }, + { 111, LH, 15, H, 1,-1, KC_F8, { "PF8" } }, + { 126, LH, 15, H, 1,-1, KC_F9, { "PF9" } }, + { 141, LH, 15, H, 1,-1, KC_F10, { "PF10" } }, + { 210, LH+1, 14, H-2, 1,-1, KC_buzzer, { "Buzzer" } }, { 2, L1, 12, H, 1,-1, KC_ESC, { "ESC" } }, { 14, L1, 10, H, 0,-1, KC_1, { "1", "!" } }, @@ -719,6 +950,214 @@ WXLunaSoftKeyPanel::keydata { // +// LUNA-88K ソフトウェアキーボード (パネル) +// + +// コンストラクタ +WXLuna88kSoftKeyPanel::WXLuna88kSoftKeyPanel(wxWindow *parent) + : inherited(parent, keydata, 226, 54) +{ + InitLunaCommon(); +} + +// デストラクタ +WXLuna88kSoftKeyPanel::~WXLuna88kSoftKeyPanel() +{ +} + +// LED を描画する。 +// 独立 LED なので戻り値は使わないので 0 でいい。 +int +WXLuna88kSoftKeyPanel::DrawLED(const keydata_t& basekey) +{ + const std::vector& led = keyboard->GetLED(); + Color fg_backup; + Color bg_backup; + Color fg; + TA attr; + + fg_backup = GetTextForeColor(); + bg_backup = GetTextBackColor(); + + if (led[basekey.led]) { + // 点灯時、文字は LED 色でボールド。 + fg = color.LED[0]; + attr = TA::Bold; + } else { + // 消灯時、文字はグレーで通常体。 + fg = UD_GREY; + attr = TA::Normal; + } + SetTextForeColor(fg); + // 背景はキーの押し下げ状態ではなく常にキー開放色のままとする。 + SetTextBackColor(color.Keytop[1][0]); + + // LUNA-88K キーボードは LED 入りキーではなく、別のところに + // LED だけがあるタイプ。(今どきの PC キーボードに近い) + static const keydata_t led_caps = { + 184, L0+1, 10, H-2, 1, -1, 0, { "Caps" } + }; + static const keydata_t led_kana = { + 194, L0+1, 10, H-2, 1, -1, 0, { "Kana" } + }; + const keydata_t& key = (basekey.keycode == KC_CAPS) + ? led_caps + : led_kana; + + // 枠を描画。 + // 2つの LED で枠が重なるため状態によって色を変えられない。 + DrawKeyBox(key, color.Keytop[1][0], UD_GREY); + + // ラベルをセンタリング。 + const char *disp = key.disp[0]; + int x = key.x + (key.w - strlen(disp) * 2) / 2; + int y = key.y + (key.h - 4) / 2; + + // ラベルを描画。 + x = x * unit + 1; + y = y * unit + 1; + DrawStringSJIS(x, y, disp, attr); + + // 前景色、背景色を元に戻す。 + SetTextForeColor(fg_backup); + SetTextBackColor(bg_backup); + + // 元のキーの文字描画オフセットは無し。 + return 0; +} + + +// キーデータ +/*static*/ std::vector +WXLuna88kSoftKeyPanel::keydata { + // +---- キートップの色(1:濃) + // | +- 0 以上なら LED 番号 + // X Y W H C L KeyCode 通常 SHIFT + { 2, L0, 10, H, 1,-1, KC_F1, { "PF1" } }, + { 12, L0, 10, H, 1,-1, KC_F2, { "PF2" } }, + { 22, L0, 10, H, 1,-1, KC_F3, { "PF3" } }, + { 32, L0, 10, H, 1,-1, KC_F4, { "PF4" } }, + { 42, L0, 10, H, 1,-1, KC_F5, { "PF5" } }, + { 52, L0, 10, H, 1,-1, KC_F6, { "PF6" } }, + { 62, L0, 10, H, 1,-1, KC_F7, { "PF7" } }, + { 72, L0, 10, H, 1,-1, KC_F8, { "PF8" } }, + { 82, L0, 10, H, 1,-1, KC_F9, { "PF9" } }, + { 92, L0, 10, H, 1,-1, KC_F10, { "PF10" } }, + { 102, L0, 10, H, 1,-1, KC_PF11, { "消去" } }, + { 112, L0, 10, H, 1,-1, KC_PF12, { "呼出" } }, + { 122, L0, 10, H, 1,-1, KC_PF13, { "文節\n←" } }, + { 132, L0, 10, H, 1,-1, KC_PF14, { "文節\n→" } }, + { 142, L0, 14, H, 1,-1, KC_BS, { "BS" } }, + + { 210, L0+1, 14, H-2, 1,-1, KC_buzzer, { "Buzzer" } }, + + { 2, L1, 12, H, 1,-1, KC_ESC, { "ESC" } }, + { 14, L1, 10, H, 0,-1, KC_1, { "1", "!" } }, + { 24, L1, 10, H, 0,-1, KC_2, { "2", "\"" } }, + { 34, L1, 10, H, 0,-1, KC_3, { "3", "#" } }, + { 44, L1, 10, H, 0,-1, KC_4, { "4", "$" } }, + { 54, L1, 10, H, 0,-1, KC_5, { "5", "%" } }, + { 64, L1, 10, H, 0,-1, KC_6, { "6", "&" } }, + { 74, L1, 10, H, 0,-1, KC_7, { "7", "'" } }, + { 84, L1, 10, H, 0,-1, KC_8, { "8", "(" } }, + { 94, L1, 10, H, 0,-1, KC_9, { "9", ")" } }, + { 104, L1, 10, H, 0,-1, KC_0, { "0", " " } }, + { 114, L1, 10, H, 0,-1, KC_minus, { "-", "=" } }, + { 124, L1, 10, H, 0,-1, KC_circum, { "^", "~" } }, + { 134, L1, 10, H, 0,-1, KC_backslash, { "\\", "|" } }, + { 144, L1, 12, H, 1,-1, KC_DEL, { "DEL" } }, + + { 2, L2, 17, H, 1,-1, KC_TAB, { "TAB" } }, + { 19, L2, 10, H, 0,-1, KC_Q, { "q", "Q" } }, + { 29, L2, 10, H, 0,-1, KC_W, { "w", "W" } }, + { 39, L2, 10, H, 0,-1, KC_E, { "e", "E" } }, + { 49, L2, 10, H, 0,-1, KC_R, { "r", "R" } }, + { 59, L2, 10, H, 0,-1, KC_T, { "t", "T" } }, + { 69, L2, 10, H, 0,-1, KC_Y, { "y", "Y" } }, + { 79, L2, 10, H, 0,-1, KC_U, { "u", "U" } }, + { 89, L2, 10, H, 0,-1, KC_I, { "i", "I" } }, + { 99, L2, 10, H, 0,-1, KC_O, { "o", "O" } }, + { 109, L2, 10, H, 0,-1, KC_P, { "p", "P" } }, + { 119, L2, 10, H, 0,-1, KC_at, { "@", "`" } }, + { 129, L2, 10, H, 0,-1, KC_bracketleft, { "[", "{" } }, + + { 2, L3, 20, H, 1,-1, KC_CTRL, { "CTRL" } }, + { 22, L3, 10, H, 0,-1, KC_A, { "a", "A" } }, + { 32, L3, 10, H, 0,-1, KC_S, { "s", "S" } }, + { 42, L3, 10, H, 0,-1, KC_D, { "d", "D" } }, + { 52, L3, 10, H, 0,-1, KC_F, { "f", "F" } }, + { 62, L3, 10, H, 0,-1, KC_G, { "g", "G" } }, + { 72, L3, 10, H, 0,-1, KC_H, { "h", "H" } }, + { 82, L3, 10, H, 0,-1, KC_J, { "j", "J" } }, + { 92, L3, 10, H, 0,-1, KC_K, { "k", "K" } }, + { 102, L3, 10, H, 0,-1, KC_L, { "l", "L" } }, + { 112, L3, 10, H, 0,-1, KC_semicolon, { ";", "+" } }, + { 122, L3, 10, H, 0,-1, KC_colon, { ":", "*" } }, + { 132, L3, 10, H, 0,-1, KC_bracketright, { "]", "}" } }, + + { 2, L4, 25, H, 1,-1, KC_SHIFT_L, { "SHIFT" } }, + { 27, L4, 10, H, 0,-1, KC_Z, { "z", "Z" } }, + { 37, L4, 10, H, 0,-1, KC_X, { "x", "X" } }, + { 47, L4, 10, H, 0,-1, KC_C, { "c", "C" } }, + { 57, L4, 10, H, 0,-1, KC_V, { "v", "V" } }, + { 67, L4, 10, H, 0,-1, KC_B, { "b", "B" } }, + { 77, L4, 10, H, 0,-1, KC_N, { "n", "N" } }, + { 87, L4, 10, H, 0,-1, KC_M, { "m", "M" } }, + { 97, L4, 10, H, 0,-1, KC_comma, { ",", "<" } }, + { 107, L4, 10, H, 0,-1, KC_period, { ".", ">" } }, + { 117, L4, 10, H, 0,-1, KC_slash, { "/", "?" } }, + { 127, L4, 10, H, 0,-1, KC_underscore, { " ", "_" } }, + { 137, L4, 19, H, 1,-1, KC_SHIFT_R, { "SHIFT" } }, + + { 2, L5, 10, H, 1,-1, KC_SF, { "META" } }, + { 12, L5, 20, H, 1,-1, KC_VALID, { "確定" } }, + { 32, L5, 10, H, 1, 1, KC_CAPS, { "CAPS" } }, + { 42, L5, 80, H, 0,-1, KC_space, { " " } }, + { 122, L5, 10, H, 1, 0, KC_kana, { "かな" } }, + { 132, L5, 24, H, 1,-1, KC_XFER, { "変換" } }, + + // カーソルキー島 + { 159, L1, 11, H, 1,-1, KC_INS, { "INS" } }, + { 170, L1, 11, H, 1,-1, KC_COPY, { "COPY" } }, + { 159, L2, 11, H, 1,-1, KC_CUT, { "CUT" } }, + { 170, L2, 11, H, 1,-1, KC_PASTE, { "PASTE" } }, + { 159, L3, 22, H, 1,-1, KC_up, { "↑" } }, + { 159, L4, 11, H, 1,-1, KC_left, { "←" } }, + { 170, L4, 11, H, 1,-1, KC_right, { "→" } }, + { 159, L5, 22, H, 1,-1, KC_down, { "↓" } }, + + // テンキー島 + { 184, L1, 10, H, 1,-1, KC_HOME, { "HOME" } }, + { 194, L1, 10, H, 1,-1, KC_PAD_plus, { "+" } }, + { 204, L1, 10, H, 1,-1, KC_PAD_minus, { "-" } }, + { 214, L1, 10, H, 1,-1, KC_PAD_multiply, { "*" } }, + + { 184, L2, 10, H, 0,-1, KC_PAD_7, { "7" } }, + { 194, L2, 10, H, 0,-1, KC_PAD_8, { "8" } }, + { 204, L2, 10, H, 0,-1, KC_PAD_9, { "9" } }, + { 214, L2, 10, H, 1,-1, KC_PAD_divide, { "/" } }, + + { 184, L3, 10, H, 0,-1, KC_PAD_4, { "4" } }, + { 194, L3, 10, H, 0,-1, KC_PAD_5, { "5" } }, + { 204, L3, 10, H, 0,-1, KC_PAD_6, { "6" } }, + { 214, L3, 10, H, 1,-1, KC_PAD_equal, { "=" } }, + + { 184, L4, 10, H, 0,-1, KC_PAD_1, { "1" } }, + { 194, L4, 10, H, 0,-1, KC_PAD_2, { "2" } }, + { 204, L4, 10, H, 0,-1, KC_PAD_3, { "3" } }, + { 214, L4, 10, H, 1,-1, KC_PAD_comma, { "," } }, + + { 184, L5, 10, H, 0,-1, KC_PAD_0, { "0" } }, + { 194, L5, 10, H, 0,-1, KC_PAD_decimal, { "." } }, + { 204, L5, 20, H, 1,-1, KC_PAD_enter, { EnterMark } }, + + // Enter だけ矩形でないので別処理するが + // この構造体には全部のキー情報が統一的に並んでいるほうがよかろう。 + { -1, -1, -1, -1, 1,-1, KC_enter, { EnterMark } }, +}; + + +// // X68k ソフトウェアキーボード (パネル) // @@ -727,20 +1166,23 @@ WXX68kSoftKeyPanel::WXX68kSoftKeyPanel(w : inherited(parent, keydata, 235, 54) { // X68k では SRAM 設定に同期させる。 - uint8 sw = gSRAM->Peek8(0xed0059); - SetGlyph5C((sw & 0x01)); - SetGlyph7E((sw & 0x02)); - SetGlyph7C((sw & 0x04)); + const auto sram = GetSRAMDevice(); + uint8 sw = sram->Peek1(0xed0059); + gFontManager->SetGlyph5C((sw & 0x01)); + gFontManager->SetGlyph7E((sw & 0x02)); + gFontManager->SetGlyph7C((sw & 0x04)); // とりあえず黒のみ - color = { - .Background = wxColour(50, 50, 53), - .Text = *wxWHITE, - .Keytop = { *wxBLACK }, - .KeyPressed = UD_BLUE, - .Border = *wxBLACK, - .LED = { UD_RED, UD_YELLOW_GREEN }, - }; + color.Background = Color(50, 50, 53); + color.Text = UD_WHITE; + color.Border = UD_BLACK; + color.LED[0] = UD_RED; + color.LED[1] = UD_YELLOW_GREEN; + color.Keytop[0][0] = UD_BLACK; + InitColorKeytop(1); + + SetBitmapBGColor(color.Background); + Fill(); } // デストラクタ @@ -750,9 +1192,11 @@ WXX68kSoftKeyPanel::~WXX68kSoftKeyPanel( // LED を描画して刻印描画のための y offset を返す。 int -WXX68kSoftKeyPanel::DrawLED(wxDC& dc, const keydata_t& key) +WXX68kSoftKeyPanel::DrawLED(const keydata_t& key) { - const std::vector& led = gKeyboard->GetLED(); + const std::vector& led = keyboard->GetLED(); + Color fg; + Color bg; // 色を選択 // idx 刻印 色 @@ -766,42 +1210,42 @@ WXX68kSoftKeyPanel::DrawLED(wxDC& dc, co // 6 全角 緑 if (led[key.led]) { int n = (key.led < 5) ? 0 : 1; - dc.SetPen(color.LED[n]); - dc.SetBrush(color.LED[n]); + fg = color.LED[n]; + bg = color.LED[n]; } else { // 消灯時は元のキートップの色で、枠は薄めにしたい // (枠の色は今の所全モデル共通なので ColorPalette に含めていない) - dc.SetPen(UD_GREY); - dc.SetBrush(color.Keytop[key.coltype]); + fg = UD_GREY; + bg = color.Keytop[key.coltype][0]; } // LED は中央前方(画面でいうと下) - wxPoint pt = wxPoint((key.x + 3) * unit, (key.y + key.h - 2) * unit); - wxSize sz = wxSize(4 * unit, 2 * unit); - dc.DrawRectangle(pt, sz); + Rect rect((key.x + 3) * unit, (key.y + key.h - 2) * unit, + 4 * unit, 2 * unit); + bitmap.FillRect(bg, rect); + bitmap.DrawRect(fg, rect); // そのため文字は少し上げる return -1; } -#define LF (L0 + 2) // ファンクションキーは少し低い(横長い) #define HT (H * 2) // 縦2倍角のキー /*static*/ std::vector WXX68kSoftKeyPanel::keydata { // +- 0以上なら LED 番号 // X Y W H C L KeyCode 通常 SHIFT - { 2, L0, 10, H, 0,-1, KC_BREAK, { "\x4\x5\x6\x7" } }, - { 15, L0, 10, H, 0,-1, KC_COPY, { "COPY" } }, - { 29, LF, 12, 6, 0,-1, KC_F1, { "F1" } }, - { 41, LF, 12, 6, 0,-1, KC_F2, { "F2" } }, - { 53, LF, 12, 6, 0,-1, KC_F3, { "F3" } }, - { 65, LF, 12, 6, 0,-1, KC_F4, { "F4" } }, - { 77, LF, 13, 6, 0,-1, KC_F5, { "F5" } }, - { 94, LF, 13, 6, 0,-1, KC_F6, { "F6" } }, - { 106, LF, 12, 6, 0,-1, KC_F7, { "F7" } }, - { 118, LF, 12, 6, 0,-1, KC_F8, { "F8" } }, - { 130, LF, 12, 6, 0,-1, KC_F9, { "F9" } }, - { 142, LF, 13, 6, 0,-1, KC_F10, { "F10" } }, + { 2, LH, 10, H, 0,-1, KC_BREAK, { "\x4\x5\x6\x7" } }, + { 15, LH, 10, H, 0,-1, KC_COPY, { "COPY" } }, + { 29, L0, 12, 6, 0,-1, KC_F1, { "F1" } }, + { 41, L0, 12, 6, 0,-1, KC_F2, { "F2" } }, + { 53, L0, 12, 6, 0,-1, KC_F3, { "F3" } }, + { 65, L0, 12, 6, 0,-1, KC_F4, { "F4" } }, + { 77, L0, 13, 6, 0,-1, KC_F5, { "F5" } }, + { 94, L0, 13, 6, 0,-1, KC_F6, { "F6" } }, + { 106, L0, 12, 6, 0,-1, KC_F7, { "F7" } }, + { 118, L0, 12, 6, 0,-1, KC_F8, { "F8" } }, + { 130, L0, 12, 6, 0,-1, KC_F9, { "F9" } }, + { 142, L0, 13, 6, 0,-1, KC_F10, { "F10" } }, { 2, L1, 10, H, 0,-1, KC_ESC, { "ESC" } }, { 12, L1, 10, H, 0,-1, KC_1, { "1", "!" } }, @@ -907,7 +1351,7 @@ WXX68kSoftKeyPanel::keydata { { 193, L4, 10, H, 0,-1, KC_PAD_1, { "1" } }, { 203, L4, 10, H, 0,-1, KC_PAD_2, { "2" } }, { 213, L4, 10, H, 0,-1, KC_PAD_3, { "3" } }, - { 223, L4, 10, HT,0,-1, KC_PAD_enter, { "\xb\xc\xd\xe" } }, + { 223, L4, 10, HT,0,-1, KC_PAD_enter, { "\xb\xc\xe\xf" } }, { 193, L5, 10, H, 0,-1, KC_PAD_0, { "0" } }, { 203, L5, 10, H, 0,-1, KC_PAD_comma, { "," } }, { 213, L5, 10, H, 0,-1, KC_PAD_decimal, { "." } }, @@ -917,26 +1361,29 @@ WXX68kSoftKeyPanel::keydata { { -1, -1, -1, -1, 0,-1, KC_enter, { EnterMark } }, }; + // // ソフトウェアキーボード (ウィンドウ) // // コンストラクタ -WXSoftKeyWindow::WXSoftKeyWindow(wxWindow *parent, vmtype_t vmtype) +WXSoftKeyWindow::WXSoftKeyWindow(wxWindow *parent, VMType vmtype) : inherited(parent, wxID_ANY, _("Software Keyboard")) { - wxBoxSizer *topsizer = new wxBoxSizer(wxVERTICAL); - - if (vmtype == VMTYPE_X68030) { - panel = new WXX68kSoftKeyPanel(this); - } else { - panel = new WXLunaSoftKeyPanel(this); + switch (vmtype) { + case VMType::X68030: + new WXX68kSoftKeyPanel(this); + break; + case VMType::LUNA1: + new WXLuna1SoftKeyPanel(this); + break; + case VMType::LUNA88K: + new WXLuna88kSoftKeyPanel(this); + break; + default: + assert(false); } - topsizer->Add(panel, 0, wxEXPAND); - - SetSizer(topsizer); - // 大きさをそれに固定 Fit(); }