diff --git a/src/KeyEventHandler.cpp b/src/KeyEventHandler.cpp index fd2101e..b7e71df 100644 --- a/src/KeyEventHandler.cpp +++ b/src/KeyEventHandler.cpp @@ -23,14 +23,166 @@ * Created on December 19, 2022, 7:36 AM */ + + #include "KeyEventHandler.h" -KeyEventHandler::KeyEventHandler() { + + +/* + 5 POKE 49168,0 +10 K = PEEK (49152) +15 IF K < 128 GOTO 10 +20 HI = INT (K / 16) +30 LO = K - (HI * 16) +40 IF LO > 9 THEN LO = LO + 7 +50 LO = LO + 48 +60 IF HI > 9 THEN HI = HI + 7 +70 HI = HI + 48 +80 PRINT "$"; CHR$ (HI); CHR$ (LO) +90 GOTO 5 +*/ + +static bool isKeyDown(const SDL_Keycode sym, const SDL_Keymod mod) { + return ( + (sym < 0x7F || sym == SDLK_LEFT || sym == SDLK_RIGHT) && + !(sym == SDLK_TAB || sym == SDLK_BACKQUOTE || sym == '[' || sym == '\\' || sym == SDLK_DELETE) && + !(sym == ']' && mod & KMOD_SHIFT) + ); } -KeyEventHandler::KeyEventHandler(const KeyEventHandler& orig) { +static bool translateKeysToAppleModernized(SDL_Keycode keycode, SDL_Keymod modifiers, unsigned char* key) { + if (keycode == SDLK_LEFT) { + *key = 8; + return true; + } + + if (keycode == SDLK_RIGHT) { + *key = 21; + return true; + } + + if (keycode < 0 || 0x100 <= keycode) { + return false; + } + + *key = (unsigned char)(keycode & 0x7F); + + // 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 = '?'; + + else if (keycode == SDLK_m) *key = ']'; + else if (keycode == SDLK_n) *key = '^'; + else if (keycode == SDLK_p) *key = '@'; + } + + if (modifiers & KMOD_CTRL) { + if (('A' <= *key && *key <= 'Z') || (*key == ']') || (*key == '^') || (*key == '@')) { + *key -= 64; + } + } + + 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) && (('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; +} + + + +KeyEventHandler::KeyEventHandler(KeypressQueue &q, KeyRepeatHandler &r) : keysDown(0), keypresses(q), repeater(r) { } KeyEventHandler::~KeyEventHandler() { } + +// Take real-world keystrokes from SDL and filter them to emulate the Apple ][ keyboard +void KeyEventHandler::dispatchKeyDown(const SDL_KeyboardEvent& keyEvent) { + if (keyEvent.repeat) { + // To repeat on the real Apple ][, you need to use the REPT key (emulated by F10) + return; + } + + const SDL_Keycode sym = keyEvent.keysym.sym; + const SDL_Keymod mod = (SDL_Keymod)keyEvent.keysym.mod; + + //printf("keydown: mod: %04X sym: %08X scan:%04X name:%s\n", mod, sym, scan, SDL_GetKeyName(sym)); + + if (isKeyDown(sym, mod)) { + ++this->keysDown; + } + + if (sym == SDLK_F10) { + this->repeater.press(); +// } else if (SDLK_F1 <= sym && sym <= SDLK_F12) { +// wxGetApp().OnFnKeyPressed(sym); + } else { + unsigned char key; + const bool sendKey = translateKeysToAppleModernized(sym, mod, &key); + if (sendKey) { + //printf(" sending to apple as ASCII ------------------------------> %02X (%02X) (%d)\n", key, key | 0x80, key | 0x80); + this->keypresses.push(key); + this->repeater.setKey(key); + } + } +} + +void KeyEventHandler::dispatchKeyUp(const SDL_KeyboardEvent& keyEvent) { + const SDL_Keycode sym = keyEvent.keysym.sym; + const SDL_Keymod mod = (SDL_Keymod)keyEvent.keysym.mod; + + if (isKeyDown(sym, mod)) { + --this->keysDown; + if (this->keysDown <= 0) { + this->repeater.clearKey(); + } + } + + if (sym == SDLK_F10) { + this->repeater.release(); + } +} diff --git a/src/KeyEventHandler.h b/src/KeyEventHandler.h index 7e2bca4..584465a 100644 --- a/src/KeyEventHandler.h +++ b/src/KeyEventHandler.h @@ -26,14 +26,22 @@ #ifndef KEYEVENTHANDLER_H #define KEYEVENTHANDLER_H -class KeyEventHandler { -public: - KeyEventHandler(); - KeyEventHandler(const KeyEventHandler& orig); - virtual ~KeyEventHandler(); -private: +#include "KeyRepeatHandler.h" +#include "keyboard.h" +#include +class KeyEventHandler { + int keysDown; + + KeypressQueue &keypresses; + KeyRepeatHandler &repeater; + +public: + KeyEventHandler(KeypressQueue &keypresses, KeyRepeatHandler &repeater); + virtual ~KeyEventHandler(); + + void dispatchKeyDown(const SDL_KeyboardEvent& keyEvent); + void dispatchKeyUp(const SDL_KeyboardEvent& keyEvent); }; #endif /* KEYEVENTHANDLER_H */ - diff --git a/src/emulator.cpp b/src/emulator.cpp index 7bbee5a..ee2d2c2 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -36,24 +36,13 @@ -static bool isKeyDown(const SDL_Keycode sym, const SDL_Keymod mod) { - return ( - (sym < 0x7F || sym == SDLK_LEFT || sym == SDLK_RIGHT) && - !(sym == SDLK_TAB || sym == SDLK_BACKQUOTE || sym == '[' || sym == '\\' || sym == SDLK_DELETE) && - !(sym == ']' && mod & KMOD_SHIFT) - ); -} - - - - Emulator::Emulator() : display(screenImage), videoStatic(display), apple2(keypresses, paddleButtonStates, display, buffered, screenImage), + keyEventHandler(keypresses, apple2.keyrepeater), timable(nullptr), // No ticked object (NULL pointer) - keysDown(0), prev_ms(SDL_GetTicks()) { } @@ -84,11 +73,11 @@ void Emulator::handleAnyPendingEvents() { case SDL_KEYDOWN: // we're collecting keypresses for the keyboard // emulation (and thus the Apple ][ emulation itself) - dispatchKeyDown(event.key); + this->keyEventHandler.dispatchKeyDown(event.key); // People who have too many press-releases should be referred to as "keyboards" break; case SDL_KEYUP: - dispatchKeyUp(event.key); + this->keyEventHandler.dispatchKeyUp(event.key); break; } } @@ -120,133 +109,6 @@ void Emulator::tick50ms() { -static bool translateKeysToAppleModernized(SDL_Keycode keycode, SDL_Keymod modifiers, unsigned char* key) { - if (keycode == SDLK_LEFT) { - *key = 8; - return true; - } else if (keycode == SDLK_RIGHT) { - *key = 21; - return true; - } - - if (keycode >= 0x100) { - return false; - } - - *key = (unsigned char) (keycode & 0x7F); - - // 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 = '?'; - - else if (keycode == SDLK_m) *key = ']'; - else if (keycode == SDLK_n) *key = '^'; - else if (keycode == SDLK_p) *key = '@'; - } - - if (modifiers & KMOD_CTRL) { - if (('A' <= *key && *key <= 'Z') || (*key == ']') || (*key == '^') || (*key == '@')) { - *key -= 64; - } - } - - 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) && (('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 ][ keyboard -void Emulator::dispatchKeyDown(const SDL_KeyboardEvent& keyEvent) { - if (keyEvent.repeat) { - // To repeat on the real Apple ][, you need to use the REPT key (emulated by F10) - return; - } - - const SDL_Keycode sym = keyEvent.keysym.sym; - const SDL_Keymod mod = (SDL_Keymod)keyEvent.keysym.mod; - - //printf("keydown: mod: %04X sym: %08X scan:%04X name:%s\n", mod, sym, scan, SDL_GetKeyName(sym)); - - if (isKeyDown(sym, mod)) { - ++this->keysDown; - } - - if (sym == SDLK_F10) { - this->apple2.rept().press(); -// } else if (SDLK_F1 <= sym && sym <= SDLK_F12) { -// wxGetApp().OnFnKeyPressed(sym); - } else { - unsigned char key; - const bool sendKey = translateKeysToAppleModernized(sym, mod, &key); - if (sendKey) { - //printf(" sending to apple as ASCII ------------------------------> %02X (%02X) (%d)\n", key, key | 0x80, key | 0x80); - this->keypresses.push(key); - this->apple2.rept().setKey(key); - } - } -} - -void Emulator::dispatchKeyUp(const SDL_KeyboardEvent& keyEvent) { - const SDL_Keycode sym = keyEvent.keysym.sym; - const SDL_Keymod mod = (SDL_Keymod) keyEvent.keysym.mod; - - if (isKeyDown(sym, mod)) { - --this->keysDown; - if (this->keysDown <= 0) { - this->apple2.rept().clearKey(); - } - } - - if (sym == SDLK_F10) { - this->apple2.rept().release(); - } -} - - - void Emulator::cmd(const wxString& c) { diff --git a/src/emulator.h b/src/emulator.h index 998c98b..258e654 100644 --- a/src/emulator.h +++ b/src/emulator.h @@ -26,6 +26,7 @@ #include "analogtv.h" #include "keyboardbuffermode.h" #include "KeyRepeatHandler.h" +#include "KeyEventHandler.h" #include "clipboardhandler.h" #include #include @@ -36,17 +37,16 @@ class E2Config; class Emulator { PaddleButtonStates paddleButtonStates; KeypressQueue keypresses; - KeyboardBufferMode buffered; ScreenImage screenImage; AnalogTV display; VideoStaticGenerator videoStatic; Apple2 apple2; ClipboardHandler clip; + KeyEventHandler keyEventHandler; Timable* timable; - int keysDown; // TODO move to KeyEventHandler Uint32 prev_ms; void powerOnComputer(); @@ -54,9 +54,6 @@ class Emulator { void handleAnyPendingEvents(); - void dispatchKeyDown(const SDL_KeyboardEvent& keyEvent); - void dispatchKeyUp(const SDL_KeyboardEvent& keyEvent); - void handleRepeatKey(); public: