--- nono/wx/wxmainview.cpp 2026/04/29 17:04:30 1.1.1.2 +++ nono/wx/wxmainview.cpp 2026/04/29 17:05:27 1.1.1.15 @@ -1,18 +1,20 @@ // // nono -// Copyright (C) 2018 isaki@NetBSD.org +// Copyright (C) 2020 nono project +// Licensed under nono-license.txt // -#include "wxheader.h" +// +// メイン画面パネル +// + +#include "wxmainview.h" +#include "wxuimessage.h" +#include "config.h" +#include "event.h" #include "keyboard.h" #include "renderer.h" -#include "scheduler.h" -#include "wxmainview.h" -#include #include -#if defined(__NetBSD__) -#include // __NetBSD_Version__ -#endif //#define KEYDEBUG 1 //#define MOUSEDEBUG 1 @@ -39,63 +41,92 @@ // Refresh{,Rect}() を呼ばず、再描画矩形を画面全体として運用する。 // ちょっと無駄なだけなので (動かないことに比べれば) 気にしない。 // -// 今のところ NetBSD 5.0 以上(と Linux (CentOS 6.3/x86_64)) が該当する。 -#if defined(__NetBSD__) && __NetBSD_Version__ >= 500000000 +// 今のところ NetBSD (5.0 以降) と OpenBSD(/amd64)(-6.7) +// (と Linux (CentOS 6.3/x86_64)) が該当する。 +#if defined(__NetBSD__) || defined(__OpenBSD__) #define DONT_USE_REFRESH 1 #endif -#define TIMERID_PAINTTIMER 1 - -static void wxmainview_refresh(); - -WXMainView *gMainView; +wxDEFINE_EVENT(NONO_EVT_MOUSEMODE, wxCommandEvent); wxBEGIN_EVENT_TABLE(WXMainView, inherited) EVT_PAINT(WXMainView::OnPaint) EVT_KEY_DOWN(WXMainView::OnKeyDown) EVT_KEY_UP(WXMainView::OnKeyUp) + EVT_CHAR(WXMainView::OnChar) EVT_MOUSE_EVENTS(WXMainView::OnMouse) - EVT_TIMER(TIMERID_PAINTTIMER, WXMainView::OnTimer) + EVT_MOUSE_CAPTURE_LOST(WXMainView::OnMouseCaptureLost) wxEND_EVENT_TABLE() WXMainView::WXMainView(wxWindow *parent) : inherited(parent) { - // 仮想画面(VM が描画する画面) - rendwidth = gRenderer->GetWidth(); - rendheight = gRenderer->GetHeight(); - - // レンダラバッファは常に仮想画面サイズ - int buflen = rendwidth * rendheight * 3; - ImageBuf = new uint8_t[buflen]; - memset(ImageBuf, 0x70, buflen); - // レンダラに通知 - gRenderer->SetBuf(ImageBuf, wxmainview_refresh); + // デバイスを取得。Keyboard は NULL の可能性あり。 + keyboard = gMainApp.FindObject(OBJ_KEYBOARD); + renderer = GetRenderer(); + + // マウスモード変更イベント + Connect(NONO_EVT_MOUSEMODE, + wxCommandEventHandler(WXMainView::OnMouseMode), NULL, this); + + // VM からの通知を受け取る + WXUIMessage::Connect(UIMessage::RENDER, this, + wxCommandEventHandler(WXMainView::OnRender)); // 実画面 (ウィンドウの大きさ) DoResize(screen_scale); - paintTimer.SetOwner(this, TIMERID_PAINTTIMER); - paintTimer.Start(16); - paintRequested = true; // first paint request + // 更新間隔 + renderer->SetRefreshInterval(33_msec); + + // 最初に一度描画 + Refresh(); } WXMainView::~WXMainView() { - delete[] ImageBuf; + // マウスをリリースしないと Assert される + if (HasCapture()) { + ReleaseMouse(); + } + WXUIMessage::Disconnect(UIMessage::RENDER, this, + wxCommandEventHandler(WXMainView::OnRender)); +} + +// (設定反映などの) 初期化 +bool +WXMainView::Init() +{ + if (keyboard) { + // キーボードの入力モードの初期値設定 + const ConfigItem& item_input = gConfig->Find("hostkbd-input"); + const std::string input_mode = item_input.AsString(); + if (input_mode == "char") { + SetCharInputMode(true); + } else if (input_mode == "jp") { + // 今は二択しかないのでちょっと噛み合ってないが + SetCharInputMode(false); + } else { + item_input.Err(); + return false; + } + } + + return true; } -// リフレッシュ要求コールバック。 -// VM から呼ばれるので一旦グローバル関数を経由する。 +// 終了用に描画を停止する void -wxmainview_refresh(void) +WXMainView::Close() { - gMainView->DoRefresh(); + // これで OnPaint() が何もせず帰るようになる。 + viewwidth = 0; + viewheight = 0; } -// リフレッシュ要求コールバック。こっちが実体。 +// リフレッシュ要求イベント void -WXMainView::DoRefresh() +WXMainView::OnRender(wxCommandEvent& event) { #if defined(DONT_USE_REFRESH) // Refresh{,Rect}() が使えないので、再描画範囲は常に全体とする @@ -104,62 +135,30 @@ WXMainView::DoRefresh() // XXX のはずだが、今の所全体 RefreshRect(wxRect(0, 0, viewwidth, viewheight), false); #endif - - // PAINT イベントを投げる - // XXX んだけど mac だと投げすぎるとシステムイベントを拾えなくなってしまう - paintRequested = true; -} - -void -WXMainView::OnTimer(wxTimerEvent& event) -{ - bool req = paintRequested.exchange(false); - if (req) { - // PAINT イベントを投げる - wxPaintEvent *ev = new wxPaintEvent(); - QueueEvent(ev); - } + // 実際に再描画する + Refresh(); + // TODO: ビデオモニタにも通知する } // 描画イベント void WXMainView::OnPaint(wxPaintEvent& event) { - wxClientDC dc(this); - - DoPaint(dc); -} + if (__predict_false(viewwidth == 0 || viewheight == 0)) { + return; + } -// 描画実行 -void -WXMainView::DoPaint(wxDC& dc) -{ - if (viewwidth == 0 || viewheight == 0) + BitmapRGB *bitmap24 = renderer->GetBitmap(); + if (__predict_false(bitmap24 == NULL)) { return; + } - wxImage image(rendwidth, rendheight, ImageBuf, true); + wxImage image(viewwidth, viewheight, bitmap24->GetBuf(), true); + wxBitmap bmp(image); - if (viewwidth != rendwidth || viewheight != rendheight) { - // wxIMAGE_QUALITY_NORMAL だと速いが、品質優先。 - image.Rescale(viewwidth, viewheight, wxIMAGE_QUALITY_HIGH); - } - - wxBitmap bitmap(image); - wxMemoryDC memDC; - memDC.SelectObject(bitmap); - - wxRegion region(0, 0, viewwidth, viewheight); - wxRegionIterator ri(region); - for (; ri; ri++) { - int dx, dy, dw, dh; - dx = ri.GetX(); - dy = ri.GetY(); - dw = ri.GetWidth(); - dh = ri.GetHeight(); - int sx = dx; - int sy = dy; - dc.Blit(dx, dy, dw, dh, &memDC, sx, sy, wxCOPY); - } + // 実画面 DC にコピー + wxPaintDC dstDC(this); + dstDC.DrawBitmap(bmp, 0, 0); } // リサイズ (UI スレッドから呼ぶこと) @@ -167,14 +166,18 @@ void WXMainView::DoResize(double scale) { screen_scale = scale; - int width = (double)rendwidth * scale; - int height = (double)rendheight * scale; + int width = (double)renderer->GetWidth() * scale; + int height = (double)renderer->GetHeight() * scale; if (viewwidth != width || viewheight != height) { - // ウィンドウサイズ変更 viewwidth = width; viewheight = height; + + // レンダラにリサイズ指示。 + renderer->ResizeView(viewwidth, viewheight); + + // ウィンドウサイズ変更 SetClientSize(viewwidth, viewheight); - SetMinSize(wxSize(viewwidth, viewheight)); + SetMinClientSize(wxSize(viewwidth, viewheight)); } } @@ -194,6 +197,13 @@ WXMainView::GetScale() const // マウス入力 // +// マウスモード変更要求イベント +void +WXMainView::OnMouseMode(wxCommandEvent& event) +{ + SetMouseMode(event.GetInt()); +} + // マウスモード設定 void WXMainView::SetMouseMode(bool mode) @@ -208,6 +218,10 @@ WXMainView::SetMouseMode(bool mode) // マウスカーソル OFF ::wxSetCursor(wxCursor(wxCURSOR_BLANK)); + if (!HasCapture()) { + CaptureMouse(); + } + // このウィンドウから外れないように移動を検出し続けるため、 // マウスカーソルをウィンドウ中央に移す。 // ウィンドウとメニューバーが分離してる wxOSX のために必要。 @@ -216,8 +230,13 @@ WXMainView::SetMouseMode(bool mode) // マウスモードを OFF にする DMPRINTF("SetMouseMode OFF\n"); + if (HasCapture()) { + ReleaseMouse(); + } + // 分かりやすさのため、マウスカーソルを中央へ戻してから復帰 - MyWarpPointer(GetClientSize() / 2); + wxSize pt = GetClientSize() / 2; + WarpPointer(pt.x, pt.y); // マウスカーソル ON ::wxSetCursor(wxNullCursor); @@ -246,28 +265,49 @@ WXMainView::OnMouse(wxMouseEvent& event) if (mousemode) { bool leaving = event.Leaving(); bool moving = event.Moving(); + bool dragging = event.Dragging(); // LeftDown() 等は押された時、LeftIsDown() 等は押されてる間 true。 bool rb = event.RightIsDown(); bool lb = event.LeftIsDown(); bool mb = event.MiddleIsDown(); - wxPoint pos = event.GetPosition(); + const wxPoint& pos = event.GetPosition(); int dx = 0; int dy = 0; - DMPRINTF( - "OnMouse Button=%d %c%c%c Leave=%d (motion=%d) Moving=%d(%d,%d)\n", - event.IsButton(), - (lb ? 'L' : '-'), - (mb ? 'M' : '-'), - (rb ? 'R' : '-'), - leaving, motion_by_warp_pointer, moving, pos.x, pos.y); +#if defined(MOUSEDEBUG) + std::string dstr = "OnMouse"; + if (moving || dragging || motion_by_warp_pointer) { + dstr += string_format(" (%d,%d)", pos.x, pos.y); + } + if (moving) + dstr += " Moving"; + if (dragging) + dstr += " Dragging"; + if (motion_by_warp_pointer) + dstr += " MotionByWarp"; + if (lb || mb || rb) { + dstr += string_format(" Button(%c%c%c)", + (lb ? 'L' : '-'), + (mb ? 'M' : '-'), + (rb ? 'R' : '-')); + } + if (leaving) + dstr += " Leaving"; + printf("%s\n", dstr.c_str()); +#endif if (leaving) { - // タスクスイッチした時とかのための自動リリース - SetMouseMode(false); + // タスクスイッチした時とかのための自動リリース。 + // メインウィンドウの上にサブウィンドウが乗っているときも + // leaving が発生するので、メインウィンドウの外に出た場合のみ + // リリースする。 + auto sz = GetSize(); + if (pos.x < 0 || pos.x > sz.x || pos.y < 0 || pos.y > sz.y) { + SetMouseMode(false); + } } - if (moving) { + if (moving || dragging) { // (My)WarpPointer() で自発的にマウスカーソルを移動させたことで // 来る EVT_MOTION は無視する。 if (motion_by_warp_pointer) { @@ -288,79 +328,225 @@ WXMainView::OnMouse(wxMouseEvent& event) } // VM に入力 - if (dx != 0 || dy != 0 || lb || mb || rb) { + if (dx != 0 || + dy != 0 || + lb != prevlb || + mb != prevmb || + rb != prevrb ) + { DMPRINTF(" Input dx=%d dy=%d %c%c%c\n", dx, dy, (lb ? 'L' : '-'), (mb ? 'M' : '-'), (rb ? 'R' : '-')); - gKeyboard->MouseInput(dx, dy, rb, lb, mb); + if (keyboard) { + keyboard->MouseInput(dx, dy, rb, lb, mb); + } } + + prevlb = lb; + prevmb = mb; + prevrb = rb; } // EVT_LEFT_DOWN をデフォルト処理するため event.Skip(); } +// マウスキャプチャロスト +void +WXMainView::OnMouseCaptureLost(wxMouseCaptureLostEvent& event) +{ + // 外部要因でマウスキャプチャをロストしたので、マウスモードを抜ける。 + SetMouseMode(false); +} + +// アクティベートイベント。 +// この(トップレベル)ウィンドウにフォーカスが当たるか外れるかで飛んでくる。 +// 実際には WXMainFrame 宛てに飛んできたイベントをこちらに転送してある。 +// マウスモード中にこのウィンドウからフォーカスが外れたら (例えば ALT+TAB の +// ようなウィンドウを切り替える操作)、マウスモードを解除するため。 +void +WXMainView::OnActivate(wxActivateEvent& event) +{ + // フォーカスが外れる際にマウスモード中ならマウスモードを解除 + if (event.GetActive() == false) { + DMPRINTF("OnActivate FocusOut\n"); + if (mousemode) { + SetMouseMode(false); + } + } else { + DMPRINTF("OnActivate FocusIn\n"); + } +} + + // // キー入力 // // wxKeyEvent でキーコードを得るためのメソッドは // GetKeyCode()、GetRawKeyCode()、GetRawKeyFlags() の3つが用意されていて -// wxWigets の port (wxGTK、wxOSX とか) によってそれぞれ内容の定義が違う。 +// wxWidgets の port (wxGTK、wxOSX とか) によってそれぞれ内容の定義が違う。 // // wxGTK の場合 +// GetKeyCode() が論理キーコードなのでこれをメインに使う。ただし左右 [SHIFT] +// のように論理キーコードだけでは区別の付かないものについては物理キー番号で +// ある GetRawKeyFlags() を併用する。 +// +// 以下詳細。 // GetKeyCode() は wxWidgets の WXK_* (/usr/pkg/include/wx-3.0/wx/defs.h)。 -// これは左右の SHIFT が区別できないが、 -// それ以外はだいたい使えそうではある。 +// これは概ね論理キーコードであり、xorg.conf の swapcaps 設定や Xmodmap の +// 影響をうける。 +// o 基本的に [SHIFT] キーの影響を受けないが、一部例外がある。 +// - [^] (0x5e) と [SHIFT]+[^] (0x30) +// - [,] (0x2c) と [SHIFT]+[,] (0x3c) +// o [\] と [_] は同じ 0x5c になる ([SHIFT] 押しながらでも同様)。 +// o [SHIFT], [CTRL], [ALT] の各左右キーは同じコードになる。 +// +// GetRawKeyFlags() は物理キー番号ようだ。GDK の hardware keycode らしいが、 +// それ以上の詳細は不明。 +// o 環境 (OS か X かライブラリ?) によって異なるようだ。 +// 少なくとも NetBSD9 と Ubuntu20.04 では一部の値が異なる。 +// o [SHIFT] キーの影響を受けない。 +// GetKeyCode() では影響を受けた例外キーもここでは影響を受けない。 +// o [SHIFT], [CTRL], [ALT] の各左右キーは違うコードになる。 // // GetRawKeyCode() は GDK の keycode っぽい? // (/usr/pkg/include/gtk-2.0/gdk/gdkkeysyms.h)。 // X11 の keysym から来てる? (/usr/X11R7/include/X11/keysymdef.h)。 -// ただし [A] と [SHIFT]+[A] が違うコードを返すというか、文字コードで -// 表現出来る時は文字コード、みたいな感じになっているので、ここでは -// 使いづらい。 +// ただし [A] と [SHIFT]+[A] が違うコードを返すというか、文字コードで表現 +// 出来る時は文字コード、みたいな感じになっているのでここでは使いづらい。 // 左右の SHIFT は区別可能。 -// [^] と [SHIFT]+[^] もそもそも文字コードになるので '^' と '~' になる。 -// -// GetRawKeyFlags() は GDK の hardware keycode らしいけど、それが何か不明。 -// 左右の SHIFT は違うコードを返す。 -// SHIFT を押しながらでもコードは変わらないっぽい。 -// [^] と [SHIFT]+[^] は同じコードを返す。 // // wxOSX の場合 // GetKeyCode() -// これは左右の SHIFT が区別できないが、 -// それ以外はだいたい使えそうではある。 +// 英字キー [A] と [SHIFT]+[A] は同じコードになるが、 +// 記号キー [1] と [SHIFT]+[1] は別になる体系のようだ。 +// 左右の [SHIFT] は区別できない。 // // GetRawKeyCode() -// [A] と [SHIFT]+[A] などは同じコードを返す。 -// 左右の SHIFT は区別可能。 +// これがたぶん物理キー番号。 +// [1] と [SHIFT]+[1] は同じコードを返す。 +// 左右の [SHIFT] は区別可能。 // // GetRawKeyFlags() は状態フラグか何かのようだ。 // +// 入力モード変更 +void +WXMainView::SetCharInputMode(bool enable) +{ + is_charinput = enable; +} + // キーを押した void WXMainView::OnKeyDown(wxKeyEvent& event) { - DKPRINTF("KeyDown "); - int keycode = GetKeyCode(event); - gKeyboard->MakeKey(keycode); - // メニューのアクセラレータのために必要 event.Skip(); + + if (is_charinput) { + return; + } + + DKPRINTF("KeyDown "); + int keycode = GetKeyCode(event); + if (keyboard) { + keyboard->MakeKey(keycode); + } } // キーを離した void WXMainView::OnKeyUp(wxKeyEvent& event) { + if (is_charinput) { + return; + } + DKPRINTF("KeyUp "); int keycode = GetKeyCode(event); - gKeyboard->BreakKey(keycode); + if (keyboard) { + keyboard->BreakKey(keycode); + } +} + +// 文字による入力モード +void +WXMainView::OnChar(wxKeyEvent& event) +{ + // メニューのアクセラレータのために必要 + event.Skip(); + + if (!is_charinput) { + return; + } + + uint ukey = event.GetUnicodeKey(); + uint ukey_orig = ukey; + DKPRINTF("Char uni=0x%02x", ukey); + if (0x20 <= ukey && ukey < 0x7f) { + DKPRINTF(" '%c'", ukey); + } + + bool ctrl = event.ControlDown(); + if (ctrl) { + DKPRINTF(" CTRL"); + + // Ctrl + A .. Ctrl + Z までは 0x01(^A) .. 0x1a(^Z) の文字が来るが、 + // Ctrl + 記号は記号の文字コードだけが送られてくるようだ。 + // Ctrl + [ は 0x1b('^[') ではなく 0x5b('[') のような感じ。 + // そこでこの場合は Ctrl キーが押されているかどうかを別途判定する。 + if (0x40 <= ukey && ukey <= 0x5f) { + ukey -= 0x40; + // Ctrl+@ ('\0') はそのまま通せないので、別文字にエスケープ。 + if (ukey == 0) { + ukey = CC_NUL; + } + } + } + // 文字コードが拾えなければキーコードから + if (ukey == WXK_NONE) { + uint wxkey = event.GetKeyCode(); + DKPRINTF(" key=%3u(0x%03x)", wxkey, wxkey); + // 一部の特殊キーをここで対応。 + // キーボード国籍による違いはないだろう。 + switch (wxkey) { + case WXK_LEFT: ukey = CC_left; break; + case WXK_UP: ukey = CC_up; break; + case WXK_RIGHT: ukey = CC_right; break; + case WXK_DOWN: ukey = CC_down; break; + case WXK_F1: ukey = CC_F1; break; + case WXK_F2: ukey = CC_F2; break; + case WXK_F3: ukey = CC_F3; break; + case WXK_F4: ukey = CC_F4; break; + case WXK_F5: ukey = CC_F5; break; + case WXK_F6: ukey = CC_F6; break; + case WXK_F7: ukey = CC_F7; break; + case WXK_F8: ukey = CC_F8; break; + case WXK_F9: ukey = CC_F9; break; + case WXK_F10: ukey = CC_F10; break; + case WXK_F11: ukey = CC_F10; break; + default: + ukey = 0; + break; + } + } + if (ukey != ukey_orig) { + DKPRINTF(" -> 0x%02x", ukey); + } + DKPRINTF("\n"); + if (ukey == 0) { + return; + } + ukey &= 0xff; + + if (keyboard) { + keyboard->CharInput(ukey); + } } // 共通キーコードを取得する。 @@ -371,355 +557,408 @@ WXMainView::GetKeyCode(wxKeyEvent& event uint32 wxcode __unused = event.GetKeyCode(); uint32 rawcode __unused = event.GetRawKeyCode(); uint32 rawflags __unused = event.GetRawKeyFlags(); - uint32 inp; + uint32 raw; int keycode; -#if defined(__WXGTK__) - // wxGTK では RawKeyFlags を使う - DKPRINTF("key=0x%03x raw=0x%04x ", - wxcode, rawcode, rawflags); - inp = rawflags; -#elif defined(__WXOSX__) - // wxOSX では RawKeyCode を使う - DKPRINTF("key=0x%03x flags=0x%06x ", - wxcode, rawcode, rawflags); - inp = rawcode; + // wx キーコードは10進、16進併記しないと読みづらい + DKPRINTF("key=%3d(0x%03x) ", wxcode, wxcode); +#if defined(__WXOSX__) + // wxOSX では raw が物理キー、flags はフラグっぽいものなので不要 + DKPRINTF("raw=0x%02x (flags=0x%06x) ", rawcode, rawflags); + raw = rawcode; +#else + // wxGTK では flags が物理キー、raw は文字コードっぽいものなので不要 + DKPRINTF("flags=0x%02x (raw=0x%04x) ", rawflags, rawcode); + raw = rawflags; #endif - // どちらにしてもテーブルを引く - if (inp < countof(keycode_table)) { - keycode = keycode_table[inp]; + // まず wx キーコードでテーブルを引く + if (wxcode < countof(keycode_table)) { + keycode = keycode_table[wxcode]; } else { keycode = KC_none; } - DKPRINTF("keycode=%d %s\n", keycode, Keyboard::keyname[keycode]); - return keycode; -} + + // wx キーコードは論理キーコードなので [SHIFT] キーの左右を区別できないが + // ここでは左右を区別したいので、物理キー番号を見て区別する。 + if (keycode == KC_SHIFT) { +#if defined(__WXOSX__) + if (raw == 0x3c) +#else + if (raw == 0x3e) +#endif + { + keycode = KC_SHIFT_R; + } else { + keycode = KC_SHIFT_L; + } + } #if defined(__WXGTK__) -// wxGTK の RawKeyFlags を共通キーコードに変換するテーブル。 -/*static*/ const int -WXMainView::keycode_table[0xd4] = { - KC_none, // 0x00 - KC_none, // 0x01 - KC_none, // 0x02 - KC_none, // 0x03 - KC_none, // 0x04 - KC_none, // 0x05 - KC_none, // 0x06 - KC_none, // 0x07 - KC_none, // 0x08 - KC_none, // 0x09 - KC_1, // 0x0a - KC_2, // 0x0b - KC_3, // 0x0c - KC_4, // 0x0d - KC_5, // 0x0e - KC_6, // 0x0f - - KC_7, // 0x10 - KC_8, // 0x11 - KC_9, // 0x12 - KC_0, // 0x13 - KC_minus, // 0x14 - KC_circum, // 0x15 - KC_BS, // 0x16 - KC_TAB, // 0x17 - KC_Q, // 0x18 - KC_W, // 0x19 - KC_E, // 0x1a - KC_R, // 0x1b - KC_T, // 0x1c - KC_Y, // 0x1d - KC_U, // 0x1e - KC_I, // 0x1f - - KC_O, // 0x20 - KC_P, // 0x21 - KC_at, // 0x22 - KC_bracketleft, // 0x23 - KC_enter, // 0x24 - KC_CTRL, // 0x25 (CTRL_L) - KC_A, // 0x26 - KC_S, // 0x27 - KC_D, // 0x28 - KC_F, // 0x29 - KC_G, // 0x2a - KC_H, // 0x2b - KC_J, // 0x2c - KC_K, // 0x2d - KC_L, // 0x2e - KC_semicolon, // 0x2f - - KC_colon, // 0x30 - KC_ESC, // 0x31 - KC_SHIFT_L, // 0x32 (SHIFT_L) - KC_bracketright,// 0x33 - KC_Z, // 0x34 - KC_X, // 0x35 - KC_C, // 0x36 - KC_V, // 0x37 - KC_B, // 0x38 - KC_N, // 0x39 - KC_M, // 0x3a - KC_comma, // 0x3b - KC_period, // 0x3c - KC_slash, // 0x3d - KC_SHIFT_R, // 0x3e (SHIFT_R) - KC_PAD_multiply,// 0x3f - - KC_none, // 0x40 - KC_space, // 0x41 - KC_none, // 0x42 - KC_F1, // 0x43 - KC_F2, // 0x44 - KC_F3, // 0x45 - KC_F4, // 0x46 - KC_F5, // 0x47 - KC_F6, // 0x48 - KC_F7, // 0x49 - KC_F8, // 0x4a - KC_F9, // 0x4b - KC_F10, // 0x4c - KC_none, // 0x4d - KC_none, // 0x4e - KC_PAD_7, // 0x4f - - KC_PAD_8, // 0x50 - KC_PAD_9, // 0x51 - KC_PAD_minus, // 0x52 - KC_PAD_4, // 0x53 - KC_PAD_5, // 0x54 - KC_PAD_6, // 0x55 - KC_PAD_plus, // 0x56 - KC_PAD_1, // 0x57 - KC_PAD_2, // 0x58 - KC_PAD_3, // 0x59 - KC_PAD_0, // 0x5a - KC_PAD_decimal, // 0x5b - KC_none, // 0x5c - KC_none, // 0x5d - KC_none, // 0x5e - KC_none, // 0x5f - - KC_none, // 0x60 - KC_none, // 0x61 - KC_up, // 0x62 - KC_none, // 0x63 - KC_left, // 0x64 - KC_none, // 0x65 - KC_right, // 0x66 - KC_none, // 0x67 - KC_down, // 0x68 - KC_none, // 0x69 - KC_INS, // 0x6a - KC_DEL, // 0x6b - KC_PAD_enter, // 0x6c - KC_CTRL, // 0x6d (CTRL_R) - KC_none, // 0x6e - KC_none, // 0x6f - - KC_PAD_divide, // 0x70 - KC_none, // 0x71 - KC_none, // 0x72 - KC_none, // 0x73 - KC_none, // 0x74 - KC_none, // 0x75 - KC_none, // 0x76 - KC_none, // 0x77 - KC_none, // 0x78 - KC_none, // 0x79 - KC_none, // 0x7a - KC_none, // 0x7b - KC_none, // 0x7c - KC_none, // 0x7d - KC_none, // 0x7e - KC_none, // 0x7f - - KC_none, // 0x80 - KC_none, // 0x81 - KC_none, // 0x82 - KC_none, // 0x83 - KC_none, // 0x84 - KC_backslash, // 0x85 - KC_none, // 0x86 - KC_none, // 0x87 - KC_none, // 0x88 - KC_none, // 0x89 - KC_none, // 0x8a - KC_none, // 0x8b - KC_none, // 0x8c - KC_none, // 0x8d - KC_none, // 0x8e - KC_none, // 0x8f - - KC_none, KC_none, KC_none, KC_none, // 0x90 - KC_none, KC_none, KC_none, KC_none, - KC_none, KC_none, KC_none, KC_none, - KC_none, KC_none, KC_none, KC_none, - - KC_none, KC_none, KC_none, KC_none, // 0xa0 - KC_none, KC_none, KC_none, KC_none, - KC_none, KC_none, KC_none, KC_none, - KC_none, KC_none, KC_none, KC_none, - - KC_none, KC_none, KC_none, KC_none, // 0xb0 - KC_none, KC_none, KC_none, KC_none, - KC_none, KC_none, KC_none, KC_none, - KC_none, KC_none, KC_none, KC_none, - - KC_none, KC_none, KC_none, KC_none, // 0xc0 - KC_none, KC_none, KC_none, KC_none, - KC_none, KC_none, KC_none, KC_none, - KC_none, KC_none, KC_none, KC_none, - - KC_none, // 0xd0 - KC_none, // 0xd1 - KC_none, // 0xd2 - KC_underscore, // 0xd3 -}; -#endif // __WXGTK__ + // wxGTK では日本語キーボードの一部のキーが論理キーコードだけでは + // 判定できないようだ + // その上 raw キーコードも OS (か何か) によってところどころ体系が + // 異なるようだ。orz + // + // OS [^] [0] [_] [\] + // --------------- ----- ----- ----- ----- + // NetBSD9 0x15 0x13 0xd3 0x85 + // OpenBSD7.1 0x15 0x13 0xd3 0x85 + // Ubuntu20.04 0x15 0x13 0x61 0x84 + + // [0] と [SHIFT]+[^] が同じキーコードになるようだ + if (keycode == KC_0) { + if (raw == 0x15) { + keycode = KC_circum; + } else { + keycode = KC_0; + } + } + // [\] と [_] が同じキーコードになるようだ。 + // その時の raw は OS によって(?)異なるようだ。 + if (keycode == KC_backslash) { + switch (raw) { + case 0xd3: // NetBSD9 + case 0x61: // Ubuntu20.04 + keycode = KC_underscore; + break; + default: + keycode = KC_backslash; + break; + } + } +#endif -#if defined(__WXOSX__) -// wxOSX の RawKeyCode を共通キーコードに変換するテーブル。 -// Mac の CAPS は押す離すで一回分の KeyDown しか来ないのでちょっと放置。 -// [英数] と [かな] もちょっと放置。 + DKPRINTF("keycode=%d %s\n", keycode, Keyboard::GetKeyName(keycode).c_str()); + return keycode; +} + +// wx キーコード(WXK_*)を共通キーコードに変換するテーブル。 +// 一部このテーブルだけでは判定できないものがある。すぐ上の GetKeyCode() 参照。 +// 値 0 は本当は KC_none と書くべきだが、こっちのほうが読みやすいので。 +// +// XXX: OSX の [CAPS] は押す離すで一回分の Down しか来ないのでちょっと放置。 +// XXX: OSX の [英数] と [かな] もちょっと放置。 /*static*/ const int -WXMainView::keycode_table[0x80] = { - KC_A, // 0x00 - KC_S, // 0x01 - KC_D, // 0x02 - KC_F, // 0x03 - KC_H, // 0x04 - KC_G, // 0x05 - KC_Z, // 0x06 - KC_X, // 0x07 - KC_C, // 0x08 - KC_V, // 0x09 - KC_none, // 0x0a - KC_B, // 0x0b - KC_Q, // 0x0c - KC_W, // 0x0d - KC_E, // 0x0e - KC_R, // 0x0f - - KC_Y, // 0x10 - KC_T, // 0x11 - KC_1, // 0x12 - KC_2, // 0x13 - KC_3, // 0x14 - KC_4, // 0x15 - KC_6, // 0x16 - KC_5, // 0x17 - KC_circum, // 0x18 - KC_9, // 0x19 - KC_7, // 0x1a - KC_minus, // 0x1b - KC_8, // 0x1c - KC_0, // 0x1d - KC_bracketleft, // 0x1e - KC_O, // 0x1f - - KC_U, // 0x20 - KC_at, // 0x21 - KC_I, // 0x22 - KC_P, // 0x23 - KC_enter, // 0x24 - KC_L, // 0x25 - KC_J, // 0x26 - KC_colon, // 0x27 - KC_K, // 0x28 - KC_semicolon, // 0x29 - KC_bracketright,// 0x2a - KC_comma, // 0x2b - KC_slash, // 0x2c - KC_N, // 0x2d - KC_M, // 0x2e - KC_period, // 0x2f - - KC_TAB, // 0x30 - KC_space, // 0x31 - KC_none, // 0x32 - KC_BS, // 0x33 - KC_none, // 0x34 - KC_ESC, // 0x35 - KC_none, // 0x36 - KC_none, // 0x37 - KC_SHIFT_L, // 0x38 - KC_none, // 0x39 - KC_none, // 0x3a - KC_CTRL, // 0x3b - KC_SHIFT_R, // 0x3c - KC_none, // 0x3d - KC_none, // 0x3e - KC_none, // 0x3f - - KC_none, // 0x40 - KC_none, // 0x41 - KC_none, // 0x42 - KC_none, // 0x43 - KC_none, // 0x44 - KC_none, // 0x45 - KC_none, // 0x46 - KC_none, // 0x47 - KC_none, // 0x48 - KC_none, // 0x49 - KC_none, // 0x4a - KC_none, // 0x4b - KC_none, // 0x4c - KC_none, // 0x4d - KC_none, // 0x4e - KC_none, // 0x4f - - KC_none, // 0x50 - KC_none, // 0x51 - KC_none, // 0x52 - KC_none, // 0x53 - KC_none, // 0x54 - KC_none, // 0x55 - KC_none, // 0x56 - KC_none, // 0x57 - KC_none, // 0x58 - KC_none, // 0x59 - KC_none, // 0x5a - KC_none, // 0x5b - KC_none, // 0x5c - KC_backslash, // 0x5d - KC_underscore, // 0x5e - KC_none, // 0x5f - - KC_F5, // 0x60 - KC_F6, // 0x61 - KC_F7, // 0x62 - KC_F3, // 0x63 - KC_F8, // 0x64 - KC_F9, // 0x65 - KC_none, // 0x66 - KC_none, // 0x67 F11 - KC_none, // 0x68 - KC_none, // 0x69 - KC_none, // 0x6a - KC_none, // 0x6b - KC_none, // 0x6c - KC_F10, // 0x6d - KC_none, // 0x6e - KC_none, // 0x6f F12 - - KC_none, // 0x70 - KC_none, // 0x71 - KC_none, // 0x72 - KC_none, // 0x73 - KC_none, // 0x74 - KC_none, // 0x75 - KC_F4, // 0x76 - KC_none, // 0x77 - KC_F2, // 0x78 - KC_none, // 0x79 - KC_F1, // 0x7a - KC_left, // 0x7b - KC_right, // 0x7c - KC_down, // 0x7d - KC_up, // 0x7e - KC_none, // 0x7f +WXMainView::keycode_table[0x190] = { + 0, // 0x00 + 0, // 0x01 + 0, // 0x02 + 0, // 0x03 + 0, // 0x04 + 0, // 0x05 + 0, // 0x06 + 0, // 0x07 + KC_BS, // 0x08 WXK_BACK + KC_TAB, // 0x09 WXK_TAB + 0, // 0x0a + 0, // 0x0b + 0, // 0x0c + KC_enter, // 0x0d WXK_RETURN + 0, // 0x0e + 0, // 0x0f + + 0, // 0x10 + 0, // 0x11 + 0, // 0x12 + 0, // 0x13 + 0, // 0x14 + 0, // 0x15 + 0, // 0x16 + 0, // 0x17 + 0, // 0x18 + 0, // 0x19 + 0, // 0x1a + KC_ESC, // 0x1b WXK_ESCAPE + 0, // 0x1c + 0, // 0x1d + 0, // 0x1e + 0, // 0x1f + + KC_space, // 0x20 WXK_SPACE + KC_1, // 0x21 (OSX: [SHIFT]+[1]) + KC_2, // 0x22 (OSX: [SHIFT]+[2]) + KC_3, // 0x23 (OSX: [SHIFT]+[3]) + KC_4, // 0x24 (OSX: [SHIFT]+[4]) + KC_5, // 0x25 (OSX: [SHIFT]+[5]) + KC_6, // 0x26 (OSX: [SHIFT]+[6]) + KC_7, // 0x27 (OSX: [SHIFT]+[7]) + KC_8, // 0x28 (OSX: [SHIFT]+[8]) + KC_9, // 0x29 (OSX: [SHIFT]+[9]) + KC_colon, // 0x2a (OSX: [SHIFT]+[:]) + KC_semicolon, // 0x2b (OSX: [SHIFT]+[;]) + KC_comma, // 0x2c + KC_minus, // 0x2d + KC_period, // 0x2e + KC_slash, // 0x2f + + KC_0, // 0x30 (GTK: [0] と [SHIFT]+[^]) + KC_1, // 0x31 + KC_2, // 0x32 + KC_3, // 0x33 + KC_4, // 0x34 + KC_5, // 0x35 + KC_6, // 0x36 + KC_7, // 0x37 + KC_8, // 0x38 + KC_9, // 0x39 + KC_colon, // 0x3a + KC_semicolon, // 0x3b + KC_comma, // 0x3c (GTK: [,]は0x2c だが [SHIFT]+[,]は0x3c) + KC_minus, // 0x3d (OSX: [SHIFT]+[-]) + KC_period, // 0x3e (OSX: [SHIFT]+[.]) + KC_slash, // 0x3f (OSX: [SHIFT]+[/]) + + KC_at, // 0x40 + KC_A, // 0x41 + KC_B, // 0x42 + KC_C, // 0x43 + KC_D, // 0x44 + KC_E, // 0x45 + KC_F, // 0x46 + KC_G, // 0x47 + KC_H, // 0x48 + KC_I, // 0x49 + KC_J, // 0x4a + KC_K, // 0x4b + KC_L, // 0x4c + KC_M, // 0x4d + KC_N, // 0x4e + KC_O, // 0x4f + + KC_P, // 0x50 + KC_Q, // 0x51 + KC_R, // 0x52 + KC_S, // 0x53 + KC_T, // 0x54 + KC_U, // 0x55 + KC_V, // 0x56 + KC_W, // 0x57 + KC_X, // 0x58 + KC_Y, // 0x59 + KC_Z, // 0x5a + KC_bracketleft, // 0x5b + KC_backslash, // 0x5c (GTK: [\] と [_]) + KC_bracketright,// 0x5d + KC_circum, // 0x5e + KC_underscore, // 0x5f (OSX: [_]) + + KC_at, // 0x60 (OSX: [SHIFT]+[@]) + 0, // 0x61 + 0, // 0x62 + 0, // 0x63 + 0, // 0x64 + 0, // 0x65 + 0, // 0x66 + 0, // 0x67 + 0, // 0x68 + 0, // 0x69 + 0, // 0x6a + 0, // 0x6b + 0, // 0x6c + 0, // 0x6d + 0, // 0x6e + 0, // 0x6f + + 0, // 0x70 + 0, // 0x71 + 0, // 0x72 + 0, // 0x73 + 0, // 0x74 + 0, // 0x75 + 0, // 0x76 + 0, // 0x77 + 0, // 0x78 + 0, // 0x79 + 0, // 0x7a + KC_bracketleft, // 0x7b (OSX: [SHIFT]+[[]) + KC_backslash, // 0x7c (OSX: [SHIFT]+[\]) + KC_bracketright,// 0x7d (OSX: [SHIFT]+[]]) + KC_circum, // 0x7e (OSX: [SHIFT]+[^]) + KC_DEL, // 0x7f + + 0,0,0,0, 0,0,0,0, // 0x80 + 0,0,0,0, 0,0,0,0, // 0x88 + 0,0,0,0, 0,0,0,0, // 0x90 + 0,0,0,0, 0,0,0,0, // 0x98 + + 0, // 0xa0 + 0, // 0xa1 + 0, // 0xa2 + 0, // 0xa3 + 0, // 0xa4 + KC_backslash, // 0xa5 (OSX: [\]) + 0, // 0xa6 + 0, // 0xa7 + 0, // 0xa8 + 0, // 0xa9 + 0, // 0xaa + 0, // 0xab + 0, // 0xac + 0, // 0xad + 0, // 0xae + 0, // 0xaf + + 0,0,0,0, 0,0,0,0, // 0xb0 + 0,0,0,0, 0,0,0,0, // 0xb8 + + 0, // 0xc0=192 + 0, // 193 WXK_SPECIAL1 + 0, // 194 WXK_SPECIAL2 + 0, // 195 WXK_SPECIAL3 + 0, // 196 WXK_SPECIAL4 + 0, // 197 WXK_SPECIAL5 + 0, // 198 WXK_SPECIAL6 + 0, // 199 WXK_SPECIAL7 + + 0, // 200 WXK_SPECIAL8 + 0, // 201 WXK_SPECIAL9 + 0, // 202 WXK_SPECIAL10 + 0, // 203 WXK_SPECIAL11 + 0, // 204 WXK_SPECIAL12 + 0, // 205 WXK_SPECIAL13 + 0, // 206 WXK_SPECIAL14 + 0, // 207 WXK_SPECIAL15 + 0, // 208 WXK_SPECIAL16 + 0, // 209 WXK_SPECIAL17 + + 0, // 210 WXK_SPECIAL18 + 0, // 211 WXK_SPECIAL19 + 0, // 212 WXK_SPECIAL20 + 0, // 0xd5 + 0, // 0xd6 + 0, // 0xd7 + + 0,0,0,0, 0,0,0,0, // 0xd8 + 0,0,0,0, 0,0,0,0, // 0xe0 + 0,0,0,0, 0,0,0,0, // 0xe8 + 0,0,0,0, 0,0,0,0, // 0xf0 + 0,0,0,0, 0,0,0,0, // 0xf8 + 0,0,0,0, 0,0,0,0, // 0x100 + 0,0,0,0, 0,0,0,0, // 0x108 + 0,0,0,0, 0,0,0,0, // 0x110 + 0,0,0,0, 0,0,0,0, // 0x118 + 0,0,0,0, 0,0,0,0, // 0x120 + + 0, // 0x128 + 0, // 0x129 + 0, // 0x12a + 0, // 0x12b + // + // WXK_* は10進数で定義されていて、特殊キーは 300 (=0x12c) から。 + // + 0, // 300 WXK_START + 0, // 301 WXK_LBUTTON + 0, // 302 WXK_RBUTTON + 0, // 303 WXK_CANCEL + 0, // 304 WXK_MBUTTON + 0, // 305 WXK_CLEAR + KC_SHIFT, // 306 WXK_SHIFT (左右[SHIFT]) + 0, // 307 WXK_ALT + KC_CTRL, // 308 WXK_CONTROL (ゲストに右[CTRL]はないので区別不要) + 0, // 309 WXK_MENU + + 0, // 310 WXK_PAUSE + 0, // 311 WXK_CAPITAL + KC_UNDO, // 312 WXK_END + KC_HOME, // 313 WXK_HOME + KC_left, // 314 WXK_LEFT + KC_up, // 315 WXK_UP + KC_right, // 316 WXK_RIGHT + KC_down, // 317 WXK_DOWN + 0, // 318 WXK_SELECT + 0, // 319 WXK_PRINT + + 0, // 320 WXK_EXECUTE + 0, // 321 WXK_SNAPSHOT + KC_INS, // 322 WXK_INSERT + 0, // 323 WXK_HELP + KC_PAD_0, // 324 WXK_NUMPAD0 + KC_PAD_1, // 325 WXK_NUMPAD1 + KC_PAD_2, // 326 WXK_NUMPAD2 + KC_PAD_3, // 327 WXK_NUMPAD3 + KC_PAD_4, // 328 WXK_NUMPAD4 + KC_PAD_5, // 329 WXK_NUMPAD5 + + KC_PAD_6, // 330 WXK_NUMPAD6 + KC_PAD_7, // 331 WXK_NUMPAD7 + KC_PAD_8, // 332 WXK_NUMPAD8 + KC_PAD_9, // 333 WXK_NUMPAD9 + 0, // 334 WXK_MULTIPLY + 0, // 335 WXK_ADD + 0, // 336 WXK_SEPARATOR + 0, // 337 WXK_SUBTRACT + 0, // 338 WXK_DECIMAL + 0, // 339 WXK_DIVIDE + + KC_F1, // 340 WXK_F1 + KC_F2, // 341 WXK_F2 + KC_F3, // 342 WXK_F3 + KC_F4, // 343 WXK_F4 + KC_F5, // 344 WXK_F5 + KC_F6, // 345 WXK_F6 + KC_F7, // 346 WXK_F7 + KC_F8, // 347 WXK_F8 + KC_F9, // 348 WXK_F9 + KC_F10, // 349 WXK_F10 + + KC_F10, // 350 WXK_F11 + 0, // 351 WXK_F12 + 0, // 352 WXK_F13 + 0, // 353 WXK_F14 + 0, // 354 WXK_F15 + 0, // 355 WXK_F16 + 0, // 356 WXK_F17 + 0, // 357 WXK_F18 + 0, // 358 WXK_F19 + 0, // 359 WXK_F20 + + 0, // 360 WXK_F21 + 0, // 361 WXK_F22 + 0, // 362 WXK_F23 + 0, // 363 WXK_F24 + 0, // 364 WXK_NUMLOCK + 0, // 365 WXK_SCROLL + KC_ROLLUP, // 366 WXK_PAGEUP + KC_ROLLDOWN, // 367 WXK_PAGEDOWN + 0, // 368 WXK_NUMPAD_SPACE + 0, // 369 WXK_NUMPAD_TAB + + KC_PAD_enter, // 370 WXK_NUMPAD_ENTER + 0, // 371 WXK_NUMPAD_F1 + 0, // 372 WXK_NUMPAD_F2 + 0, // 373 WXK_NUMPAD_F3 + 0, // 374 WXK_NUMPAD_F4 + 0, // 375 WXK_NUMPAD_HOME + 0, // 376 WXK_NUMPAD_LEFT + 0, // 377 WXK_NUMPAD_UP + 0, // 378 WXK_NUMPAD_RIGHT + 0, // 379 WXK_NUMPAD_DOWN + + 0, // 380 WXK_NUMPAD_PAGEUP + 0, // 381 WXK_NUMPAD_PAGEDOWN + 0, // 382 WXK_NUMPAD_END + 0, // 383 WXK_NUMPAD_BEGIN + 0, // 384 WXK_NUMPAD_INSERT + 0, // 385 WXK_NUMPAD_DELETE + KC_PAD_equal, // 386 WXK_NUMPAD_EQUAL + KC_PAD_multiply,// 387 WXK_NUMPAD_MULTIPLY + KC_PAD_plus, // 388 WXK_NUMPAD_ADD + 0, // 389 WXK_NUMPAD_SEPARATOR + + KC_PAD_minus, // 390 WXK_NUMPAD_SUBTRACT + KC_PAD_decimal, // 391 WXK_NUMPAD_DECIMAL + KC_PAD_divide, // 392 WXK_NUMPAD_DIVIDE + 0, // 393 WXK_WINDOWS_LEFT + 0, // 394 WXK_WINDOWS_RIGHT + 0, // 395 WXK_WINDOWS_MENU + // WXK_RAW_CONTROL は wxOSX でのみ定義してあり (wxOSX 以外では別名)、 + // wxOSX とそれ以外とで定義済みキーの最大値が違う。そこが可変だとこの + // テーブルが困るので、wxOSX 以外でも常に WXK_RAW_CONTROL 分の枠は用意 + // することにする。wxOSX 以外だと飛んでこないというだけで害はない。 + KC_CTRL, // 396 WXK_RAW_CONTROL (OSX) + + 0, // 397 + 0, // 398 + 0, // 399=0x18f }; -#endif // __WXOSX__