diff --git a/Machines/AmstradCPC/Keyboard.cpp b/Machines/AmstradCPC/Keyboard.cpp index f3476505f..58340d4cc 100644 --- a/Machines/AmstradCPC/Keyboard.cpp +++ b/Machines/AmstradCPC/Keyboard.cpp @@ -150,3 +150,7 @@ uint16_t *CharacterMapper::sequence_for_character(char character) { return table_lookup_sequence_for_character(key_sequences, sizeof(key_sequences), character); } + +bool CharacterMapper::needs_pause_after_key(uint16_t key) { + return key != KeyControl && key != KeyShift; +} diff --git a/Machines/AmstradCPC/Keyboard.hpp b/Machines/AmstradCPC/Keyboard.hpp index 65544faba..5aadbf5e3 100644 --- a/Machines/AmstradCPC/Keyboard.hpp +++ b/Machines/AmstradCPC/Keyboard.hpp @@ -38,7 +38,10 @@ struct KeyboardMapper: public KeyboardMachine::MappedMachine::KeyboardMapper { }; struct CharacterMapper: public ::Utility::CharacterMapper { - uint16_t *sequence_for_character(char character); + uint16_t *sequence_for_character(char character) override; + + bool needs_pause_after_reset_all_keys() override { return false; } + bool needs_pause_after_key(uint16_t key) override; }; }; diff --git a/Machines/Utility/Typer.cpp b/Machines/Utility/Typer.cpp index 20d5a345e..3c35ab0f7 100644 --- a/Machines/Utility/Typer.cpp +++ b/Machines/Utility/Typer.cpp @@ -74,31 +74,51 @@ const uint16_t *Typer::sequence_for_character(char c) const { return sequence; } -bool Typer::try_type_next_character() { +uint16_t Typer::try_type_next_character() { const uint16_t *const sequence = sequence_for_character(string_[string_pointer_]); if(!sequence) { - return false; + return 0; } - if(!phase_) delegate_->clear_all_keys(); - else { - delegate_->set_key_state(sequence[phase_ - 1], true); - return sequence[phase_] != KeyboardMachine::MappedMachine::KeyEndSequence; + // If this is the start of the output sequence, start with a reset all keys. + // Then pause unless the caracter mapper says not to. + if(!phase_) { + delegate_->clear_all_keys(); + if(character_mapper_->needs_pause_after_reset_all_keys()) { + return 0xffff; // Arbitrarily. Anything non-zero will do. + } } - return true; + // Advance phase. + ++phase_; + + // If the sequence is over, stop. + if(sequence[phase_ - 1] == KeyboardMachine::MappedMachine::KeyEndSequence) { + return 0; + } + + // Otherwise, type the key. + delegate_->set_key_state(sequence[phase_ - 1], true); + + return sequence[phase_ - 1]; } bool Typer::type_next_character() { if(string_pointer_ == string_.size()) return false; - if(!try_type_next_character()) { - phase_ = 0; - ++string_pointer_; - if(string_pointer_ == string_.size()) return false; - } else { - ++phase_; + while(true) { + const uint16_t key_pressed = try_type_next_character(); + + if(!key_pressed) { + phase_ = 0; + ++string_pointer_; + if(string_pointer_ == string_.size()) return false; + } + + if(character_mapper_->needs_pause_after_key(key_pressed)) { + break; + } } return true; diff --git a/Machines/Utility/Typer.hpp b/Machines/Utility/Typer.hpp index 90eb21d9b..19b872a9f 100644 --- a/Machines/Utility/Typer.hpp +++ b/Machines/Utility/Typer.hpp @@ -28,6 +28,18 @@ class CharacterMapper { /// @returns The EndSequence-terminated sequence of keys that would cause @c character to be typed. virtual uint16_t *sequence_for_character(char character) = 0; + /// The typer will automatically reset all keys in between each sequence that it types. + /// By default it will pause for one key's duration when doing so. Character mappers + /// can eliminate that pause by overriding this method. + /// @returns @c true if the typer should pause after performing a reset; @c false otherwise. + virtual bool needs_pause_after_reset_all_keys() { return true; } + + /// The typer will pause between every entry in a keyboard sequence. On some machines + /// that may not be necessary — it'll often depends on whether the machine needs time to + /// observe a modifier like shift before it sees the actual keypress. + /// @returns @c true if the typer should pause after forwarding @c key; @c false otherwise. + virtual bool needs_pause_after_key(uint16_t key) { return true; } + protected: typedef uint16_t KeySequence[16]; @@ -81,7 +93,7 @@ class Typer { Delegate *delegate_; std::unique_ptr character_mapper_; - bool try_type_next_character(); + uint16_t try_type_next_character(); const uint16_t *sequence_for_character(char) const; };