From f40dbefa671aa2a6972939b15a120241fae51373 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 2 Nov 2019 22:30:02 -0400 Subject: [PATCH] Implements most of keyboard input. --- Machines/AtariST/AtariST.cpp | 17 ++++- Machines/AtariST/IntelligentKeyboard.cpp | 84 +++++++++++++++++++++++- Machines/AtariST/IntelligentKeyboard.hpp | 33 ++++++++++ 3 files changed, 130 insertions(+), 4 deletions(-) diff --git a/Machines/AtariST/AtariST.cpp b/Machines/AtariST/AtariST.cpp index 7897b2690..87821642d 100644 --- a/Machines/AtariST/AtariST.cpp +++ b/Machines/AtariST/AtariST.cpp @@ -9,6 +9,7 @@ #include "AtariST.hpp" #include "../CRTMachine.hpp" +#include "../KeyboardMachine.hpp" #include "../MouseMachine.hpp" //#define LOG_TRACE @@ -45,7 +46,8 @@ class ConcreteMachine: public Motorola::ACIA::ACIA::InterruptDelegate, public Motorola::MFP68901::MFP68901::InterruptDelegate, public DMAController::InterruptDelegate, - public MouseMachine::Machine { + public MouseMachine::Machine, + public KeyboardMachine::MappedMachine { public: ConcreteMachine(const Target &target, const ROMMachine::ROMFetcher &rom_fetcher) : mc68000_(*this), @@ -488,7 +490,18 @@ class ConcreteMachine: Inputs::Mouse &get_mouse() final { return ikbd_; } - }; + + // MARK: - KeyboardMachine + void set_key_state(uint16_t key, bool is_pressed) final { + ikbd_.set_key_state(Key(key), is_pressed); + } + + IntelligentKeyboard::KeyboardMapper keyboard_mapper_; + KeyboardMapper *get_keyboard_mapper() final { + return &keyboard_mapper_; + } + +}; } } diff --git a/Machines/AtariST/IntelligentKeyboard.cpp b/Machines/AtariST/IntelligentKeyboard.cpp index 95c77c94d..d62af66a2 100644 --- a/Machines/AtariST/IntelligentKeyboard.cpp +++ b/Machines/AtariST/IntelligentKeyboard.cpp @@ -58,6 +58,16 @@ void IntelligentKeyboard::run_for(HalfCycles duration) { } + // Forward key changes; implicit assumption here: mutexs are cheap while there's + // negligible contention. + { + std::lock_guard guard(key_queue_mutex_); + for(uint8_t key: key_queue_) { + output_bytes({key}); + } + key_queue_.clear(); + } + output_line_.advance_writer(duration); } @@ -66,8 +76,6 @@ void IntelligentKeyboard::output_bytes(std::initializer_list values) { for(auto value : values) { output_line_.write(2, 10, 0x200 | (value << 1)); } - - // TODO: this isn't thread safe! Might need this class to imply a poll? update_clocking_observer(); } @@ -225,6 +233,77 @@ void IntelligentKeyboard::post_relative_mouse_event(int x, int y) { } while(x || y); } +// MARK: - Keyboard Input +void IntelligentKeyboard::set_key_state(Key key, bool is_pressed) { + std::lock_guard guard(key_queue_mutex_); + if(is_pressed) { + key_queue_.push_back(uint8_t(key)); + } else { + key_queue_.push_back(0x80 | uint8_t(key)); + } +} + +uint16_t IntelligentKeyboard::KeyboardMapper::mapped_key_for_key(Inputs::Keyboard::Key key) { + using Key = Inputs::Keyboard::Key; + using STKey = Atari::ST::Key; + switch(key) { + default: return KeyboardMachine::MappedMachine::KeyNotMapped; + +#define Bind(x, y) case Key::x: return uint16_t(STKey::y) +#define QBind(x) case Key::x: return uint16_t(STKey::x) + + QBind(k1); QBind(k2); QBind(k3); QBind(k4); QBind(k5); QBind(k6); QBind(k7); QBind(k8); QBind(k9); QBind(k0); + QBind(Q); QBind(W); QBind(E); QBind(R); QBind(T); QBind(Y); QBind(U); QBind(I); QBind(O); QBind(P); + QBind(A); QBind(S); QBind(D); QBind(F); QBind(G); QBind(H); QBind(J); QBind(K); QBind(L); + QBind(Z); QBind(X); QBind(C); QBind(V); QBind(B); QBind(N); QBind(M); + + QBind(Left); QBind(Right); QBind(Up); QBind(Down); + + QBind(BackTick); QBind(Tab); + QBind(Hyphen); QBind(Equals); QBind(Backspace); + QBind(OpenSquareBracket); + QBind(CloseSquareBracket); + QBind(CapsLock); + QBind(Semicolon); + QBind(Quote); + Bind(Enter, Return); + QBind(LeftShift); + QBind(RightShift); + + Bind(Comma, Comma); + Bind(FullStop, FullStop); + Bind(ForwardSlash, ForwardSlash); + + Bind(LeftOption, Alt); + Bind(RightOption, Alt); + QBind(Space); + QBind(Backslash); + +/* Bind(KeyPadDelete, KeyPadDelete); + Bind(KeyPadEquals, KeyPadEquals); + Bind(KeyPadSlash, KeyPadSlash); + Bind(KeyPadAsterisk, KeyPadAsterisk); + Bind(KeyPadMinus, KeyPadMinus); + Bind(KeyPadPlus, KeyPadPlus); + Bind(KeyPadEnter, KeyPadEnter); + Bind(KeyPadDecimalPoint, KeyPadDecimalPoint); + + Bind(KeyPad9, KeyPad9); + Bind(KeyPad8, KeyPad8); + Bind(KeyPad7, KeyPad7); + Bind(KeyPad6, KeyPad6); + Bind(KeyPad5, KeyPad5); + Bind(KeyPad4, KeyPad4); + Bind(KeyPad3, KeyPad3); + Bind(KeyPad2, KeyPad2); + Bind(KeyPad1, KeyPad1); + Bind(KeyPad0, KeyPad0);*/ + +#undef QBind +#undef Bind + } +} + // MARK: - Mouse Input void IntelligentKeyboard::move(int x, int y) { @@ -252,3 +331,4 @@ void IntelligentKeyboard::reset_all_buttons() { // MARK: - Joystick Output void IntelligentKeyboard::disable_joysticks() { } + diff --git a/Machines/AtariST/IntelligentKeyboard.hpp b/Machines/AtariST/IntelligentKeyboard.hpp index 5a1c89e52..95ceca6c6 100644 --- a/Machines/AtariST/IntelligentKeyboard.hpp +++ b/Machines/AtariST/IntelligentKeyboard.hpp @@ -11,14 +11,38 @@ #include "../../ClockReceiver/ClockingHintSource.hpp" #include "../../Components/SerialPort/SerialPort.hpp" +#include "../KeyboardMachine.hpp" #include "../../Inputs/Mouse.hpp" #include +#include namespace Atari { namespace ST { +enum class Key: uint16_t { + Escape = 1, + k1, k2, k3, k4, k5, k6, k7, k8, k9, k0, Hyphen, Equals, Backspace, + Tab, Q, W, E, R, T, Y, U, I, O, P, OpenSquareBracket, CloseSquareBracket, Return, + Control, A, S, D, F, G, H, J, K, L, Semicolon, Quote, BackTick, + LeftShift, Backslash, Z, X, C, V, B, N, M, Comma, FullStop, ForwardSlash, RightShift, + /* 0x37 is unused. */ + Alt = 0x38, Space, CapsLock, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, + /* Various gaps follow. */ + Home = 0x47, Up, + KeypadMinus = 0x4a, Left, + Right = 0x4d, KeypadPlus, + Down = 0x50, + Insert = 0x52, Delete, + ISO = 0x60, Undo, Help, KeypadOpenBracket, KeypadCloseBracket, KeypadDivide, KeypadMultiply, + Keypad7, Keypad8, Keypad9, Keypad4, KeyPad5, Keypad6, Keypad1, Keypad2, Keypad3, Keypad0, KeypadDecimalPoint, + KeypadEnter +}; +static_assert(uint16_t(Key::RightShift) == 0x36, "RightShift should have key code 0x36; check intermediate entries"); +static_assert(uint16_t(Key::F10) == 0x44, "F10 should have key code 0x44; check intermediate entries"); +static_assert(uint16_t(Key::KeypadEnter) == 0x72, "KeypadEnter should have key code 0x72; check intermediate entries"); + /*! A receiver for the Atari ST's "intelligent keyboard" commands, which actually cover keyboard input and output and mouse handling. @@ -32,7 +56,16 @@ class IntelligentKeyboard: ClockingHint::Preference preferred_clocking() final; void run_for(HalfCycles duration); + void set_key_state(Key key, bool is_pressed); + class KeyboardMapper: public KeyboardMachine::MappedMachine::KeyboardMapper { + uint16_t mapped_key_for_key(Inputs::Keyboard::Key key) final; + }; + private: + // MARK: - Key queue. + std::mutex key_queue_mutex_; + std::vector key_queue_; + // MARK: - Serial line state. int bit_count_ = 0; int command_ = 0;