diff --git a/Machines/KeyboardMachine.cpp b/Machines/KeyboardMachine.cpp index c6562bee4..ff21ddf44 100644 --- a/Machines/KeyboardMachine.cpp +++ b/Machines/KeyboardMachine.cpp @@ -27,3 +27,6 @@ void Machine::reset_all_keys(Inputs::Keyboard *keyboard) { Inputs::Keyboard &Machine::get_keyboard() { return keyboard_; } + +void Machine::type_string(const std::string &) { +} diff --git a/Machines/KeyboardMachine.hpp b/Machines/KeyboardMachine.hpp index a9522b2eb..375e95b1c 100644 --- a/Machines/KeyboardMachine.hpp +++ b/Machines/KeyboardMachine.hpp @@ -30,6 +30,13 @@ class Machine: public Inputs::Keyboard::Delegate { */ virtual void clear_all_keys() = 0; + /*! + Causes the machine to attempt to type the supplied string. + + This is best effort. Success or failure is permitted to be a function of machine and current state. + */ + virtual void type_string(const std::string &); + /*! Provides a destination for keyboard input. */ diff --git a/Machines/MSX/MSX.cpp b/Machines/MSX/MSX.cpp index 58c161f31..930893570 100644 --- a/Machines/MSX/MSX.cpp +++ b/Machines/MSX/MSX.cpp @@ -139,6 +139,10 @@ class ConcreteMachine: void configure_as_target(const StaticAnalyser::Target &target) override { insert_media(target.media); + + if(target.loading_command.length()) { + type_string(target.loading_command); + } } bool insert_media(const StaticAnalyser::Media &media) override { @@ -160,6 +164,10 @@ class ConcreteMachine: return true; } + void type_string(const std::string &string) override final { + input_text_ += string; + } + void page_memory(uint8_t value) { for(size_t c = 0; c < 4; ++c) { read_pointers_[c] = memory_slots_[value & 3].read_pointers[c]; @@ -296,6 +304,32 @@ class ConcreteMachine: case CPU::Z80::PartialMachineCycle::Interrupt: *cycle.value = 0xff; + + // Take this as a convenient moment to jump into the keyboard buffer, if desired. + if(!input_text_.empty()) { + // TODO: is it safe to assume these addresses? + const int buffer_start = 0xfbf0; + const int buffer_end = 0xfb18; + + int read_address = ram_[0xf3fa] | (ram_[0xf3fb] << 8); + int write_address = ram_[0xf3f8] | (ram_[0xf3f9] << 8); + + const int buffer_size = buffer_end - buffer_start; + int available_space = write_address + buffer_size - read_address - 1; + + const std::size_t characters_to_write = std::min(static_cast(available_space), input_text_.size()); + write_address -= buffer_start; + for(std::size_t c = 0; c < characters_to_write; ++c) { + char character = input_text_[c]; + ram_[write_address + buffer_start] = static_cast(character); + write_address = (write_address + 1) % buffer_size; + } + write_address += buffer_start; + input_text_.erase(input_text_.begin(), input_text_.begin() + static_cast(characters_to_write)); + + ram_[0xf3f8] = static_cast(write_address); + ram_[0xf3f9] = static_cast(write_address >> 8); + } break; default: break; @@ -457,6 +491,7 @@ class ConcreteMachine: uint8_t key_states_[16]; int selected_key_line_ = 0; + std::string input_text_; MSX::KeyboardMapper keyboard_mapper_; }; diff --git a/Machines/Utility/Typer.hpp b/Machines/Utility/Typer.hpp index 2a7f22fc7..cbdca2421 100644 --- a/Machines/Utility/Typer.hpp +++ b/Machines/Utility/Typer.hpp @@ -87,12 +87,6 @@ class TypeRecipient: public Typer::Delegate { typer_.reset(new Typer(string, get_typer_delay(), get_typer_frequency(), std::move(character_mapper), this)); } - /*! - Provided as a hook for subclasses to implement so that external callers can install a typer - without needing inside knowledge as to where the character mapper comes from. - */ - virtual void type_string(const std::string &) = 0; - /*! Provided in order to conform to that part of the Typer::Delegate interface that goes above and beyond KeyboardMachine::Machine; responds to the end of typing by clearing all keys. diff --git a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm index fdf230241..d44d54994 100644 --- a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm +++ b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm @@ -188,9 +188,9 @@ struct MachineDelegate: CRTMachine::Machine::Delegate, public LockProtectedDeleg } - (void)paste:(NSString *)paste { - Utility::TypeRecipient *typeRecipient = _machine->type_recipient(); - if(typeRecipient) - typeRecipient->type_string([paste UTF8String]); + KeyboardMachine::Machine *keyboardMachine = _machine->type_recipient(); + if(keyboardMachine) + keyboardMachine->type_string([paste UTF8String]); } - (void)applyTarget:(const StaticAnalyser::Target &)target { diff --git a/OSBindings/SDL/main.cpp b/OSBindings/SDL/main.cpp index 03d6575cd..e48ef5ebd 100644 --- a/OSBindings/SDL/main.cpp +++ b/OSBindings/SDL/main.cpp @@ -439,9 +439,9 @@ int main(int argc, char *argv[]) { case SDL_KEYDOWN: // Syphon off the key-press if it's control+shift+V (paste). if(event.key.keysym.sym == SDLK_v && (SDL_GetModState()&KMOD_CTRL) && (SDL_GetModState()&KMOD_SHIFT)) { - Utility::TypeRecipient *type_recipient = machine->type_recipient(); + KeyboardMachine::Machine *keyboard_machine = machine->keyboard_machine()(); if(type_recipient) { - type_recipient->type_string(SDL_GetClipboardText()); + keyboard_machine->type_string(SDL_GetClipboardText()); break; } } diff --git a/StaticAnalyser/MSX/StaticAnalyser.cpp b/StaticAnalyser/MSX/StaticAnalyser.cpp index 797007996..3d4d340a0 100644 --- a/StaticAnalyser/MSX/StaticAnalyser.cpp +++ b/StaticAnalyser/MSX/StaticAnalyser.cpp @@ -61,9 +61,9 @@ void StaticAnalyser::MSX::AddTargets(const Media &media, std::list &dest std::vector files_on_tape = GetFiles(tape); if(!files_on_tape.empty()) { switch(files_on_tape.front().type) { - case File::Type::ASCII: target.loading_command = "RUN\"CAS:\n"; break; - case File::Type::TokenisedBASIC: target.loading_command = "CLOAD\nRUN\n"; break; - case File::Type::Binary: target.loading_command = "BLOAD\"CAS:\",R\n"; break; + case File::Type::ASCII: target.loading_command = "RUN\"CAS:\r"; break; + case File::Type::TokenisedBASIC: target.loading_command = "CLOAD\rRUN\r"; break; + case File::Type::Binary: target.loading_command = "BLOAD\"CAS:\",R\r"; break; default: break; } target.media.tapes.push_back(tape);