diff --git a/Analyser/Dynamic/MultiMachine/Implementation/MultiKeyboardMachine.cpp b/Analyser/Dynamic/MultiMachine/Implementation/MultiKeyboardMachine.cpp index 42d0c0835..c27794e76 100644 --- a/Analyser/Dynamic/MultiMachine/Implementation/MultiKeyboardMachine.cpp +++ b/Analyser/Dynamic/MultiMachine/Implementation/MultiKeyboardMachine.cpp @@ -56,10 +56,12 @@ MultiKeyboardMachine::MultiKeyboard::MultiKeyboard(const std::vector<::KeyboardM } } -void MultiKeyboardMachine::MultiKeyboard::set_key_pressed(Key key, char value, bool is_pressed) { +bool MultiKeyboardMachine::MultiKeyboard::set_key_pressed(Key key, char value, bool is_pressed) { + bool was_consumed = false; for(const auto &machine: machines_) { - machine->get_keyboard().set_key_pressed(key, value, is_pressed); + was_consumed |= machine->get_keyboard().set_key_pressed(key, value, is_pressed); } + return was_consumed; } void MultiKeyboardMachine::MultiKeyboard::reset_all_keys() { diff --git a/Analyser/Dynamic/MultiMachine/Implementation/MultiKeyboardMachine.hpp b/Analyser/Dynamic/MultiMachine/Implementation/MultiKeyboardMachine.hpp index a828546fe..bc0803d83 100644 --- a/Analyser/Dynamic/MultiMachine/Implementation/MultiKeyboardMachine.hpp +++ b/Analyser/Dynamic/MultiMachine/Implementation/MultiKeyboardMachine.hpp @@ -32,7 +32,7 @@ class MultiKeyboardMachine: public KeyboardMachine::Machine { public: MultiKeyboard(const std::vector<::KeyboardMachine::Machine *> &machines); - void set_key_pressed(Key key, char value, bool is_pressed) final; + bool set_key_pressed(Key key, char value, bool is_pressed) final; void reset_all_keys() final; const std::set &observed_keys() final; bool is_exclusive() final; diff --git a/Inputs/Keyboard.cpp b/Inputs/Keyboard.cpp index 6193a5ff8..7c9ff819d 100644 --- a/Inputs/Keyboard.cpp +++ b/Inputs/Keyboard.cpp @@ -19,14 +19,15 @@ Keyboard::Keyboard(const std::set &essential_modifiers) : essential_modifie Keyboard::Keyboard(const std::set &observed_keys, const std::set &essential_modifiers) : observed_keys_(observed_keys), essential_modifiers_(essential_modifiers), is_exclusive_(false) {} -void Keyboard::set_key_pressed(Key key, char value, bool is_pressed) { +bool Keyboard::set_key_pressed(Key key, char value, bool is_pressed) { std::size_t key_offset = static_cast(key); if(key_offset >= key_states_.size()) { key_states_.resize(key_offset+1, false); } key_states_[key_offset] = is_pressed; - if(delegate_) delegate_->keyboard_did_change_key(this, key, is_pressed); + if(delegate_) return delegate_->keyboard_did_change_key(this, key, is_pressed); + return false; } const std::set &Keyboard::get_essential_modifiers() { diff --git a/Inputs/Keyboard.hpp b/Inputs/Keyboard.hpp index 28e5054f1..3011ed826 100644 --- a/Inputs/Keyboard.hpp +++ b/Inputs/Keyboard.hpp @@ -45,7 +45,9 @@ class Keyboard { Keyboard(const std::set &observed_keys, const std::set &essential_modifiers); // Host interface. - virtual void set_key_pressed(Key key, char value, bool is_pressed); + + /// @returns @c true if the key press affects the machine; @c false otherwise. + virtual bool set_key_pressed(Key key, char value, bool is_pressed); virtual void reset_all_keys(); /// @returns a set of all Keys that this keyboard responds to. @@ -68,7 +70,7 @@ class Keyboard { // Delegate interface. struct Delegate { - virtual void keyboard_did_change_key(Keyboard *keyboard, Key key, bool is_pressed) = 0; + virtual bool keyboard_did_change_key(Keyboard *keyboard, Key key, bool is_pressed) = 0; virtual void reset_all_keys(Keyboard *keyboard) = 0; }; void set_delegate(Delegate *delegate); diff --git a/Machines/AmstradCPC/Keyboard.cpp b/Machines/AmstradCPC/Keyboard.cpp index 8b49d9d61..8850f52ed 100644 --- a/Machines/AmstradCPC/Keyboard.cpp +++ b/Machines/AmstradCPC/Keyboard.cpp @@ -13,7 +13,9 @@ using namespace AmstradCPC; uint16_t KeyboardMapper::mapped_key_for_key(Inputs::Keyboard::Key key) { #define BIND(source, dest) case Inputs::Keyboard::Key::source: return dest switch(key) { - default: return KeyCopy; + default: break; + + BIND(BackTick, KeyCopy); BIND(k0, Key0); BIND(k1, Key1); BIND(k2, Key2); BIND(k3, Key3); BIND(k4, Key4); BIND(k5, Key5); BIND(k6, Key6); BIND(k7, Key7); BIND(k8, Key8); BIND(k9, Key9); @@ -72,6 +74,7 @@ uint16_t KeyboardMapper::mapped_key_for_key(Inputs::Keyboard::Key key) { BIND(KeypadDelete, KeyDelete); } #undef BIND + return KeyboardMachine::MappedMachine::KeyNotMapped; } uint16_t *CharacterMapper::sequence_for_character(char character) { @@ -142,7 +145,7 @@ uint16_t *CharacterMapper::sequence_for_character(char character) { /* x */ KEYS(KeyX), /* y */ KEYS(KeyY), /* z */ KEYS(KeyZ), /* { */ X, /* | */ SHIFT(KeyAt), /* } */ X, - /* ~ */ X, /* DEL */ KEYS(KeyDelete), + /* ~ */ X }; #undef KEYS #undef SHIFT diff --git a/Machines/Apple/AppleII/AppleII.cpp b/Machines/Apple/AppleII/AppleII.cpp index 0e1a3c037..3c6c25c44 100644 --- a/Machines/Apple/AppleII/AppleII.cpp +++ b/Machines/Apple/AppleII/AppleII.cpp @@ -811,18 +811,18 @@ template class ConcreteMachine: open_apple_is_pressed_ = closed_apple_is_pressed_ = key_is_down_ = false; } - void set_key_pressed(Key key, char value, bool is_pressed) final { + bool set_key_pressed(Key key, char value, bool is_pressed) final { switch(key) { default: break; case Key::F12: m6502_.set_reset_line(is_pressed); - return; + return true; case Key::LeftOption: open_apple_is_pressed_ = is_pressed; - return; + return true; case Key::RightOption: closed_apple_is_pressed_ = is_pressed; - return; + return true; } // If no ASCII value is supplied, look for a few special cases. @@ -833,7 +833,7 @@ template class ConcreteMachine: case Key::Down: value = 0x0a; break; case Key::Up: value = 0x0b; break; case Key::Backspace: value = 0x7f; break; - default: return; + default: return false; } } @@ -848,6 +848,8 @@ template class ConcreteMachine: key_is_down_ = false; } } + + return true; } Inputs::Keyboard &get_keyboard() final { diff --git a/Machines/Electron/Electron.cpp b/Machines/Electron/Electron.cpp index 89c6793b8..a9f91d1c0 100644 --- a/Machines/Electron/Electron.cpp +++ b/Machines/Electron/Electron.cpp @@ -62,7 +62,7 @@ class ConcreteMachine: set_clock_rate(2000000); speaker_.set_input_rate(2000000 / SoundGenerator::clock_rate_divider); - speaker_.set_high_frequency_cutoff(7000); + speaker_.set_high_frequency_cutoff(6000); const std::string machine_name = "Electron"; std::vector required_roms = { diff --git a/Machines/Electron/Keyboard.cpp b/Machines/Electron/Keyboard.cpp index 1ecd358f4..3ed607ead 100644 --- a/Machines/Electron/Keyboard.cpp +++ b/Machines/Electron/Keyboard.cpp @@ -13,7 +13,9 @@ using namespace Electron; uint16_t KeyboardMapper::mapped_key_for_key(Inputs::Keyboard::Key key) { #define BIND(source, dest) case Inputs::Keyboard::Key::source: return Electron::Key::dest switch(key) { - default: return KeyCopy; + default: break; + + BIND(BackTick, KeyCopy); BIND(k0, Key0); BIND(k1, Key1); BIND(k2, Key2); BIND(k3, Key3); BIND(k4, Key4); BIND(k5, Key5); BIND(k6, Key6); BIND(k7, Key7); BIND(k8, Key8); BIND(k9, Key9); @@ -52,6 +54,7 @@ uint16_t KeyboardMapper::mapped_key_for_key(Inputs::Keyboard::Key key) { BIND(Space, KeySpace); } #undef BIND + return KeyboardMachine::MappedMachine::KeyNotMapped; } uint16_t *CharacterMapper::sequence_for_character(char character) { @@ -123,7 +126,7 @@ uint16_t *CharacterMapper::sequence_for_character(char character) { /* x */ SHIFT(KeyX), /* y */ SHIFT(KeyY), /* z */ SHIFT(KeyZ), /* { */ CTRL(KeyUp), /* | */ SHIFT(KeyRight), /* } */ CTRL(KeyDown), - /* ~ */ CTRL(KeyLeft), /* DEL */ KEYS(KeyDelete), + /* ~ */ CTRL(KeyLeft) }; #undef KEYS #undef SHIFT diff --git a/Machines/KeyboardMachine.cpp b/Machines/KeyboardMachine.cpp index 0d79387ee..1a60103d6 100644 --- a/Machines/KeyboardMachine.cpp +++ b/Machines/KeyboardMachine.cpp @@ -14,9 +14,11 @@ MappedMachine::MappedMachine(const std::set &essential_mo keyboard_.set_delegate(this); } -void MappedMachine::keyboard_did_change_key(Inputs::Keyboard *keyboard, Inputs::Keyboard::Key key, bool is_pressed) { +bool MappedMachine::keyboard_did_change_key(Inputs::Keyboard *keyboard, Inputs::Keyboard::Key key, bool is_pressed) { uint16_t mapped_key = get_keyboard_mapper()->mapped_key_for_key(key); - if(mapped_key != KeyNotMapped) set_key_state(mapped_key, is_pressed); + if(mapped_key == KeyNotMapped) return false; + set_key_state(mapped_key, is_pressed); + return true; } void MappedMachine::reset_all_keys(Inputs::Keyboard *keyboard) { diff --git a/Machines/KeyboardMachine.hpp b/Machines/KeyboardMachine.hpp index e4af3adb1..a84f53fb0 100644 --- a/Machines/KeyboardMachine.hpp +++ b/Machines/KeyboardMachine.hpp @@ -95,7 +95,7 @@ class MappedMachine: public Inputs::Keyboard::Delegate, public Machine { virtual Inputs::Keyboard &get_keyboard() override; private: - void keyboard_did_change_key(Inputs::Keyboard *keyboard, Inputs::Keyboard::Key key, bool is_pressed) override; + bool keyboard_did_change_key(Inputs::Keyboard *keyboard, Inputs::Keyboard::Key key, bool is_pressed) override; void reset_all_keys(Inputs::Keyboard *keyboard) override; Inputs::Keyboard keyboard_; }; diff --git a/Machines/MasterSystem/MasterSystem.cpp b/Machines/MasterSystem/MasterSystem.cpp index ce98a0bf8..ea4d46cfb 100644 --- a/Machines/MasterSystem/MasterSystem.cpp +++ b/Machines/MasterSystem/MasterSystem.cpp @@ -355,12 +355,18 @@ class ConcreteMachine: return keyboard_; } - void keyboard_did_change_key(Inputs::Keyboard *, Inputs::Keyboard::Key key, bool is_pressed) final { + bool keyboard_did_change_key(Inputs::Keyboard *, Inputs::Keyboard::Key key, bool is_pressed) final { if(key == Inputs::Keyboard::Key::Enter) { pause_is_pressed_ = is_pressed; - } else if(key == Inputs::Keyboard::Key::Escape) { - reset_is_pressed_ = is_pressed; + return true; } + + if(key == Inputs::Keyboard::Key::Escape) { + reset_is_pressed_ = is_pressed; + return true; + } + + return false; } void reset_all_keys(Inputs::Keyboard *) final { diff --git a/Machines/ZX8081/Keyboard.cpp b/Machines/ZX8081/Keyboard.cpp index 5dac570e4..2a0291d65 100644 --- a/Machines/ZX8081/Keyboard.cpp +++ b/Machines/ZX8081/Keyboard.cpp @@ -32,6 +32,11 @@ uint16_t KeyboardMapper::mapped_key_for_key(Inputs::Keyboard::Key key) { // Virtual keys follow. BIND(Backspace, KeyDelete); BIND(Escape, KeyBreak); + BIND(Up, KeyUp); + BIND(Down, KeyDown); + BIND(Left, KeyLeft); + BIND(Right, KeyRight); + BIND(BackTick, KeyEdit); BIND(F1, KeyEdit); } #undef BIND return KeyboardMachine::MappedMachine::KeyNotMapped; diff --git a/Machines/ZX8081/Keyboard.hpp b/Machines/ZX8081/Keyboard.hpp index 294787c9b..50fcfeda3 100644 --- a/Machines/ZX8081/Keyboard.hpp +++ b/Machines/ZX8081/Keyboard.hpp @@ -26,7 +26,7 @@ enum Key: uint16_t { // Add some virtual keys; these do not exist on a real ZX80 or ZX81. They're just a convenience. KeyDelete = 0x0801, - KeyBreak = 0x0802, + KeyBreak, KeyLeft, KeyRight, KeyUp, KeyDown, KeyEdit }; struct KeyboardMapper: public KeyboardMachine::MappedMachine::KeyboardMapper { diff --git a/Machines/ZX8081/ZX8081.cpp b/Machines/ZX8081/ZX8081.cpp index 8afde474e..9b773e9ec 100644 --- a/Machines/ZX8081/ZX8081.cpp +++ b/Machines/ZX8081/ZX8081.cpp @@ -353,19 +353,22 @@ template class ConcreteMachine: const auto line = key >> 8; // Check for special cases. - if(line == 8) { + if(line > 7) { switch(key) { - case KeyDelete: - // Map delete to shift+0. - set_key_state(KeyShift, is_pressed); - set_key_state(Key0, is_pressed); +#define ShiftedKey(source, base) \ + case source: \ + set_key_state(KeyShift, is_pressed); \ + set_key_state(base, is_pressed); \ break; - case KeyBreak: - // Map break to shift+space. - set_key_state(KeyShift, is_pressed); - set_key_state(KeySpace, is_pressed); - break; + ShiftedKey(KeyDelete, Key0); + ShiftedKey(KeyBreak, KeySpace); + ShiftedKey(KeyUp, Key7); + ShiftedKey(KeyDown, Key6); + ShiftedKey(KeyLeft, Key5); + ShiftedKey(KeyRight, Key8); + ShiftedKey(KeyEdit, Key1); +#undef ShiftedKey } } else { if(is_pressed) diff --git a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm index 35f5dfb81..5992b9fae 100644 --- a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm +++ b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm @@ -504,10 +504,21 @@ struct ActivityObserver: public Activity::Observer { } } - // If this is logical mode and this key maps to a symbol, supply it - // as something to type. If this isn't logical mode, or this key doesn't - // map to a symbol, pass it along as a standard press. - if(self.inputMode == CSMachineKeyboardInputModeKeyboardLogical) { + // Decide whether to try to 'type' (in the logical mapping sense) in the first instance. + bool shouldTryToType = self.inputMode == CSMachineKeyboardInputModeKeyboardLogical; + + // Even if the default wasn't to try to type, have a go anyway if the key wasn't + // recognised directly. E.g. if the user hits their square bracket key on a machine that + // doesn't have a correspondingly-placed key, then try to type a square bracket. + if(!shouldTryToType) { + @synchronized(self) { + shouldTryToType = !keyboard.set_key_pressed(mapped_key, pressedKey, isPressed); + } + } + + // If this should try to type, give that a go. But typing may fail, e.g. because the user + // has pressed something like the cursor keys, which don't actually map to a typeable symbol. + if(shouldTryToType) { @synchronized(self) { if(pressedKey && keyboard_machine->can_type(pressedKey)) { if(isPressed) { @@ -517,10 +528,12 @@ struct ActivityObserver: public Activity::Observer { return; } } - } - @synchronized(self) { - keyboard.set_key_pressed(mapped_key, pressedKey, isPressed); + // Okay, so at this point either: set_key_pressed was already tried but will fail anyway, + // or else it hasn't been tried yet and is worth a go. + @synchronized(self) { + shouldTryToType = !keyboard.set_key_pressed(mapped_key, pressedKey, isPressed); + } } return;