--- nono/wx/wxsoftkey.cpp 2026/04/29 17:05:12 1.1.1.12 +++ nono/wx/wxsoftkey.cpp 2026/04/29 17:05:16 1.1.1.13 @@ -11,6 +11,7 @@ #include "wxsoftkey.h" #include "fontmanager.h" #include "wxcolor.h" +#include "wxmainframe.h" #include "wxmainview.h" #include "wxuimessage.h" #include "sram.h" @@ -41,6 +42,9 @@ WXSoftKeyPanel::WXSoftKeyPanel(wxWindow : inherited(parent) , keydata(keydata_) { + // デバイスを取得 + keyboard = GetKeyboard(); + timer.SetOwner(this); u_width = u_width_; @@ -60,12 +64,14 @@ WXSoftKeyPanel::WXSoftKeyPanel(wxWindow std::fill(persistence.begin(), persistence.end(), 0); // このパネルへのキー入力はメインビューへのキー入力と同じ。 + auto mainframe = dynamic_cast(GetParent()->GetParent()); + auto mainview = mainframe->GetMainView(); Connect(wxEVT_CHAR, wxCharEventHandler(WXMainView::OnChar), NULL, - gMainView); + mainview); Connect(wxEVT_KEY_UP, wxKeyEventHandler(WXMainView::OnKeyUp), NULL, - gMainView); + mainview); Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(WXMainView::OnKeyDown), NULL, - gMainView); + mainview); // VM からの通知を受け取る WXUIMessage::Connect(UIMessage::KEYBOARD, this, @@ -91,7 +97,7 @@ WXSoftKeyPanel::~WXSoftKeyPanel() timer.Stop(); - WXUIMessage::Disconnect(UIMessage::KEYBOARD, + WXUIMessage::Disconnect(UIMessage::KEYBOARD, this, wxCommandEventHandler(WXSoftKeyPanel::OnKeyChanged)); } @@ -104,7 +110,7 @@ WXSoftKeyPanel::UpdateTitle() assert(parent); // 次回比較用にメンバ変数に覚えておく - connected = gKeyboard->IsConnected(); + connected = keyboard->IsConnected(); if (connected) { parent->SetTitle(title); @@ -178,8 +184,14 @@ WXSoftKeyPanel::FontChanged() keyright.right() * unit, keyright.y * unit, keybs.right() * unit, keyscore.y * unit); - // コントロールの大きさを変更 + // アイコンを変更。参照順序の関係で下のほうにおいてある…。 + InitIcon(); + + // バックバッファのサイズを固定する wxSize size(u_width * unit, u_height * unit); + SetFixedSize(size); + + // コントロールの大きさを変更 SetClientSize(size); SetMinClientSize(size); } @@ -221,13 +233,13 @@ WXSoftKeyPanel::OnKeyChanged(wxCommandEv // ソフトウェアキーボードの KeyUp() で開放された場合のどちらも // ここでクリア。 for (auto& k : toggle) { - if (gKeyboard->IsPressed(k.first) == false) { + if (keyboard->IsPressed(k.first) == false) { k.second = 0; } } // 接続状況が変わっていたらタイトルを更新。 - if (gKeyboard->IsConnected() != connected) { + if (keyboard->IsConnected() != connected) { UpdateTitle(); } @@ -248,7 +260,7 @@ WXSoftKeyPanel::Draw() 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) || - gKeyboard->IsShift()) + keyboard->IsShift()) { modifier = ModShift; } else { @@ -258,7 +270,7 @@ WXSoftKeyPanel::Draw() auto text_color = color.Text; // キーボードが接続されていないときは刻印をグレーにしておく - if (gKeyboard->IsConnected() == false) { + if (keyboard->IsConnected() == false) { text_color = UD_GREY; } SetTextForeColor(text_color); @@ -271,7 +283,7 @@ WXSoftKeyPanel::Draw() timer_start = true; } else { // そうでない場合に限り、現在の状態を問い合わせる - bool is_pressed = gKeyboard->IsPressed(key.keycode); + bool is_pressed = keyboard->IsPressed(key.keycode); if (is_pressed) { // 押されている c = 10; @@ -289,9 +301,11 @@ WXSoftKeyPanel::Draw() SetTextBackColor(color.Keytop[key.coltype][c]); - // エンターキーだけ枠の描き方が違うので別処理 - if (__predict_false(key.x < 0)) { + // エンターキーとブザー表示は描き方が違うので別処理 + if (__predict_false(key.keycode == KC_enter)) { DrawEnterKey(); + } else if (__predict_false(key.keycode == KC_buzzer)) { + DrawBuzzer(key); } else { DrawKey(key); } @@ -367,7 +381,7 @@ WXSoftKeyPanel::DrawKey(const keydata_t& x = x * unit + 1; y = y * unit + 1; if (strcmp(disp, EnterMark) == 0) { - DrawEnterMark(x, y); + bitmap.DrawBitmap(x, y, *enter_icon, palette); } else { if (lf == NULL) { // 1行の場合 @@ -410,66 +424,140 @@ WXSoftKeyPanel::DrawEnterKey() enter_top.x, enter_top.GetBottom(), enter_top.y); // エンター記号を描画 - DrawEnterMark( + bitmap.DrawBitmap( (enter_top.x + enter_top.GetRight()) / 2 - (4 / 2), - (enter_top.y + enter_btm.GetBottom()) / 2 - (4 / 2)); + (enter_top.y + enter_btm.GetBottom()) / 2 - (4 / 2), + *enter_icon, palette); } -#define B(x) (0b##x >> 8), (0b##x & 0xff) +// ブザー表示(キーに相当)を描画 +void +WXSoftKeyPanel::DrawBuzzer(const keydata_t& key) +{ + Color fg; + + // 枠。キーではないので薄くしておく。 + Rect rect( + key.x * unit, key.y * unit, + key.w * unit + 1, key.h * unit + 1); + bitmap.FillRect(palette[0], rect); + bitmap.DrawRect(UD_GREY, rect); + + // テキスト色は本来呼び出し元の DrawKey() で設定してあるが、 + // ここはキーではないので非発声時の文字色だけ薄くしたい。 + // 発声時はキー押下と同じにする。 + fg = GetTextForeColor(); + if (persistence[key.keycode] == 0) { + SetTextForeColor(UD_GREY); + } -static constexpr uint8 EnterMark12[] = { - B(000000000000'0000), // 0 - B(000000001110'0000), // 1 - B(000000001010'0000), // 2 - B(000000001010'0000), // 3 - B(000000001010'0000), // 4 - B(001100001010'0000), // 5 - B(010111110010'0000), // 6 - B(100000000010'0000), // 7 - B(010111111100'0000), // 8 - B(001100000000'0000), // 9 - B(000000000000'0000), // a - B(000000000000'0000), // b + // 刻印 (モディファイヤの影響を受けないと分かっているので常に [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 constexpr uint8 EnterMark16[] = { - B(0000000000111110), // 0 - B(0000000000100010), // 1 - B(0000000000100010), // 2 - B(0000000000100010), // 3 - B(0000000000100010), // 4 - B(0000000000100010), // 5 - B(0000000000100010), // 6 - B(0000110000100010), // 7 - B(0001010000100010), // 8 - B(0010011111000010), // 9 - B(0100000000000010), // a - B(1000000000000010), // b - B(0100000000000010), // c - B(0010011111111100), // d - B(0001010000000000), // e - B(0000110000000000), // f + +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 }; -// 指定の位置にエンター記号を描画する (エンターキー全体の描画ではない)。 -// メインキーとテンキーの両方で同じ図柄を使う。 -// 大きさは (3unit, 4unit) なので実質全角1文字分くらい。 +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::DrawEnterMark(int px, int py) +WXSoftKeyPanel::InitIcon() { - const uint8 *mark; + const int width = font_width; + const int height = font_height; + const uint8 *icon; - switch (font_height) { + switch (height) { case 12: - mark = EnterMark12; + icon = EnterIcon12; break; case 16: - mark = EnterMark16; + icon = EnterIcon16; + break; + case 24: + icon = EnterIcon24; break; default: - PANIC("Unexpected font_height=%d", font_height); + PANIC("Unexpected font_height=%d", height); } - BitmapI1 src(mark, font_height, font_height); - bitmap.DrawBitmap(px, py, src, palette); + + enter_icon.reset(new BitmapI1(icon, width * 2, height)); } // keycode に対応する keydata を返す @@ -506,7 +594,7 @@ WXSoftKeyPanel::DoLeftDown(uint code) // トグルキーはここで完結。LeftUp では何もしない。 // second のクリアは KeyUp() からコールバックされる OnKeyChanged() // で行っている。 - if (gKeyboard->IsPressed(code)) { + if (keyboard->IsPressed(code)) { KeyUp(code); } else { KeyDown(code); @@ -575,7 +663,7 @@ WXSoftKeyPanel::OnRightDown(wxMouseEvent if (key != NULL) { uint code = key->keycode; - if (gKeyboard->IsPressed(code)) { + if (keyboard->IsPressed(code)) { // 押されていたら開放 KeyUp(code); } else { @@ -617,7 +705,7 @@ void WXSoftKeyPanel::KeyDown(uint code) { // VM に通知 (Keyboard がホストに通知する) - gKeyboard->MakeKey(code); + keyboard->MakeKey(code); } // このキーが放された処理 @@ -625,7 +713,7 @@ void WXSoftKeyPanel::KeyUp(uint code) { // VM に通知 (Keyboard がホストに通知する) - gKeyboard->BreakKey(code); + keyboard->BreakKey(code); } @@ -666,6 +754,7 @@ WXLunaSoftKeyPanel::WXLunaSoftKeyPanel(w InitColorKeytop(2); SetBitmapBGColor(color.Background); + Fill(); } // デストラクタ @@ -677,7 +766,7 @@ WXLunaSoftKeyPanel::~WXLunaSoftKeyPanel( int WXLunaSoftKeyPanel::DrawLED(const keydata_t& key) { - const std::vector& led = gKeyboard->GetLED(); + const std::vector& led = keyboard->GetLED(); Color fg; Color bg; @@ -724,6 +813,7 @@ WXLunaSoftKeyPanel::keydata { { 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" } }, + { 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", "!" } }, @@ -840,7 +930,8 @@ WXX68kSoftKeyPanel::WXX68kSoftKeyPanel(w : inherited(parent, keydata, 235, 54) { // X68k では SRAM 設定に同期させる。 - uint8 sw = gSRAM->Peek8(0xed0059); + const auto sram = GetSRAMDevice(); + uint8 sw = sram->Peek8(0xed0059); gFontManager->SetGlyph5C((sw & 0x01)); gFontManager->SetGlyph7E((sw & 0x02)); gFontManager->SetGlyph7C((sw & 0x04)); @@ -855,6 +946,7 @@ WXX68kSoftKeyPanel::WXX68kSoftKeyPanel(w InitColorKeytop(1); SetBitmapBGColor(color.Background); + Fill(); } // デストラクタ @@ -866,7 +958,7 @@ WXX68kSoftKeyPanel::~WXX68kSoftKeyPanel( int WXX68kSoftKeyPanel::DrawLED(const keydata_t& key) { - const std::vector& led = gKeyboard->GetLED(); + const std::vector& led = keyboard->GetLED(); Color fg; Color bg; @@ -1024,7 +1116,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, { "." } },