--- nono/wx/wxsoftkey.cpp 2026/04/29 17:05:44 1.1.1.15 +++ nono/wx/wxsoftkey.cpp 2026/04/29 17:05:48 1.1.1.16 @@ -319,17 +319,16 @@ WXSoftKeyPanel::Draw() } // 指定のキーを一つ (枠から刻印まで) 描画する。 +// palette[FG] はテキスト色 (キーボード非接続ならグレー)。 +// palette[BG] はこのキーの背景色 (押されているか、減光中か、 +// 押されていない時の二色あるかも知れないキートップ色)。 void WXSoftKeyPanel::DrawKey(const keydata_t& key) { uint attr = TA::Normal; // 枠 - Rect rect( - key.x * unit, key.y * unit, - key.w * unit + 1, key.h * unit + 1); - bitmap.FillRect(palette[0], rect); - bitmap.DrawRect(color.Text, rect); + DrawKeyBox(key, palette[0], color.Text); // 刻印を選択 const char *disp = key.disp[modifier]; @@ -368,18 +367,20 @@ WXSoftKeyPanel::DrawKey(const keydata_t& 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) { y += DrawLED(key); } + y = y * unit + 1; // 文字を描画 - x = x * unit + 1; - y = y * unit + 1; if (strcmp(disp, EnterMark) == 0) { bitmap.DrawBitmapI1(x, y, *enter_icon, palette); } else { @@ -395,6 +396,17 @@ WXSoftKeyPanel::DrawKey(const keydata_t& } } +// キーの枠と背景色を描画する。 +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() @@ -437,11 +449,7 @@ WXSoftKeyPanel::DrawBuzzer(const keydata 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); + DrawKeyBox(key, palette[0], UD_GREY); // テキスト色は本来呼び出し元の DrawKey() で設定してあるが、 // ここはキーではないので非発声時の文字色だけ薄くしたい。 @@ -716,14 +724,10 @@ WXSoftKeyPanel::KeyUp(uint code) keyboard->BreakKey(code); } - -// -// LUNA ソフトウェアキーボード (パネル) -// - -// コンストラクタ -WXLunaSoftKeyPanel::WXLunaSoftKeyPanel(wxWindow *parent) - : inherited(parent, keydata, 226, 54) +// LUNA-I、LUNA-88K のコンストラクタ共通部分。 +// クラス階層を増やすのも手間なので。 +void +WXSoftKeyPanel::InitLunaCommon() { // LUNA では // BS キーの左隣 (0x5c) は円記号ではなくバックスラッシュ。 @@ -757,14 +761,26 @@ WXLunaSoftKeyPanel::WXLunaSoftKeyPanel(w Fill(); } + +// +// LUNA-I ソフトウェアキーボード (パネル) +// + +// コンストラクタ +WXLuna1SoftKeyPanel::WXLuna1SoftKeyPanel(wxWindow *parent) + : inherited(parent, keydata, 226, 54) +{ + InitLunaCommon(); +} + // デストラクタ -WXLunaSoftKeyPanel::~WXLunaSoftKeyPanel() +WXLuna1SoftKeyPanel::~WXLuna1SoftKeyPanel() { } // LED を描画して刻印描画のための y offset を返す。 int -WXLunaSoftKeyPanel::DrawLED(const keydata_t& key) +WXLuna1SoftKeyPanel::DrawLED(const keydata_t& key) { const std::vector& led = keyboard->GetLED(); Color fg; @@ -790,30 +806,46 @@ WXLunaSoftKeyPanel::DrawLED(const keydat 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" } }, - { 210, L0+1, 14, H-2, 1,-1, KC_buzzer, { "Buzzer" } }, + { 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", "!" } }, @@ -922,6 +954,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 ソフトウェアキーボード (パネル) // @@ -993,24 +1233,23 @@ WXX68kSoftKeyPanel::DrawLED(const keydat 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", "!" } }, @@ -1126,6 +1365,7 @@ WXX68kSoftKeyPanel::keydata { { -1, -1, -1, -1, 0,-1, KC_enter, { EnterMark } }, }; + // // ソフトウェアキーボード (ウィンドウ) // @@ -1134,10 +1374,18 @@ WXX68kSoftKeyPanel::keydata { WXSoftKeyWindow::WXSoftKeyWindow(wxWindow *parent, VMType vmtype) : inherited(parent, wxID_ANY, _("Software Keyboard")) { - if (vmtype == VMType::X68030) { + switch (vmtype) { + case VMType::X68030: new WXX68kSoftKeyPanel(this); - } else { - new WXLunaSoftKeyPanel(this); + break; + case VMType::LUNA1: + new WXLuna1SoftKeyPanel(this); + break; + case VMType::LUNA88K: + new WXLuna88kSoftKeyPanel(this); + break; + default: + assert(false); } Fit();