--- nono/vm/lunakbd.cpp 2026/04/29 17:05:06 1.1.1.12 +++ nono/vm/lunakbd.cpp 2026/04/29 17:06:00 1.1.1.18 @@ -4,13 +4,21 @@ // Licensed under nono-license.txt // -// キーボードとマウス // +// LUNA のキーボードとマウス +// + // キーボード/マウスからシリアルポートへの入力は、1バイトの送信自体に約1msec // (9600bps、スタートビット1、ストップビット1) で送信後に 1msec 空けるそう // なので、ここでは単純に 2msec を1スロットとする。 +// +// ブザー発声はキー入力とは本来あまり関係ないが、ブザー発声中もキー入力中と +// 同様に高速走行を抑制したいため、キー扱いとしていることに留意。 #include "lunakbd.h" +#include "event.h" +#include "monitor.h" +#include "scheduler.h" #include "sio.h" #include "uimessage.h" @@ -19,12 +27,9 @@ LunaKeyboard::LunaKeyboard() { led.resize(2); - event.func = (DeviceCallback_t)&LunaKeyboard::Callback; - event.SetName("Keyboard/Mouse"); - - monitor.func = (MonitorCallback_t)&LunaKeyboard::MonitorUpdate; - monitor.SetSize(40, 4); - monitor.Regist(ID_MONITOR_KEYBOARD); + monitor = gMonitorManager->Regist(ID_MONITOR_KEYBOARD, this); + monitor->SetCallback(&LunaKeyboard::MonitorScreen); + monitor->SetSize(40, 4); } // デストラクタ @@ -32,12 +37,36 @@ LunaKeyboard::~LunaKeyboard() { } -// 電源オン +// 初期化 bool -LunaKeyboard::PowerOn() +LunaKeyboard::Init() +{ + if (inherited::Init() == false) { + return false; + } + + // LUNA-88K は左 [SHIFT] が 0x0d、右 [SHIFT] が 0x0c。 + if (gMainApp.IsLUNA88K()) { + keycode2lunakey_table[0x0c] = LunaKey_SHIFT_R; + keycode2lunakey_table[0x0d] = LunaKey_SHIFT_L; + } + + sio = GetSIODevice(); + + auto evman = GetEventManager(); + event = evman->Regist(this, + ToEventCallback(&LunaKeyboard::Callback), + "Keyboard/Mouse"); + + return true; +} + +// キーボード接続時の MD 固有処理 +void +LunaKeyboard::MDConnect() { // XXX リセットはマウスには届かないような気がするので - // 電源オンで初期化。 + // 接続時(電源オン)で初期化。 mouse_x = 0; mouse_y = 0; mouse_r = false; @@ -47,28 +76,30 @@ LunaKeyboard::PowerOn() prev_l = false; prev_m = false; - // ブザー停止 - buzzer_on = false; + // ブザー停止状態で初期化すると定義されている + BreakKey(KC_buzzer); - return true; + // デフォルトでマウス有効 + MouseOn(); } -// リセット +// キーボード取り外し時の MD 固有処理 void -LunaKeyboard::ResetHard() +LunaKeyboard::MDDisconnect() { - inherited::ResetHard(); + // 動作中のタイマーは停止 + scheduler->StopEvent(event); - // 動作中のタイマーは一旦とめる - event.Stop(); + // 電源が切れるのでブザー停止 + BreakKey(KC_buzzer); - // マウスサンプリングは電源オン時から有効 - MouseOn(); + // マウスサンプリングは停止 + MouseOff(); } // モニター void -LunaKeyboard::MonitorUpdate(Monitor *, TextScreen& screen) +LunaKeyboard::MonitorScreen(Monitor *, TextScreen& screen) { int x; int y; @@ -88,7 +119,7 @@ LunaKeyboard::MonitorUpdate(Monitor *, T screen.Puts(x + 4, y, TA::OnOff(led[0]), "Kana"); y++; screen.Puts(0, y, "Buzzer:"); - screen.Print(x, y, buzzer_on ? TA::Normal : TA::Disable, + screen.Print(x, y, IsPressed(KC_buzzer) ? TA::Normal : TA::Disable, "%umsec %uHz", buzzer_msec, buzzer_freq); y++; @@ -183,7 +214,7 @@ LunaKeyboard::KeyInput(uint keystat) // LED 状態が変更になったので全走査指示。 // KeyInputCommon() 内で一度ポストしてるので無駄気味だが仕方ない… - UIMessage::Post(UIMessage::KEYBOARD); + uimessage->Post(UIMessage::KEYBOARD); } // LUNA のキーボードはキーボード側でキーリピートしないので @@ -244,12 +275,12 @@ LunaKeyboard::SendStart() void LunaKeyboard::Start(uint64 period) { - uint64 now = gMPU->GetVirtTime(); + uint64 now = scheduler->GetVirtTime(); uint64 target = ((now / period) + 1) * period; // XXX メンバの event.vtime 参照してるけどどうするかね - if (event.IsRunning() == false || target < event.vtime) { - event.time = target - now; - event.Start(); + if (event->IsRunning() == false || target < event->vtime) { + event->time = target - now; + scheduler->RestartEvent(event); } } @@ -257,9 +288,9 @@ LunaKeyboard::Start(uint64 period) // キー入力、マウス入力、ブザー出力のいずれかが発生している間 2msec ごとに // 呼ばれる。 void -LunaKeyboard::Callback(Event& ev) +LunaKeyboard::Callback(Event *ev) { - uint64 now = gMPU->GetVirtTime(); + uint64 now = scheduler->GetVirtTime(); uint mdkey; // マウスサンプリングオンなら 20msec ごとにサンプリングを行う。 @@ -267,19 +298,18 @@ LunaKeyboard::Callback(Event& ev) MouseSampling(); } + // キューから取り出す。ここで取り出せるのは MDKey またはマウスデータ if (sendqueue.Dequeue(&mdkey)) { - // キューから取り出す。ここで取り出せるのは MDKey - // またはマウスデータ // 送信 - gSIO->Rx(1, mdkey); + sio->Rx(1, mdkey); } - if (buzzer_on && now > buzzer_end) { - buzzer_on = false; - Release(); + if (IsPressed(KC_buzzer) && now > buzzer_end) { + // VM スレッド内なので BreakKey() ではなくこっちを直接呼ぶ + KeyInput(KC_buzzer | KC_FLAG_BREAK); } - if (sendqueue.Empty() == false || buzzer_on) { + if (sendqueue.Empty() == false || IsPressed(KC_buzzer)) { // 送信データが残っていれば次は 2msec 後 Start(2_msec); } else if (mouse_on) { @@ -392,11 +422,11 @@ LunaKeyboard::Command(uint32 data) uint code = data & 0x01; uint on = data & 0x10; led[code] = (bool)on; - UIMessage::Post(UIMessage::KEYBOARD); + uimessage->Post(UIMessage::KEYBOARD); if (loglevel >= 1) { const auto name = GetKeyName(LED2Keycode(code)); - putlogn("Command LED $%x(%s) %s", - code, name.c_str(), (on ? "ON" : "OFF")); + putlogn("Command $%02x LED $%x(%s) %s", + data, code, name.c_str(), (on ? "ON" : "OFF")); } break; } @@ -413,12 +443,13 @@ LunaKeyboard::Command(uint32 data) uint f = data & 7; buzzer_msec = buzzer_msec_table[t]; buzzer_freq = buzzer_freq_table[f]; - putlog(1, "Command Buzzer %dmsec, %dHz", buzzer_msec, buzzer_freq); + putlog(1, "Command $%02x Buzzer %umsec, %uHz", + data, buzzer_msec, buzzer_freq); - uint64 now = gMPU->GetVirtTime(); - buzzer_end = now + buzzer_msec * 1_msec; - buzzer_on = true; - Acquire(); + uint64 now = scheduler->GetVirtTime(); + buzzer_end = now + msec_to_nsec(buzzer_msec); + // VM スレッド内なので MakeKey() ではなく KeyInput() を直接呼ぶ + KeyInput(KC_buzzer | KC_FLAG_MAKE); Start(2_msec); break; } @@ -428,7 +459,7 @@ LunaKeyboard::Command(uint32 data) // +---+---+---+---+---+---+---+---+ // | 0 0 1 | x x x x x | // +---+---+---+---+---+---+---+---+ - putlog(1, "Command Mouse Sampling Off"); + putlog(1, "Command $%02x Mouse Sampling Off", data); MouseOff(); break; @@ -437,12 +468,12 @@ LunaKeyboard::Command(uint32 data) // +---+---+---+---+---+---+---+---+ // | 0 1 1 | x x x x x | // +---+---+---+---+---+---+---+---+ - putlog(1, "Command Mouse Sampling On"); + putlog(1, "Command $%02x Mouse Sampling On", data); MouseOn(); break; default: - putlog(1, "未定義コマンド受信 $%02x", data); + putlog(1, "Command $%02x Undefined", data); break; } } @@ -451,7 +482,7 @@ LunaKeyboard::Command(uint32 data) // 共通キーコードから LUNA キーコードに変換する。 // ぶっちゃけた話共通キーコードは LUNA キーコードをベースにしているので、 // 穴がある以外は全部透過。 -/*static*/ const uint +/*static*/ uint LunaKeyboard::keycode2lunakey_table[KC_max] = { NoKey, // [00] NoKey, // [01] @@ -487,8 +518,8 @@ LunaKeyboard::keycode2lunakey_table[KC_m LunaKey_right, // [1e] LunaKey_down, // [1f] - NoKey, // [20] - NoKey, // [21] + LunaKey_INSERT, // [20] + LunaKey_COPY, // [21] LunaKey_1, // [22] LunaKey_2, // [23] LunaKey_3, // [24] @@ -502,10 +533,10 @@ LunaKeyboard::keycode2lunakey_table[KC_m LunaKey_minus, // [2c] LunaKey_circum, // [2d] LunaKey_backslash, // [2e] - NoKey, // [2f] + LunaKey_buzzer, // [2f] - NoKey, // [30] - NoKey, // [31] + LunaKey_CUT, // [30] + LunaKey_PASTE, // [31] LunaKey_Q, // [32] LunaKey_W, // [33] LunaKey_E, // [34] @@ -555,7 +586,7 @@ LunaKeyboard::keycode2lunakey_table[KC_m NoKey, // [5e] NoKey, // [5f] - NoKey, // [60] + LunaKey_PAD_HOME, // [60] LunaKey_PAD_plus, // [61] LunaKey_PAD_minus, // [62] LunaKey_PAD_7, // [63]