From 9344f6a824fde825c021d71c1e1504053153e027 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 28 Dec 2023 15:05:55 -0500 Subject: [PATCH 01/11] 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; } } From ffb992d04ad4cf2b536c3a55b23ddded2765d2d2 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 28 Dec 2023 15:07:39 -0500 Subject: [PATCH 02/11] Erase done TODO. --- Machines/Apple/AppleII/AppleII.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Machines/Apple/AppleII/AppleII.cpp b/Machines/Apple/AppleII/AppleII.cpp index b3f915848..127200666 100644 --- a/Machines/Apple/AppleII/AppleII.cpp +++ b/Machines/Apple/AppleII/AppleII.cpp @@ -280,7 +280,6 @@ template class ConcreteMachine: } 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; } From 2baae216eaea0adfd38c8f9c844269eadfb727ed Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 28 Dec 2023 15:09:45 -0500 Subject: [PATCH 03/11] This TODO is also already dispatched. --- OSBindings/SDL/main.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/OSBindings/SDL/main.cpp b/OSBindings/SDL/main.cpp index f29160286..674ae3aea 100644 --- a/OSBindings/SDL/main.cpp +++ b/OSBindings/SDL/main.cpp @@ -1214,7 +1214,6 @@ 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) { - // TODO: is_repeat. if(keyboard_machine->apply_key(key, keypress.input.size() ? keypress.input[0] : 0, keypress.is_down, keypress.repeat, logical_keyboard)) { continue; } From 21e6f4d8234d2c58d9a2bbf322140f582a04a49c Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 28 Dec 2023 15:12:06 -0500 Subject: [PATCH 04/11] Update SDL intermediate struct. --- OSBindings/SDL/main.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/OSBindings/SDL/main.cpp b/OSBindings/SDL/main.cpp index 674ae3aea..bc93da1f5 100644 --- a/OSBindings/SDL/main.cpp +++ b/OSBindings/SDL/main.cpp @@ -976,9 +976,11 @@ int main(int argc, char *argv[]) { SDL_Scancode scancode = SDL_SCANCODE_UNKNOWN; SDL_Keycode keycode = SDLK_UNKNOWN; bool is_down = true; + bool repeat = false; KeyPress(uint32_t timestamp, const char *text) : timestamp(timestamp), input(text) {} - KeyPress(uint32_t timestamp, SDL_Scancode scancode, SDL_Keycode keycode, bool is_down) : timestamp(timestamp), scancode(scancode), keycode(keycode), is_down(is_down) {} + KeyPress(uint32_t timestamp, SDL_Scancode scancode, SDL_Keycode keycode, bool is_down, bool repeat) : + timestamp(timestamp), scancode(scancode), keycode(keycode), is_down(is_down), repeat(repeat) {} KeyPress() {} }; std::vector keypresses; @@ -1048,7 +1050,7 @@ int main(int argc, char *argv[]) { } break; case SDL_TEXTINPUT: - keypresses.emplace_back(event.text.timestamp, event.text.text); + keypresses.emplace_back(event.text.timestamp, event.text.text, false); break; case SDL_KEYDOWN: @@ -1129,7 +1131,12 @@ int main(int argc, char *argv[]) { break; } - keypresses.emplace_back(event.text.timestamp, event.key.keysym.scancode, event.key.keysym.sym, event.type == SDL_KEYDOWN); + keypresses.emplace_back( + event.text.timestamp, + event.key.keysym.scancode, + event.key.keysym.sym, + event.type == SDL_KEYDOWN, + event.repeat); } break; case SDL_MOUSEBUTTONDOWN: From 1b5b3e575c4c0aadad7aa486e0273bb538520661 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 29 Dec 2023 14:45:48 -0500 Subject: [PATCH 05/11] Add repeat-only functionality. --- Machines/Apple/AppleII/AppleII.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Machines/Apple/AppleII/AppleII.cpp b/Machines/Apple/AppleII/AppleII.cpp index 127200666..3d7286963 100644 --- a/Machines/Apple/AppleII/AppleII.cpp +++ b/Machines/Apple/AppleII/AppleII.cpp @@ -339,6 +339,13 @@ template class ConcreteMachine: case Key::F5: case Key::F6: case Key::F7: case Key::F8: case Key::F9: case Key::F10: case Key::F11: repeat_is_pressed = is_pressed; + + if constexpr (!is_iie()) { + if(is_pressed && !is_repeat) { + value = last_key; + break; + } + } return true; case Key::F12: @@ -391,6 +398,7 @@ template class ConcreteMachine: } if(is_pressed) { + last_key = value; keyboard_input = uint8_t(value | 0x80); key_is_down = true; } else { @@ -410,6 +418,7 @@ template class ConcreteMachine: } } + char last_key = 0; bool repeat_is_pressed = false; bool shift_is_pressed = false; bool control_is_pressed = false; From 051cdc63b8364689b29079f93e2f1ecef43bf2bd Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 29 Dec 2023 14:54:47 -0500 Subject: [PATCH 06/11] Fix SDL build. --- OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj | 2 ++ OSBindings/SDL/main.cpp | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 6a99225bb..3a04d1d79 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -6592,6 +6592,7 @@ "$(inherited)", IGNORE_APPLE, ); + HEADER_SEARCH_PATHS = /Users/thomasharte/Library/Frameworks/SDL2.framework/Headers; LD_RUNPATH_SEARCH_PATHS = "$(USER_LIBRARY_DIR)/Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.13; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -6613,6 +6614,7 @@ NDEBUG, IGNORE_APPLE, ); + HEADER_SEARCH_PATHS = /Users/thomasharte/Library/Frameworks/SDL2.framework/Headers; LD_RUNPATH_SEARCH_PATHS = "$(USER_LIBRARY_DIR)/Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.13; ONLY_ACTIVE_ARCH = YES; diff --git a/OSBindings/SDL/main.cpp b/OSBindings/SDL/main.cpp index bc93da1f5..1da6e2c8f 100644 --- a/OSBindings/SDL/main.cpp +++ b/OSBindings/SDL/main.cpp @@ -1050,7 +1050,7 @@ int main(int argc, char *argv[]) { } break; case SDL_TEXTINPUT: - keypresses.emplace_back(event.text.timestamp, event.text.text, false); + keypresses.emplace_back(event.text.timestamp, event.text.text); break; case SDL_KEYDOWN: @@ -1136,7 +1136,7 @@ int main(int argc, char *argv[]) { event.key.keysym.scancode, event.key.keysym.sym, event.type == SDL_KEYDOWN, - event.repeat); + event.key.repeat); } break; case SDL_MOUSEBUTTONDOWN: From 4f846ef8d07314ce2a22488c733de132b19683a1 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 31 Dec 2023 15:11:45 -0500 Subject: [PATCH 07/11] Remove absolute path. --- OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 3a04d1d79..61a2c8c82 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -6592,7 +6592,7 @@ "$(inherited)", IGNORE_APPLE, ); - HEADER_SEARCH_PATHS = /Users/thomasharte/Library/Frameworks/SDL2.framework/Headers; + HEADER_SEARCH_PATHS = "$(USER_LIBRARY_DIR)/Frameworks/SDL2.framework/Headers"; LD_RUNPATH_SEARCH_PATHS = "$(USER_LIBRARY_DIR)/Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.13; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -6614,7 +6614,7 @@ NDEBUG, IGNORE_APPLE, ); - HEADER_SEARCH_PATHS = /Users/thomasharte/Library/Frameworks/SDL2.framework/Headers; + HEADER_SEARCH_PATHS = "$(USER_LIBRARY_DIR)/Frameworks/SDL2.framework/Headers"; LD_RUNPATH_SEARCH_PATHS = "$(USER_LIBRARY_DIR)/Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.13; ONLY_ACTIVE_ARCH = YES; From a58f643b4de8a1d17dd3be67018062440dd01f4a Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 31 Dec 2023 15:21:20 -0500 Subject: [PATCH 08/11] Improve repeat behaviour. --- Machines/Apple/AppleII/AppleII.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Machines/Apple/AppleII/AppleII.cpp b/Machines/Apple/AppleII/AppleII.cpp index 3d7286963..aa0b767ab 100644 --- a/Machines/Apple/AppleII/AppleII.cpp +++ b/Machines/Apple/AppleII/AppleII.cpp @@ -341,9 +341,8 @@ template class ConcreteMachine: repeat_is_pressed = is_pressed; if constexpr (!is_iie()) { - if(is_pressed && !is_repeat) { - value = last_key; - break; + if(is_pressed && (!is_repeat || pressed_character)) { + keyboard_input = uint8_t(last_pressed_character | 0x80); } } return true; @@ -398,10 +397,13 @@ template class ConcreteMachine: } if(is_pressed) { - last_key = value; + last_pressed_character = pressed_character = value; keyboard_input = uint8_t(value | 0x80); key_is_down = true; } else { + if(value == pressed_character) { + pressed_character = 0; + } if((keyboard_input & 0x3f) == value) { key_is_down = false; } @@ -418,7 +420,8 @@ template class ConcreteMachine: } } - char last_key = 0; + char pressed_character = 0, last_pressed_character = 0; + bool repeat_is_pressed = false; bool shift_is_pressed = false; bool control_is_pressed = false; From b7e1ac840f17ede487ff4c8f67925e476140ed95 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 31 Dec 2023 16:43:32 -0500 Subject: [PATCH 09/11] Add necessary Qt change. --- OSBindings/Qt/mainwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OSBindings/Qt/mainwindow.cpp b/OSBindings/Qt/mainwindow.cpp index f46df4ae8..c8913c5c0 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, false); + keyboard.set_key_pressed(*key, event->text().size() ? event->text()[0].toLatin1() : '\0', isPressed, event->isAutoRepeat()); if(keyboard.is_exclusive() || keyboard.observed_keys().find(*key) != keyboard.observed_keys().end()) { return false; } From 2698ac2d0ff152f77b7a652946820062faca0a7d Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 1 Jan 2024 09:33:20 -0500 Subject: [PATCH 10/11] Comment and clarify. --- Machines/Apple/AppleII/AppleII.cpp | 54 ++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/Machines/Apple/AppleII/AppleII.cpp b/Machines/Apple/AppleII/AppleII.cpp index aa0b767ab..bb593ba12 100644 --- a/Machines/Apple/AppleII/AppleII.cpp +++ b/Machines/Apple/AppleII/AppleII.cpp @@ -276,12 +276,18 @@ template class ConcreteMachine: Keyboard(Processor *m6502) : m6502_(m6502) {} void reset_all_keys() final { - open_apple_is_pressed = closed_apple_is_pressed = control_is_pressed = shift_is_pressed = key_is_down = false; + open_apple_is_pressed = + closed_apple_is_pressed = + control_is_pressed_ = + shift_is_pressed_ = + repeat_is_pressed_ = + key_is_down = + character_is_pressed_ = false; } bool set_key_pressed(Key key, char value, bool is_pressed, bool is_repeat) final { if constexpr (!is_iie()) { - if(is_repeat && !repeat_is_pressed) return true; + if(is_repeat && !repeat_is_pressed_) return true; } // If no ASCII value is supplied, look for a few special cases. @@ -327,22 +333,22 @@ template class ConcreteMachine: } case Key::LeftControl: - control_is_pressed = is_pressed; + control_is_pressed_ = is_pressed; return true; case Key::LeftShift: case Key::RightShift: - shift_is_pressed = is_pressed; + shift_is_pressed_ = is_pressed; return true; 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: - repeat_is_pressed = is_pressed; + repeat_is_pressed_ = is_pressed; if constexpr (!is_iie()) { - if(is_pressed && (!is_repeat || pressed_character)) { - keyboard_input = uint8_t(last_pressed_character | 0x80); + if(is_pressed && (!is_repeat || character_is_pressed_)) { + keyboard_input = uint8_t(last_pressed_character_ | 0x80); } } return true; @@ -370,10 +376,10 @@ template class ConcreteMachine: // Prior to the IIe, the keyboard could produce uppercase only. if(!is_iie()) value = char(toupper(value)); - if(control_is_pressed && isalpha(value)) value &= 0xbf; + if(control_is_pressed_ && isalpha(value)) value &= 0xbf; // TODO: properly map IIe keys - if(!is_iie() && shift_is_pressed) { + if(!is_iie() && shift_is_pressed_) { switch(value) { case 0x27: value = 0x22; break; // ' -> " case 0x2c: value = 0x3c; break; // , -> < @@ -397,12 +403,13 @@ template class ConcreteMachine: } if(is_pressed) { - last_pressed_character = pressed_character = value; + last_pressed_character_ = value; + character_is_pressed_ = true; keyboard_input = uint8_t(value | 0x80); key_is_down = true; } else { - if(value == pressed_character) { - pressed_character = 0; + if(value == last_pressed_character_) { + character_is_pressed_ = false; } if((keyboard_input & 0x3f) == value) { key_is_down = false; @@ -420,20 +427,33 @@ template class ConcreteMachine: } } - char pressed_character = 0, last_pressed_character = 0; - 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. bool open_apple_is_pressed = false; bool closed_apple_is_pressed = false; + + // Current keyboard input register, as exposed to the programmer; on the IIe the programmer + // can also poll for whether any key is currently down. uint8_t keyboard_input = 0x00; bool key_is_down = false; + + // A string serialiser for receiving copy and paste. std::unique_ptr string_serialiser; private: - Processor *const m6502_; + // ASCII input state, referenced by the REPT key on models before the IIe. + char last_pressed_character_ = 0; + bool character_is_pressed_ = false; + + // The repeat key itself. + bool repeat_is_pressed_ = false; + + // Modifier states. + bool shift_is_pressed_ = false; + bool control_is_pressed_ = false; + + // 6502 connection, for applying the reset button. + Processor *const m6502_; }; Keyboard keyboard_; From 26123bf399b088f4dc9e346b9e71da3a5c00cf36 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 1 Jan 2024 15:15:40 -0500 Subject: [PATCH 11/11] Mostly hide state. --- Machines/Apple/AppleII/AppleII.cpp | 58 +++++++++++++++++------------- 1 file changed, 34 insertions(+), 24 deletions(-) diff --git a/Machines/Apple/AppleII/AppleII.cpp b/Machines/Apple/AppleII/AppleII.cpp index bb593ba12..c4fdb77af 100644 --- a/Machines/Apple/AppleII/AppleII.cpp +++ b/Machines/Apple/AppleII/AppleII.cpp @@ -281,7 +281,7 @@ template class ConcreteMachine: control_is_pressed_ = shift_is_pressed_ = repeat_is_pressed_ = - key_is_down = + key_is_down_ = character_is_pressed_ = false; } @@ -348,7 +348,7 @@ template class ConcreteMachine: if constexpr (!is_iie()) { if(is_pressed && (!is_repeat || character_is_pressed_)) { - keyboard_input = uint8_t(last_pressed_character_ | 0x80); + keyboard_input_ = uint8_t(last_pressed_character_ | 0x80); } } return true; @@ -405,14 +405,14 @@ template class ConcreteMachine: if(is_pressed) { last_pressed_character_ = value; character_is_pressed_ = true; - keyboard_input = uint8_t(value | 0x80); - key_is_down = true; + keyboard_input_ = uint8_t(value | 0x80); + key_is_down_ = true; } else { if(value == last_pressed_character_) { character_is_pressed_ = false; } - if((keyboard_input & 0x3f) == value) { - key_is_down = false; + if((keyboard_input_ & 0x3f) == value) { + key_is_down_ = false; } } @@ -420,27 +420,38 @@ template class ConcreteMachine: } uint8_t get_keyboard_input() { - if(string_serialiser) { - return string_serialiser->head() | 0x80; + if(string_serialiser_) { + return string_serialiser_->head() | 0x80; } else { - return keyboard_input; + return keyboard_input_; } } + void clear_keyboard_input() { + keyboard_input_ &= 0x7f; + if(string_serialiser_ && !string_serialiser_->advance()) { + string_serialiser_.reset(); + } + } + + bool get_key_is_down() { + return key_is_down_; + } + + void set_string_serialiser(std::unique_ptr &&serialiser) { + string_serialiser_ = std::move(serialiser); + } // The IIe has three keys that are wired directly to the same input as the joystick buttons. bool open_apple_is_pressed = false; bool closed_apple_is_pressed = false; - // Current keyboard input register, as exposed to the programmer; on the IIe the programmer - // can also poll for whether any key is currently down. - uint8_t keyboard_input = 0x00; - bool key_is_down = false; - - // A string serialiser for receiving copy and paste. - std::unique_ptr string_serialiser; - private: + // Current keyboard input register, as exposed to the programmer; on the IIe the programmer + // can also poll for whether any key is currently down. + uint8_t keyboard_input_ = 0x00; + bool key_is_down_ = false; + // ASCII input state, referenced by the REPT key on models before the IIe. char last_pressed_character_ = 0; bool character_is_pressed_ = false; @@ -452,6 +463,9 @@ template class ConcreteMachine: bool shift_is_pressed_ = false; bool control_is_pressed_ = false; + // A string serialiser for receiving copy and paste. + std::unique_ptr string_serialiser_; + // 6502 connection, for applying the reset button. Processor *const m6502_; }; @@ -768,15 +782,11 @@ template class ConcreteMachine: break; case 0xc010: - keyboard_.keyboard_input &= 0x7f; - if(keyboard_.string_serialiser) { - if(!keyboard_.string_serialiser->advance()) - keyboard_.string_serialiser.reset(); - } + keyboard_.clear_keyboard_input(); // On the IIe, reading C010 returns additional key info. if(is_iie() && isReadOperation(operation)) { - *value = (keyboard_.key_is_down ? 0x80 : 0x00) | (keyboard_.keyboard_input & 0x7f); + *value = (keyboard_.get_key_is_down() ? 0x80 : 0x00) | (keyboard_.get_keyboard_input() & 0x7f); } break; @@ -920,7 +930,7 @@ template class ConcreteMachine: } void type_string(const std::string &string) final { - keyboard_.string_serialiser = std::make_unique(string, true); + keyboard_.set_string_serialiser(std::make_unique(string, true)); } bool can_type(char c) const final {