diff --git a/src/emulator.cpp b/src/emulator.cpp index 01923a4..42aaacf 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . -*/ + */ #include "emulator.h" #include "configep2.h" #include "e2const.h" @@ -23,445 +23,421 @@ #include -Emulator::Emulator(): - display(screenImage), - videoStatic(display), - apple2(keypresses,paddleButtonStates,display,fhyper,buffered,screenImage), - timable(0), // No ticked object (NULL pointer) - quit(false), - repeat(false), - keysDown(0), - command(false), - pendingCommandExit(false) -{ +Emulator::Emulator() : +display(screenImage), +videoStatic(display), +apple2(keypresses, paddleButtonStates, display, fhyper, buffered, screenImage), +timable(0), // No ticked object (NULL pointer) +quit(false), +repeat(false), +keysDown(0), +command(false), +pendingCommandExit(false) { } - -Emulator::~Emulator() -{ +Emulator::~Emulator() { } -void Emulator::toggleComputerPower() -{ - if (this->timable==&this->videoStatic) - powerOnComputer(); - else - powerOffComputer(); +void Emulator::toggleComputerPower() { + if (this->timable == &this->videoStatic) + powerOnComputer(); + else + powerOffComputer(); } -void Emulator::powerOnComputer() -{ - this->apple2.powerOn(); - this->screenImage.drawPower(true); - this->display.setNoise(false); +void Emulator::powerOnComputer() { + this->apple2.powerOn(); + this->screenImage.drawPower(true); + this->display.setNoise(false); - // The apple2 becomes the ticked object - this->timable = &this->apple2; + // The apple2 becomes the ticked object + this->timable = &this->apple2; } -void Emulator::powerOffComputer() -{ - // TODO Need to ask user if OK to lose any unsaved changes to disks - this->apple2.powerOff(); - this->screenImage.drawPower(false); - this->display.setNoise(true); - this->videoStatic.powerOn(); +void Emulator::powerOffComputer() { + // TODO Need to ask user if OK to lose any unsaved changes to disks + this->apple2.powerOff(); + this->screenImage.drawPower(false); + this->display.setNoise(true); + this->videoStatic.powerOn(); - // The video static becomes the ticked object - this->timable = &this->videoStatic; + // The video static becomes the ticked object + this->timable = &this->videoStatic; } -void Emulator::config(Config& cfg) -{ - cfg.parse(this->apple2.ram,this->apple2.rom,this->apple2.slts,this->apple2.revision,this->screenImage,this->apple2.cassette); +void Emulator::config(Config& cfg) { + cfg.parse(this->apple2.ram, this->apple2.rom, this->apple2.slts, this->apple2.revision, this->screenImage, this->apple2.cassette); } -void Emulator::init() -{ - powerOffComputer(); - this->display.setType(AnalogTV::MONITOR_COLOR); - this->display.powerOn(true); +void Emulator::init() { + powerOffComputer(); + this->display.setType(AnalogTV::MONITOR_COLOR); + this->display.powerOn(true); } - // How many emulation ticks between asking SDL if there is any new input - // from the user or other GUI events. - // This is also how often we shall update the estimate of the emulator's - // actual speed performance - // When the CPU is the object being ticked (each tick is a CPU cycle), then - // this is 20.04378892 Hz in emulated seconds time +// How many emulation ticks between asking SDL if there is any new input +// from the user or other GUI events. +// This is also how often we shall update the estimate of the emulator's +// actual speed performance +// When the CPU is the object being ticked (each tick is a CPU cycle), then +// this is 20.04378892 Hz in emulated seconds time #define CHECK_EVERY_CYCLE 51024 #define CHECK_CYCLES_K 51024000 #define EXPECTED_MS 50 // U.A.2 p. 7-13: REPT key repeats at 10Hz. -static const int CYCLES_PER_REPT(E2Const::AVG_CPU_HZ/10); +static const int CYCLES_PER_REPT(E2Const::AVG_CPU_HZ / 10); - // The core of this Apple -int Emulator::run() -{ - int skip = CHECK_EVERY_CYCLE; - Uint32 prev_ms = SDL_GetTicks(); - // While the user still wants to run this emulation... - while (!this->quit) - { - // (Obligatory protection against NULL object pointer) - if (this->timable) - { - this->timable->tick(); - // If the Apple ][ keyboard repeat is on (the REPT key is - // down)... - if (this->repeat) - { - // Count our way down to when the timer for the REPT key - // fires off: 10Hz in terms of how many CPU cycles have gone - // by - --this->rept; - // If it's time for the REPT key timer to fire (at long - // last)... - if (this->rept <= 0) - { - // ...reload the timer for the next firing 1/10 second from - // now ( *reset* the timer ) - this->rept = CYCLES_PER_REPT; - // If any other keys are actually being held down... - if (this->keysDown > 0) - { - // ...REPEAT the most recent one that was pressed - this->keypresses.push(this->lastKeyDown); - } - } - } - } +// The core of this Apple - // People who have too many press releases should be referred to as - // keyboards - - --skip; - // If skip has been decremented to zero... - if (!skip) - { - // ...then it's time to drain away any piled-up user interaction - // events that SDL has stored up for us - // Reload the skip quantity - skip = CHECK_EVERY_CYCLE; - SDL_Event event; - while (SDL_PollEvent(&event)) - { - switch (event.type) - { - // If SDL is going away... - case SDL_QUIT: - this->quit = true; - break; - case SDL_KEYDOWN: - // If we're collecting a command line for changing any - // of the configurables of the emulator... - if (this->command) - cmdKey(event.key); - else - // ...else we're collecting keypresses for the keyboard - // emulation (and thus the Apple ][ emulation itself) - dispatchKeypress(event.key); - break; - case SDL_KEYUP: - // If we're collecting a command line for changing any - // of the configurables of the emulator... - if (this->command) - { - if (this->pendingCommandExit) - { - this->command = false; - this->pendingCommandExit = false; - } - } - else - { - // ...else we're collecting keypresses for the keyboard - // emulation (and thus the Apple ][ emulation itself) - dispatchKeyUp(event.key); - } - break; - } - } - // If we're trying to run as slow as a real Apple ][... - if (!this->fhyper.isHyper()) - { - const int delta_ms = EXPECTED_MS-(SDL_GetTicks()-prev_ms); - if (0 < delta_ms && delta_ms <= EXPECTED_MS) - { - SDL_Delay(delta_ms); - } - - } - // Display the current estimate of the emulator's actual speed - // performance - this->screenImage.displayHz(CHECK_CYCLES_K/(SDL_GetTicks()-prev_ms)); - prev_ms = SDL_GetTicks(); - } - } - return 0; -} - -void Emulator::dispatchKeyUp(const SDL_KeyboardEvent& keyEvent) -{ - SDL_Keycode sym = keyEvent.keysym.sym; - SDL_Keymod mod = (SDL_Keymod)keyEvent.keysym.mod; - unsigned char key = (unsigned char)(sym & 0x7F); - - // printf("key UP: %d sym: %d mod: %04X scn: %d\n",key,sym,mod,scancode); - - if ((sym < 0x7F || sym == SDLK_LEFT || sym == SDLK_RIGHT) && - !(sym == SDLK_TAB || sym == SDLK_BACKQUOTE || sym == '[' || sym == '\\' || sym == SDLK_DELETE) && - !(sym == ']' && mod&KMOD_SHIFT)) - { - --this->keysDown; - } - // ...else if this is the emulated REPT key on the Apple keyboard... - else if (sym == SDLK_F10) - { - // ...stop repeating. The key has been released - this->repeat = false; - this->rept = 0; - } -} - - // Take real-world keystrokes from SDL and filter them to emulate the - // Apple ][ or Apple ][ plus keyboard -void Emulator::dispatchKeypress(const SDL_KeyboardEvent& keyEvent) -{ - if (keyEvent.repeat) - { - return; +int Emulator::run() { + int skip = CHECK_EVERY_CYCLE; + Uint32 prev_ms = SDL_GetTicks(); + // While the user still wants to run this emulation... + while (!this->quit) { + // (Obligatory protection against NULL object pointer) + if (this->timable) { + this->timable->tick(); + // If the Apple ][ keyboard repeat is on (the REPT key is + // down)... + if (this->repeat) { + // Count our way down to when the timer for the REPT key + // fires off: 10Hz in terms of how many CPU cycles have gone + // by + --this->rept; + // If it's time for the REPT key timer to fire (at long + // last)... + if (this->rept <= 0) { + // ...reload the timer for the next firing 1/10 second from + // now ( *reset* the timer ) + this->rept = CYCLES_PER_REPT; + // If any other keys are actually being held down... + if (this->keysDown > 0) { + // ...REPEAT the most recent one that was pressed + this->keypresses.push(this->lastKeyDown); + } + } + } } - SDL_Keycode sym = keyEvent.keysym.sym; - SDL_Keymod mod = (SDL_Keymod)keyEvent.keysym.mod; - unsigned char key = (unsigned char)(sym & 0x7F); + // People who have too many press releases should be referred to as + // keyboards -// printf("key DN: %d sym: %d mod: %04X scn: %d\n",key,sym,mod,scancode); + --skip; + // If skip has been decremented to zero... + if (!skip) { + // ...then it's time to drain away any piled-up user interaction + // events that SDL has stored up for us + // Reload the skip quantity + skip = CHECK_EVERY_CYCLE; + SDL_Event event; + while (SDL_PollEvent(&event)) { + switch (event.type) { + // If SDL is going away... + case SDL_QUIT: + this->quit = true; + break; + case SDL_KEYDOWN: + // If we're collecting a command line for changing any + // of the configurables of the emulator... + if (this->command) + cmdKey(event.key); + else + // ...else we're collecting keypresses for the keyboard + // emulation (and thus the Apple ][ emulation itself) + dispatchKeypress(event.key); + break; + case SDL_KEYUP: + // If we're collecting a command line for changing any + // of the configurables of the emulator... + if (this->command) { + if (this->pendingCommandExit) { + this->command = false; + this->pendingCommandExit = false; + } + } else { + // ...else we're collecting keypresses for the keyboard + // emulation (and thus the Apple ][ emulation itself) + dispatchKeyUp(event.key); + } + break; + } + } + // If we're trying to run as slow as a real Apple ][... + if (!this->fhyper.isHyper()) { + const int delta_ms = EXPECTED_MS - (SDL_GetTicks() - prev_ms); + if (0 < delta_ms && delta_ms <= EXPECTED_MS) { + SDL_Delay(delta_ms); + } - if ((sym < 0x7F || sym == SDLK_LEFT || sym == SDLK_RIGHT) && - !(sym == SDLK_TAB || sym == SDLK_BACKQUOTE || sym == '[' || sym == '\\' || sym == SDLK_DELETE) && - !(sym == ']' && mod&KMOD_SHIFT)) - { - ++this->keysDown; - } - - if (sym == SDLK_LEFT) - { - key = 8; - } - else if (sym == SDLK_RIGHT) - { - key = 21; - } - else if (sym == SDLK_PAUSE) - { - this->apple2.reset(); - return; - } - else if (sym == SDLK_INSERT) - { - // Feed input from the clipboard to the Apple keyboard - std::string s = this->clip.getText(); - for (unsigned int i = 0; i < s.length(); ++i) - { - key = s[i]; - // TODO fix pasting line-endings - if (key == '\n') - key = '\r'; - if ('a' <= key && key <= 'z') - { - key -= 32; - } - this->keypresses.push(key); - } - return; - } - // ...else if this is the emulated REPT key on the Apple keyboard... - else if (sym == SDLK_F10) - { - // ...start auto-repeat - this->repeat = true; - this->rept = CYCLES_PER_REPT; - return; - } - // ...else if the user wants to run at full speed instead of emulating - // the Apple's speed... - else if (sym == SDLK_F11) - { - this->fhyper.toggleHyper(); - this->screenImage.toggleHyperLabel(); - return; - } - else if (sym == SDLK_F12) - { - this->buffered.toggleBuffered(); - this->screenImage.toggleKdbBufferLabel(); - return; - } - // ...else if the user has hit the rocker switch on the back of the Apple... - else if (sym == SDLK_F1) - { - toggleComputerPower(); - return; - } - // ...else if the user wants to look at a different video display medium... - else if (sym == SDLK_F2) - { - this->display.cycleType(); - this->screenImage.cycleDisplayLabel(); - return; - } - // ...else if the user wants to switch to/from full screen and an - // individual application window... - else if (sym == SDLK_F3) - { - this->screenImage.toggleFullScreen(); - this->screenImage.drawPower(this->timable==&this->apple2); - return; - } - // ...else if the user wants to switch between the interlaced extension - // of the display and the non-interlaced historically correct display... - else if (sym == SDLK_F4) - { - this->display.toggleBleedDown(); - this->screenImage.toggleFillLinesLabel(); - return; - } - // ...else initiate command line entry at the bottom of the emulator window - else if (sym == SDLK_F5) - { - this->command = true; - this->screenImage.enterCommandMode(); - } - // ...else exit the entire emulation - else if (sym == SDLK_END) - { - this->quit = true; - return; - } - // ...else save a screen shot - else if (sym == SDLK_PRINTSCREEN) - { - this->screenImage.saveBMP(); - } - - // The unmodified Apple ][ hardware keyboard only generates upper-case - if ('a' <= key && key <= 'z') - { - key -= 32; - } - - if ((mod&KMOD_SHIFT) && (mod&KMOD_CTRL) && sym == '2') - { - // Ctrl-Shift-2 == Ctrl-@ == NUL == ASCII: 0 - key = 0; - } - else if ((mod&KMOD_SHIFT) && (mod&KMOD_CTRL) && sym == ' ') - { - // Ctrl-Shift-Space is the same as Space - key = ' '; - } - else if ((mod&KMOD_CTRL) && !(mod&KMOD_SHIFT) && SDLK_KP_0 <= sym && sym <= SDLK_KP_9) - { - // Control-only numeric keypad keys are converted to regular digit keys - key = sym-SDLK_KP_0+'0'; - } - else if ((mod&KMOD_CTRL) && !(mod&KMOD_SHIFT) && (('0' <= sym && sym <= '9') || sym == '/' || sym == ' ')) - { - // Control-only upon 0-9, / and space leaves them unchanged, the - // same as unmodified - key = sym; - } - else if (sym == ']') - { - if (mod&KMOD_SHIFT) - { - // ignore '}' (shift ']') - return; - } - if (mod&KMOD_CTRL) - { - // Ctrl-] == ASCII: $1D - key = 29; - } - } - // ...else if this is one of the keys that can't be typed on an Apple ][ - // keyboard... - else if (key == 0 || sym == SDLK_TAB || sym == SDLK_BACKQUOTE || sym == '[' || sym == '\\' || sym == SDLK_DELETE) - { - return; - } - - -// printf(" sending to apple as ascii------------------------------>%02X (%02X)\n",key,key|0x80); - this->keypresses.push(key); - this->lastKeyDown = key; + } + // Display the current estimate of the emulator's actual speed + // performance + this->screenImage.displayHz(CHECK_CYCLES_K / (SDL_GetTicks() - prev_ms)); + prev_ms = SDL_GetTicks(); + } + } + return 0; } - // Collect and edit a command line typed at the bottom of the emulator - // window -void Emulator::cmdKey(const SDL_KeyboardEvent& keyEvent) -{ - SDL_Keycode sym = keyEvent.keysym.sym; - SDL_Keymod mod = (SDL_Keymod)keyEvent.keysym.mod; - unsigned char key = (unsigned char)(sym & 0x7F); +void Emulator::dispatchKeyUp(const SDL_KeyboardEvent& keyEvent) { + SDL_Keycode sym = keyEvent.keysym.sym; + SDL_Keymod mod = (SDL_Keymod) keyEvent.keysym.mod; + unsigned char key = (unsigned char) (sym & 0x7F); - if (sym == SDLK_RETURN) - { - processCommand(); - } - else if (sym == SDLK_ESCAPE) - { - cmdline.erase(cmdline.begin(),cmdline.end()); - processCommand(); - } - else if (sym == SDLK_BACKSPACE) - { - if (cmdline.length()) - { - cmdline.erase(cmdline.end()-1); - this->screenImage.backspaceCommand(); - } - } - else if (sym == SDLK_INSERT) - { - std::string s = this->clip.getText(); - for (unsigned int i = 0; i < s.length(); ++i) - { - key = s[i]; - if (key == '\n' || key == '\r') - { - processCommand(); - break; - } - else - { - cmdline += key; - this->screenImage.addkeyCommand(key); - } - } - } - else if (key) - { - cmdline += key; - this->screenImage.addkeyCommand(key); - } + if ((sym < 0x7F || sym == SDLK_LEFT || sym == SDLK_RIGHT) && + !(sym == SDLK_TAB || sym == SDLK_BACKQUOTE || sym == '[' || sym == '\\' || sym == SDLK_DELETE) && + !(sym == ']' && mod & KMOD_SHIFT)) { + --this->keysDown; + }// ...else if this is the emulated REPT key on the Apple keyboard... + else if (sym == SDLK_F10) { + // ...stop repeating. The key has been released + this->repeat = false; + this->rept = 0; + } } - // Process a command line typed at the bottom of the emulator window -void Emulator::processCommand() -{ - this->screenImage.exitCommandMode(); - this->pendingCommandExit = true; +static bool translateKeysToAppleModernized(SDL_Keycode keycode, SDL_Keymod modifiers, unsigned char* key) { + if (keycode >= 0x100) { + return false; + } - if (cmdline.empty()) - { - return; - } + *key = (unsigned char) (keycode & 0x7F); - Config::parseLine(cmdline,this->apple2.ram,this->apple2.rom,this->apple2.slts,this->apple2.revision,this->screenImage,this->apple2.cassette); - cmdline.erase(cmdline.begin(),cmdline.end()); + // The Apple ][ hardware keyboard only generates upper-case + if ('a' <= *key && *key <= 'z') { + *key -= 32; + } + + // from SDL 1.2 to 2.0, we can't use UNICODE so we need to + // apply shift and control modifiers ourselves + if (modifiers & KMOD_SHIFT) { + if (keycode == SDLK_BACKQUOTE) *key = '~'; + else if (keycode == SDLK_1) *key = '!'; + else if (keycode == SDLK_2) *key = '@'; + else if (keycode == SDLK_3) *key = '#'; + else if (keycode == SDLK_4) *key = '$'; + else if (keycode == SDLK_5) *key = '%'; + else if (keycode == SDLK_6) *key = '^'; + else if (keycode == SDLK_7) *key = '&'; + else if (keycode == SDLK_8) *key = '*'; + else if (keycode == SDLK_9) *key = '('; + else if (keycode == SDLK_0) *key = ')'; + else if (keycode == SDLK_MINUS) *key = '_'; + else if (keycode == SDLK_EQUALS) *key = '+'; + + else if (keycode == SDLK_SEMICOLON) *key = ':'; + else if (keycode == SDLK_QUOTE) *key = '\"'; + + else if (keycode == SDLK_COMMA) *key = '<'; + else if (keycode == SDLK_PERIOD) *key = '>'; + else if (keycode == SDLK_SLASH) *key = '?'; + } + + if (modifiers & KMOD_CTRL) { + if ('A' <= *key && *key <= 'Z') { + *key -= 64; + } + } + + if (keycode == SDLK_LEFT) { + *key = 8; + } else if (keycode == SDLK_RIGHT) { + *key = 21; + } + + + if ((modifiers & KMOD_SHIFT) && (modifiers & KMOD_CTRL) && keycode == '2') { + // Ctrl-Shift-2 == Ctrl-@ == NUL == ASCII: 0 + *key = 0; + } else if ((modifiers & KMOD_SHIFT) && (modifiers & KMOD_CTRL) && keycode == ' ') { + // Ctrl-Shift-Space is the same as Space + *key = ' '; + } else if ((modifiers & KMOD_CTRL) && !(modifiers & KMOD_SHIFT) && SDLK_KP_0 <= keycode && keycode <= SDLK_KP_9) { + // Control-only numeric *keypad *keys are converted to regular digit *keys + *key = keycode - SDLK_KP_0 + '0'; + } else if ((modifiers & KMOD_CTRL) && !(modifiers & KMOD_SHIFT) && (('0' <= keycode && keycode <= '9') || keycode == '/' || keycode == ' ')) { + // Control-only upon 0-9, / and space leaves them unchanged, the + // same as unmodified + *key = keycode; + } else if (keycode == ']') { + if (modifiers & KMOD_SHIFT) { + // ignore '}' (shift ']') + return false; + } + if (modifiers & KMOD_CTRL) { + // Ctrl-] == ASCII: $1D + *key = 29; + } + }// ...else if this is one of the *keys that can't be typed on an Apple ][ + // *keyboard... + else if (*key == 0 || keycode == SDLK_TAB || keycode == SDLK_BACKQUOTE || keycode == '[' || keycode == '\\' || keycode == SDLK_DELETE) { + return false; + } + + + return true; +} + + + +// Take real-world keystrokes from SDL and filter them to emulate the +// Apple ][ or Apple ][ plus keyboard + +void Emulator::dispatchKeypress(const SDL_KeyboardEvent& keyEvent) { + if (keyEvent.repeat) { + return; + } + + SDL_Keycode sym = keyEvent.keysym.sym; + SDL_Keymod mod = (SDL_Keymod) keyEvent.keysym.mod; + SDL_Scancode scan = keyEvent.keysym.scancode; + + printf("keydown: mod: %04X sym: %08X scan:%04X name:%s\n", mod, sym, scan, SDL_GetKeyName(sym)); + + if ((sym < 0x7F || sym == SDLK_LEFT || sym == SDLK_RIGHT) && + !(sym == SDLK_TAB || sym == SDLK_BACKQUOTE || sym == '[' || sym == '\\' || sym == SDLK_DELETE) && + !(sym == ']' && mod & KMOD_SHIFT)) { + ++this->keysDown; + } + + + + /* + * First handle the key presses that are for commands, as opposed to + * simple key-presses that we send to the apple. + */ + + if (sym == SDLK_PAUSE) { + this->apple2.reset(); + return; + } else if (sym == SDLK_INSERT) { + // Feed input from the clipboard to the Apple keyboard + std::string s = this->clip.getText(); + for (unsigned int i = 0; i < s.length(); ++i) { + unsigned char key = s[i]; + // TODO fix pasting line-endings + if (key == '\n') + key = '\r'; + if ('a' <= key && key <= 'z') { + key -= 32; + } + this->keypresses.push(key); + } + return; + }// ...else if this is the emulated REPT key on the Apple keyboard... + else if (sym == SDLK_F10) { + // ...start auto-repeat + this->repeat = true; + this->rept = CYCLES_PER_REPT; + return; + }// ...else if the user wants to run at full speed instead of emulating + // the Apple's speed... + else if (sym == SDLK_F11) { + this->fhyper.toggleHyper(); + this->screenImage.toggleHyperLabel(); + return; + } else if (sym == SDLK_F12) { + this->buffered.toggleBuffered(); + this->screenImage.toggleKdbBufferLabel(); + return; + }// ...else if the user has hit the rocker switch on the back of the Apple... + else if (sym == SDLK_F1) { + toggleComputerPower(); + return; + }// ...else if the user wants to look at a different video display medium... + else if (sym == SDLK_F2) { + this->display.cycleType(); + this->screenImage.cycleDisplayLabel(); + return; + }// ...else if the user wants to switch to/from full screen and an + // individual application window... + else if (sym == SDLK_F3) { + this->screenImage.toggleFullScreen(); + this->screenImage.drawPower(this->timable == &this->apple2); + return; + }// ...else if the user wants to switch between the interlaced extension + // of the display and the non-interlaced historically correct display... + else if (sym == SDLK_F4) { + this->display.toggleBleedDown(); + this->screenImage.toggleFillLinesLabel(); + return; + }// ...else initiate command line entry at the bottom of the emulator window + else if (sym == SDLK_F5) { + this->command = true; + this->screenImage.enterCommandMode(); + return; + }// ...else exit the entire emulation + else if (sym == SDLK_END) { + this->quit = true; + return; + }// ...else save a screen shot + else if (sym == SDLK_PRINTSCREEN) { + this->screenImage.saveBMP(); + return; + } + + + unsigned char key; + const bool sendKey = translateKeysToAppleModernized(sym, mod, &key); + + + + if (sendKey) { + printf(" sending to apple as ASCII ------------------------------> %02X (%02X)\n", key, key | 0x80); + this->keypresses.push(key); + this->lastKeyDown = key; + } +} + + +// Collect and edit a command line typed at the bottom of the emulator +// window + +void Emulator::cmdKey(const SDL_KeyboardEvent& keyEvent) { + SDL_Keycode sym = keyEvent.keysym.sym; + SDL_Keymod mod = (SDL_Keymod) keyEvent.keysym.mod; + unsigned char key = (unsigned char) (sym & 0x7F); + + if (sym == SDLK_RETURN) { + processCommand(); + } else if (sym == SDLK_ESCAPE) { + cmdline.erase(cmdline.begin(), cmdline.end()); + processCommand(); + } else if (sym == SDLK_BACKSPACE) { + if (cmdline.length()) { + cmdline.erase(cmdline.end() - 1); + this->screenImage.backspaceCommand(); + } + } else if (sym == SDLK_INSERT) { + std::string s = this->clip.getText(); + for (unsigned int i = 0; i < s.length(); ++i) { + key = s[i]; + if (key == '\n' || key == '\r') { + processCommand(); + break; + } else { + cmdline += key; + this->screenImage.addkeyCommand(key); + } + } + } else if (key) { + cmdline += key; + this->screenImage.addkeyCommand(key); + } +} + +// Process a command line typed at the bottom of the emulator window + +void Emulator::processCommand() { + this->screenImage.exitCommandMode(); + this->pendingCommandExit = true; + + if (cmdline.empty()) { + return; + } + + Config::parseLine(cmdline, this->apple2.ram, this->apple2.rom, this->apple2.slts, this->apple2.revision, this->screenImage, this->apple2.cassette); + cmdline.erase(cmdline.begin(), cmdline.end()); }