From 9344f6a824fde825c021d71c1e1504053153e027 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 28 Dec 2023 15:05:55 -0500 Subject: [PATCH] Indicate whether a keypress is a repeat. Treat appropriately in the Apple II. --- .../Implementation/MultiKeyboardMachine.cpp | 4 ++-- .../Implementation/MultiKeyboardMachine.hpp | 2 +- Inputs/Keyboard.cpp | 2 +- Inputs/Keyboard.hpp | 2 +- Machines/Apple/AppleII/AppleII.cpp | 14 ++++++++++++-- Machines/KeyboardMachine.hpp | 6 +++--- .../Clock Signal/Documents/MachineDocument.swift | 12 ++++++------ OSBindings/Mac/Clock Signal/Machine/CSMachine.h | 2 +- OSBindings/Mac/Clock Signal/Machine/CSMachine.mm | 10 ++++++++-- OSBindings/Qt/mainwindow.cpp | 2 +- OSBindings/SDL/main.cpp | 5 +++-- 11 files changed, 39 insertions(+), 22 deletions(-) diff --git a/Analyser/Dynamic/MultiMachine/Implementation/MultiKeyboardMachine.cpp b/Analyser/Dynamic/MultiMachine/Implementation/MultiKeyboardMachine.cpp index d2557968a..d5a42ba5b 100644 --- a/Analyser/Dynamic/MultiMachine/Implementation/MultiKeyboardMachine.cpp +++ b/Analyser/Dynamic/MultiMachine/Implementation/MultiKeyboardMachine.cpp @@ -56,10 +56,10 @@ MultiKeyboardMachine::MultiKeyboard::MultiKeyboard(const std::vector<::MachineTy } } -bool 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 is_repeat) { bool was_consumed = false; for(const auto &machine: machines_) { - was_consumed |= machine->get_keyboard().set_key_pressed(key, value, is_pressed); + was_consumed |= machine->get_keyboard().set_key_pressed(key, value, is_pressed, is_repeat); } return was_consumed; } diff --git a/Analyser/Dynamic/MultiMachine/Implementation/MultiKeyboardMachine.hpp b/Analyser/Dynamic/MultiMachine/Implementation/MultiKeyboardMachine.hpp index c01b93c57..c0bee0596 100644 --- a/Analyser/Dynamic/MultiMachine/Implementation/MultiKeyboardMachine.hpp +++ b/Analyser/Dynamic/MultiMachine/Implementation/MultiKeyboardMachine.hpp @@ -31,7 +31,7 @@ class MultiKeyboardMachine: public MachineTypes::KeyboardMachine { public: MultiKeyboard(const std::vector &machines); - bool set_key_pressed(Key key, char value, bool is_pressed) final; + bool set_key_pressed(Key key, char value, bool is_pressed, bool is_repeat) final; void reset_all_keys() final; const std::set &observed_keys() const final; bool is_exclusive() const final; diff --git a/Inputs/Keyboard.cpp b/Inputs/Keyboard.cpp index f58bca83a..7abdb87e5 100644 --- a/Inputs/Keyboard.cpp +++ b/Inputs/Keyboard.cpp @@ -21,7 +21,7 @@ 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) {} -bool Keyboard::set_key_pressed(Key key, char, bool is_pressed) { +bool Keyboard::set_key_pressed(Key key, char, bool is_pressed, bool) { const size_t key_offset = size_t(key); if(key_offset >= key_states_.size()) { key_states_.resize(key_offset+1, false); diff --git a/Inputs/Keyboard.hpp b/Inputs/Keyboard.hpp index 0b4a4120c..3dcbb5cc5 100644 --- a/Inputs/Keyboard.hpp +++ b/Inputs/Keyboard.hpp @@ -51,7 +51,7 @@ class Keyboard { // Host interface. /// @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 bool set_key_pressed(Key key, char value, bool is_pressed, bool is_repeat); virtual void reset_all_keys(); /// @returns a set of all Keys that this keyboard responds to. diff --git a/Machines/Apple/AppleII/AppleII.cpp b/Machines/Apple/AppleII/AppleII.cpp index 292323433..b3f915848 100644 --- a/Machines/Apple/AppleII/AppleII.cpp +++ b/Machines/Apple/AppleII/AppleII.cpp @@ -279,7 +279,12 @@ template class ConcreteMachine: open_apple_is_pressed = closed_apple_is_pressed = control_is_pressed = shift_is_pressed = key_is_down = false; } - bool set_key_pressed(Key key, char value, bool is_pressed) final { + bool set_key_pressed(Key key, char value, bool is_pressed, bool is_repeat) final { + // TODO: unless a repeat key is pressed or this is a IIe. + if constexpr (!is_iie()) { + if(is_repeat && !repeat_is_pressed) return true; + } + // If no ASCII value is supplied, look for a few special cases. switch(key) { case Key::Left: value = 0x08; break; @@ -333,7 +338,11 @@ template class ConcreteMachine: case Key::F1: case Key::F2: case Key::F3: case Key::F4: case Key::F5: case Key::F6: case Key::F7: case Key::F8: - case Key::F9: case Key::F10: case Key::F11: case Key::F12: + case Key::F9: case Key::F10: case Key::F11: + repeat_is_pressed = is_pressed; + return true; + + case Key::F12: case Key::PrintScreen: case Key::ScrollLock: case Key::Pause: @@ -402,6 +411,7 @@ template class ConcreteMachine: } } + bool repeat_is_pressed = false; bool shift_is_pressed = false; bool control_is_pressed = false; // The IIe has three keys that are wired directly to the same input as the joystick buttons. diff --git a/Machines/KeyboardMachine.hpp b/Machines/KeyboardMachine.hpp index 81c0918b1..57e655112 100644 --- a/Machines/KeyboardMachine.hpp +++ b/Machines/KeyboardMachine.hpp @@ -75,12 +75,12 @@ class KeyboardMachine: public KeyActions { (i) if @c symbol can be typed and this is a key down, @c type_string it; (ii) if @c symbol cannot be typed, set @c key as @c is_pressed */ - bool apply_key(Inputs::Keyboard::Key key, char symbol, bool is_pressed, bool map_logically) { + bool apply_key(Inputs::Keyboard::Key key, char symbol, bool is_pressed, bool is_repeat, bool map_logically) { Inputs::Keyboard &keyboard = get_keyboard(); if(!map_logically) { // Try a regular keypress first, and stop if that works. - if(keyboard.set_key_pressed(key, symbol, is_pressed)) { + if(keyboard.set_key_pressed(key, symbol, is_pressed, is_repeat)) { return true; } @@ -103,7 +103,7 @@ class KeyboardMachine: public KeyActions { // That didn't work. Forward as a keypress. As, either: // (i) this is a key down, but doesn't have a symbol, or is an untypeable symbol; or // (ii) this is a key up, which it won't be an issue to miscommunicate. - return keyboard.set_key_pressed(key, symbol, is_pressed); + return keyboard.set_key_pressed(key, symbol, is_pressed, is_repeat); } } }; diff --git a/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift b/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift index cefc57dac..c8c0e81dd 100644 --- a/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift +++ b/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift @@ -345,14 +345,14 @@ class MachineDocument: /// Forwards key down events directly to the machine. func keyDown(_ event: NSEvent) { if let machine = self.machine { - machine.setKey(event.keyCode, characters: event.characters, isPressed: true) + machine.setKey(event.keyCode, characters: event.characters, isPressed: true, isRepeat: event.isARepeat) } } /// Forwards key up events directly to the machine. func keyUp(_ event: NSEvent) { if let machine = self.machine { - machine.setKey(event.keyCode, characters: event.characters, isPressed: false) + machine.setKey(event.keyCode, characters: event.characters, isPressed: false, isRepeat: false) } } @@ -361,19 +361,19 @@ class MachineDocument: if let machine = self.machine { if newModifiers.modifierFlags.contains(.shift) != shiftIsDown { shiftIsDown = newModifiers.modifierFlags.contains(.shift) - machine.setKey(VK_Shift, characters: nil, isPressed: shiftIsDown) + machine.setKey(VK_Shift, characters: nil, isPressed: shiftIsDown, isRepeat: false) } if newModifiers.modifierFlags.contains(.control) != controlIsDown { controlIsDown = newModifiers.modifierFlags.contains(.control) - machine.setKey(VK_Control, characters: nil, isPressed: controlIsDown) + machine.setKey(VK_Control, characters: nil, isPressed: controlIsDown, isRepeat: false) } if newModifiers.modifierFlags.contains(.command) != commandIsDown { commandIsDown = newModifiers.modifierFlags.contains(.command) - machine.setKey(VK_Command, characters: nil, isPressed: commandIsDown) + machine.setKey(VK_Command, characters: nil, isPressed: commandIsDown, isRepeat: false) } if newModifiers.modifierFlags.contains(.option) != optionIsDown { optionIsDown = newModifiers.modifierFlags.contains(.option) - machine.setKey(VK_Option, characters: nil, isPressed: optionIsDown) + machine.setKey(VK_Option, characters: nil, isPressed: optionIsDown, isRepeat: false) } } } diff --git a/OSBindings/Mac/Clock Signal/Machine/CSMachine.h b/OSBindings/Mac/Clock Signal/Machine/CSMachine.h index ae801b5f1..eb4aaa143 100644 --- a/OSBindings/Mac/Clock Signal/Machine/CSMachine.h +++ b/OSBindings/Mac/Clock Signal/Machine/CSMachine.h @@ -67,7 +67,7 @@ typedef NS_ENUM(NSInteger, CSMachineKeyboardInputMode) { - (void)start; - (void)stop; -- (void)setKey:(uint16_t)key characters:(nullable NSString *)characters isPressed:(BOOL)isPressed; +- (void)setKey:(uint16_t)key characters:(nullable NSString *)characters isPressed:(BOOL)isPressed isRepeat:(BOOL)isRepeat; - (void)clearAllKeys; - (void)setMouseButton:(int)button isPressed:(BOOL)isPressed; diff --git a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm index 3331eb969..1a49f67b0 100644 --- a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm +++ b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm @@ -366,7 +366,7 @@ struct ActivityObserver: public Activity::Observer { [self updateJoystickTimer]; } -- (void)setKey:(uint16_t)key characters:(NSString *)characters isPressed:(BOOL)isPressed { +- (void)setKey:(uint16_t)key characters:(NSString *)characters isPressed:(BOOL)isPressed isRepeat:(BOOL)isRepeat { [self applyInputEvent:^{ auto keyboard_machine = self->_machine->keyboard_machine(); if(keyboard_machine && (self.inputMode != CSMachineKeyboardInputModeJoystick || !keyboard_machine->get_keyboard().is_exclusive())) { @@ -437,7 +437,13 @@ struct ActivityObserver: public Activity::Observer { } @synchronized(self) { - if(keyboard_machine->apply_key(mapped_key, pressedKey, isPressed, self.inputMode == CSMachineKeyboardInputModeKeyboardLogical)) { + if(keyboard_machine->apply_key( + mapped_key, + pressedKey, + isPressed, + isRepeat, + self.inputMode == CSMachineKeyboardInputModeKeyboardLogical) + ) { return; } } diff --git a/OSBindings/Qt/mainwindow.cpp b/OSBindings/Qt/mainwindow.cpp index 1e36e338c..f46df4ae8 100644 --- a/OSBindings/Qt/mainwindow.cpp +++ b/OSBindings/Qt/mainwindow.cpp @@ -889,7 +889,7 @@ bool MainWindow::processEvent(QKeyEvent *event) { if(!keyboardMachine) return true; auto &keyboard = keyboardMachine->get_keyboard(); - keyboard.set_key_pressed(*key, event->text().size() ? event->text()[0].toLatin1() : '\0', isPressed); + keyboard.set_key_pressed(*key, event->text().size() ? event->text()[0].toLatin1() : '\0', isPressed, false); if(keyboard.is_exclusive() || keyboard.observed_keys().find(*key) != keyboard.observed_keys().end()) { return false; } diff --git a/OSBindings/SDL/main.cpp b/OSBindings/SDL/main.cpp index d0c253d30..f29160286 100644 --- a/OSBindings/SDL/main.cpp +++ b/OSBindings/SDL/main.cpp @@ -1214,14 +1214,15 @@ int main(int argc, char *argv[]) { // is sufficiently untested on SDL, and somewhat too reliant on empirical timestamp behaviour, // for it to be trustworthy enough otherwise to expose. if(logical_keyboard) { - if(keyboard_machine->apply_key(key, keypress.input.size() ? keypress.input[0] : 0, keypress.is_down, logical_keyboard)) { + // TODO: is_repeat. + if(keyboard_machine->apply_key(key, keypress.input.size() ? keypress.input[0] : 0, keypress.is_down, keypress.repeat, logical_keyboard)) { continue; } } else { // This is a slightly terrible way of obtaining a symbol for the key, e.g. for letters it will always return // the capital letter version, at least empirically. But it'll have to do for now. const char *key_name = SDL_GetKeyName(keypress.keycode); - if(keyboard_machine->get_keyboard().set_key_pressed(key, (strlen(key_name) == 1) ? key_name[0] : 0, keypress.is_down)) { + if(keyboard_machine->get_keyboard().set_key_pressed(key, (strlen(key_name) == 1) ? key_name[0] : 0, keypress.is_down, keypress.repeat)) { continue; } }