--- nono/wx/wxsoftkey.cpp 2026/04/29 17:04:39 1.1.1.5 +++ nono/wx/wxsoftkey.cpp 2026/04/29 17:04:56 1.1.1.7 @@ -6,6 +6,7 @@ #include "wxsoftkey.h" #include "wxcolor.h" +#include "wxmainview.h" #include "wxtextscreen.h" #include "sram.h" @@ -27,24 +28,40 @@ wxBEGIN_EVENT_TABLE(WXSoftKeyPanel, inhe EVT_LEFT_DCLICK(WXSoftKeyPanel::OnLeftDClick) EVT_RIGHT_DOWN(WXSoftKeyPanel::OnRightDown) EVT_PAINT(WXSoftKeyPanel::OnPaint) - EVT_SIZE(WXSoftKeyPanel::OnSize) + EVT_TIMER(wxID_ANY, WXSoftKeyPanel::OnTimer) wxEND_EVENT_TABLE() // コンストラクタ WXSoftKeyPanel::WXSoftKeyPanel(wxWindow *parent, - int u_width_, int u_height_) + const std::vector& keydata_, int u_width_, int u_height_) : inherited(parent) + , keydata(keydata_) { 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; + + DoSize(); + + // このパネルへのキー入力はメインビューへのキー入力と同じ。 + Connect(wxEVT_KEY_UP, wxKeyEventHandler(WXMainView::OnKeyUp), NULL, + gMainView); + Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(WXMainView::OnKeyDown), NULL, + gMainView); + + // 更新間隔は適当 + timer.SetOwner(this); + timer.Start(100); } // デストラクタ WXSoftKeyPanel::~WXSoftKeyPanel() { - bitmap.reset(); - image.reset(); - bmpbuf.reset(); } // フォントサイズ変更 (外部インタフェース) @@ -77,30 +94,33 @@ WXSoftKeyPanel::DoSize() // エンターキーだけ矩形でないのでここでリージョンを計算。 // unit が確定したところで一回行う。 + // ただし SHIFT_R のキーコードはちょっと使いづらいので、ここでは SHIFT_R + // を使わず [_] キーで代用する。 + // + // | ^ | \ | BS | + // | | | | + // --+---+---+--(A)--+------(B) + // | | | + // | [ | | + // | | Enter | + // --+---+---+--(F)-(E) | + // | | | | + // | : | ] | | + // | | | | + // --+---+---+------(D)-----(C) + // | | + // _ | SHIFT | // - // | ^ | \ | BS | - // | | | | - // +---+---+--(A)--+------(B) - // | | | - // | [ | | - // | | Enter | - // +---+---+--(F)-(E) | - // | | | | - // | : | ] | | - // | | | | - // +---+---+------(D)-----(C) - // | | - // | SHIFT | const keydata_t& keybs = FindKeydata(KC_BS); const keydata_t& keyleft = FindKeydata(KC_bracketleft); const keydata_t& keyright = FindKeydata(KC_bracketright); - const keydata_t& keyshift = FindKeydata(KC_SHIFT_R); + const keydata_t& keyscore = FindKeydata(KC_underscore); // 各点のピクセル座標 enter_points = { { keyleft.right() * unit, keyleft.y * unit }, // A { keybs.right() * unit, keyleft.y * unit }, // B - { keyshift.right() * unit, keyshift.y * unit }, // C - { keyright.right() * unit, keyshift.y * unit }, // D + { 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 }; @@ -110,51 +130,40 @@ WXSoftKeyPanel::DoSize() // コントロールの大きさを変更 wxSize size(u_width * unit, u_height * unit); SetClientSize(size); - SetMinSize(size); -} - -// サイズ変更イベント -void -WXSoftKeyPanel::OnSize(wxSizeEvent& event) -{ - // Mac ではウィンドウ作成時に 0 以下の値が来ることがある - // GTK では 1 で来ることがある - const wxSize& size = event.GetSize(); - if (size.x <= 1 || size.y <= 1) { - return; - } - - view_width = size.x; - view_height = size.y; - - // ビットマップを持っていれば一旦解放 - bitmap.reset(); - image.reset(); - bmpbuf.reset(); + SetMinClientSize(size); // ビットマップ作成 - // 正しく描かれなかった時に分かりやすいよう初期値は濃いグレーにしておく - bmpbuf.reset(new uint8 [view_width * view_height * 3]); - memset(&bmpbuf[0], 0x70, view_width * view_height * 3); - image.reset(new wxImage(view_width, view_height, bmpbuf.get(), true)); - bitmap.reset(new wxBitmap(*image)); + bitmap.Create(size.x, size.y); // 再描画を指示 Refresh(); } +// タイマーイベント +void +WXSoftKeyPanel::OnTimer(wxTimerEvent& event) +{ + // 更新があれば再描画を指示 + const std::vector& pressed = gKeyboard->GetPressed(); + UpdateModifier(); + if (pressed != last_pressed || modifier != last_modifier) { + Refresh(); + } +} + // 描画イベント (UI スレッドから呼ばれる) void WXSoftKeyPanel::OnPaint(wxPaintEvent& event) { // メモリ DC に描画 wxMemoryDC memDC; - memDC.SelectObject(*bitmap); + memDC.SelectObject(bitmap); Draw(memDC); // 実画面 DC にコピー wxPaintDC dstDC(this); - dstDC.Blit(0, 0, view_width, view_height, &memDC, 0, 0); + wxSize size = bitmap.GetSize(); + dstDC.Blit(0, 0, size.x, size.y, &memDC, 0, 0); } // 描画本体 @@ -167,8 +176,9 @@ WXSoftKeyPanel::Draw(wxDC& dc) dc.SetPen(color.Text); SetTextForeColor(color.Text); - for (const auto& key : GetKeydata()) { - if (hit[key.keycode]) { + for (const auto& key : keydata) { + bool is_pressed = gKeyboard->IsPressed(key.keycode); + if (is_pressed) { // 押されている SetTextBackColor(color.KeyPressed); dc.SetBrush(color.KeyPressed); @@ -184,8 +194,14 @@ WXSoftKeyPanel::Draw(wxDC& dc) } else { DrawKey(dc, key); } + + // 次回更新チェック用に現状を保存 + last_pressed[key.keycode] = is_pressed; } + // 次回更新チェック用に現状を保存 + last_modifier = modifier; + #if 0 // X68k キーボードだとどこに表示するか SetTextBackColor(color.Background); @@ -315,7 +331,7 @@ WXSoftKeyPanel::DrawEnterMark(wxDC& dc, const keydata_t& WXSoftKeyPanel::FindKeydata(uint keycode) const { - for (const auto& key : GetKeydata()) { + for (const auto& key : keydata) { if (key.keycode == keycode) { return key; } @@ -339,15 +355,10 @@ void WXSoftKeyPanel::DoLeftDown(const keydata_t *key) { if (key != NULL) { - uint code = key->keycode; - if (hit[code]) { - // 押下(長押し)中のキーならここで開放 - KeyUp(*key); - } else { - // 押下して、LeftUp のために覚えておく - KeyDown(*key); - leftdown_key = key; - } + // 押下 + KeyDown(*key); + // LeftUp のために覚えておく + leftdown_key = key; } } @@ -367,11 +378,8 @@ void WXSoftKeyPanel::DoLeftUp(const keydata_t *key) { if (key != NULL) { - // 押されていたら開放 - uint code = key->keycode; - if (hit[code]) { - KeyUp(*key); - } + // 開放 + KeyUp(*key); } leftdown_key = NULL; } @@ -406,7 +414,7 @@ WXSoftKeyPanel::OnRightDown(wxMouseEvent if (key != NULL) { uint code = key->keycode; - if (hit[code]) { + if (gKeyboard->IsPressed(code)) { // 押されていたら開放 KeyUp(*key); } else { @@ -426,7 +434,7 @@ WXSoftKeyPanel::GetKeydataFromPoint(cons return &FindKeydata(KC_enter); } - for (const auto& key : GetKeydata()) { + for (const auto& key : keydata) { if (key.x < 0) { continue; } @@ -443,13 +451,75 @@ 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) +{ + uint code = key.keycode; + + // VM に通知 (Keyboard がそれをホストに通知するかはまた別) + gKeyboard->MakeKey(code); + + // 修飾キー + if (IsModifier(code)) { + UpdateModifier(); + } + + // キー状態が変わった(かも知れない)ので再描画 + // 押した時にはタイマーを待たずに再描画したほうがよかろう + Refresh(); +} + +// このキーが放された処理 +void +WXSoftKeyPanel::KeyUp(const keydata_t& key) +{ + uint code = key.keycode; + + // VM に通知 (Keyboard がそれをホストに通知するかはまた別) + gKeyboard->BreakKey(code); + + // 修飾キー + if (IsModifier(code)) { + UpdateModifier(); + } + + // キー状態が変わった(かも知れない)が、 + // 解放時はタイマーに任せた再描画でよかろう + //Refresh(); +} + + // // LUNA ソフトウェアキーボード (パネル) // // コンストラクタ WXLunaSoftKeyPanel::WXLunaSoftKeyPanel(wxWindow *parent) - : inherited(parent, 226, 54) + : inherited(parent, keydata, 226, 54) { // LUNA では // BS キーの左隣 (0x5c) は円記号ではなくバックスラッシュ。 @@ -483,8 +553,6 @@ WXLunaSoftKeyPanel::WXLunaSoftKeyPanel(w .LED = { UD_RED }, }; } - - DoSize(); } // デストラクタ @@ -504,7 +572,8 @@ WXLunaSoftKeyPanel::DrawLED(wxDC& dc, co dc.SetBrush(color.LED[0]); } else { // 消灯時は元のキートップの色で、枠は薄めにしたい - dc.SetPen(GetTextDisableColor()); + // (枠の色は今の所全モデル共通なので ColorPalette に含めていない) + dc.SetPen(UD_GREY); dc.SetBrush(color.Keytop[key.coltype]); } @@ -517,48 +586,6 @@ WXLunaSoftKeyPanel::DrawLED(wxDC& dc, co return +1; } -// このキーが押された処理 -void -WXLunaSoftKeyPanel::KeyDown(const keydata_t& key) -{ - uint code = key.keycode; - - // 押された - hit[code] = true; - - // VM に通知 (Keyboard がそれをホストに通知するかはまた別) - gKeyboard->MakeKey(code); - - // 修飾キー - if (code == KC_SHIFT_L || code == KC_SHIFT_R) { - modifier = ModShift; - } - - // キー状態が変わった(かも知れない)ので再描画 - Refresh(); -} - -// このキーが放された処理 -void -WXLunaSoftKeyPanel::KeyUp(const keydata_t& key) -{ - uint code = key.keycode; - - // 放された - hit[code] = false; - - // VM に通知 (Keyboard がそれをホストに通知するかはまた別) - gKeyboard->BreakKey(code); - - // 修飾キー - if (code == KC_SHIFT_L || code == KC_SHIFT_R) { - modifier = ModNormal; - } - - // キー状態が変わった(かも知れない)ので再描画 - Refresh(); -} - // キーデータ #define H (8) // キーの高さ #define L0 (2) // ファンクションキーの行 @@ -695,7 +722,7 @@ WXLunaSoftKeyPanel::keydata { // コンストラクタ WXX68kSoftKeyPanel::WXX68kSoftKeyPanel(wxWindow *parent) - : inherited(parent, 235, 54) + : inherited(parent, keydata, 235, 54) { // X68k では SRAM 設定に同期させる。 uint8 sw = gSRAM->Peek8(0xed0059); @@ -712,8 +739,6 @@ WXX68kSoftKeyPanel::WXX68kSoftKeyPanel(w .Border = *wxBLACK, .LED = { UD_RED, UD_YELLOW_GREEN }, }; - - DoSize(); } // デストラクタ @@ -743,7 +768,8 @@ WXX68kSoftKeyPanel::DrawLED(wxDC& dc, co dc.SetBrush(color.LED[n]); } else { // 消灯時は元のキートップの色で、枠は薄めにしたい - dc.SetPen(GetTextDisableColor()); + // (枠の色は今の所全モデル共通なので ColorPalette に含めていない) + dc.SetPen(UD_GREY); dc.SetBrush(color.Keytop[key.coltype]); } @@ -756,54 +782,13 @@ WXX68kSoftKeyPanel::DrawLED(wxDC& dc, co return -1; } -// このキーが押された処理 -void -WXX68kSoftKeyPanel::KeyDown(const keydata_t& key) -{ - uint code = key.keycode; - - // 押された - hit[code] = true; - - // VM に通知 (Keyboard がそれをホストに通知するかはまた別) - gKeyboard->MakeKey(code); - - // 修飾キー - if (code == KC_SHIFT_L || code == KC_SHIFT_R) { - modifier = ModShift; - } - - // キー状態が変わった(かも知れない)ので再描画 - Refresh(); -} - -// このキーが放された処理 -void -WXX68kSoftKeyPanel::KeyUp(const keydata_t& key) -{ - uint code = key.keycode; - - hit[code] = false; - - // VM に通知 (Keyboard がそれをホストに通知するかはまた別) - gKeyboard->BreakKey(code); - - // 修飾キー - if (code == KC_SHIFT_L || code == KC_SHIFT_R) { - modifier = ModNormal; - } - - // キー状態が変わった(かも知れない)ので再描画 - Refresh(); -} - #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, { "BRK" } }, + { 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" } }, @@ -860,7 +845,7 @@ WXX68kSoftKeyPanel::keydata { { 121, L3, 10, H, 0,-1, KC_colon, { ":", "*" } }, { 131, L3, 10, H, 0,-1, KC_bracketright, { "]", "}" } }, - { 2, L4, 24, H, 0,-1, KC_SHIFT_L, { "SHIFT" } }, + { 2, L4, 24, H, 0,-1, KC_SHIFT, { "SHIFT" } }, { 26, L4, 10, H, 0,-1, KC_Z, { "z", "Z" } }, { 36, L4, 10, H, 0,-1, KC_X, { "x", "X" } }, { 46, L4, 10, H, 0,-1, KC_C, { "c", "C" } }, @@ -872,7 +857,7 @@ WXX68kSoftKeyPanel::keydata { { 106, L4, 10, H, 0,-1, KC_period, { ".", ">" } }, { 116, L4, 10, H, 0,-1, KC_slash, { "/", "?" } }, { 126, L4, 10, H, 0,-1, KC_underscore, { " ", "_" } }, - { 136, L4, 19, H, 0,-1, KC_SHIFT_R, { "SHIFT" } }, + { 136, L4, 19, H, 0,-1, KC_SHIFT, { "SHIFT" } }, { 21, L5, 10, H, 0, 5, KC_hira, { "ひら" } }, { 31, L5, 12, H, 0,-1, KC_XF1, { "XF1" } }, @@ -920,7 +905,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, { "ENT" } }, + { 223, L4, 10, HT,0,-1, KC_PAD_enter, { "\xb\xc\xd\xe" } }, { 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, { "." } }, @@ -931,41 +916,29 @@ WXX68kSoftKeyPanel::keydata { }; // -// LUNA ソフトウェアキーボード (ウィンドウ) +// ソフトウェアキーボード (ウィンドウ) // // コンストラクタ -WXLunaSoftKeyWindow::WXLunaSoftKeyWindow(wxWindow *parent, wxWindowID id) - : inherited(parent, id, _("Software Keyboard")) +WXSoftKeyWindow::WXSoftKeyWindow(wxWindow *parent, vmtype_t vmtype) + : inherited(parent, wxID_ANY, _("Software Keyboard")) { - panel = new WXLunaSoftKeyPanel(this); + wxBoxSizer *topsizer = new wxBoxSizer(wxVERTICAL); - // 大きさをそれに固定 - Layout(); - Fit(); -} - -// デストラクタ -WXLunaSoftKeyWindow::~WXLunaSoftKeyWindow() -{ -} - -// -// X680x0 ソフトウェアキーボード (ウィンドウ) -// + if (vmtype == VMTYPE_X68030) { + panel = new WXX68kSoftKeyPanel(this); + } else { + panel = new WXLunaSoftKeyPanel(this); + } -// コンストラクタ -WXX68kSoftKeyWindow::WXX68kSoftKeyWindow(wxWindow *parent, wxWindowID id) - : inherited(parent, id, _("Software Keyboard")) -{ - panel = new WXX68kSoftKeyPanel(this); + topsizer->Add(panel, 0, wxEXPAND); + SetSizer(topsizer); // 大きさをそれに固定 - Layout(); Fit(); } // デストラクタ -WXX68kSoftKeyWindow::~WXX68kSoftKeyWindow() +WXSoftKeyWindow::~WXSoftKeyWindow() { }