From f7fc5e47e9bc59d3a466d923da65b6afa3008e24 Mon Sep 17 00:00:00 2001 From: Chris Mosher Date: Fri, 23 Dec 2022 09:31:34 +0900 Subject: [PATCH] remove SDL event loop and use wx for keypresses instead; fix screen resizing --- src/E2wxFrame.cpp | 1 - src/KeyEventHandler.cpp | 102 +++++++++++++++++++------------------- src/KeyEventHandler.h | 6 +-- src/PreferencesDialog.cpp | 1 + src/emulator.cpp | 32 ++---------- src/emulator.h | 4 -- src/screenimage.cpp | 77 ++++++++++++++++------------ src/screenimage.h | 15 ++++-- 8 files changed, 115 insertions(+), 123 deletions(-) diff --git a/src/E2wxFrame.cpp b/src/E2wxFrame.cpp index f6410d0..55cee7b 100644 --- a/src/E2wxFrame.cpp +++ b/src/E2wxFrame.cpp @@ -169,7 +169,6 @@ void E2wxFrame::OnPreferences(wxCommandEvent& event) { dlg->ShowModal(); dlg->Destroy(); } - // TODO re-configure emulator here wxGetApp().StartEmulator(); } diff --git a/src/KeyEventHandler.cpp b/src/KeyEventHandler.cpp index b7e71df..fd76f60 100644 --- a/src/KeyEventHandler.cpp +++ b/src/KeyEventHandler.cpp @@ -43,21 +43,27 @@ 90 GOTO 5 */ -static bool isKeyDown(const SDL_Keycode sym, const SDL_Keymod mod) { + + +static bool is_key_down(const wxKeyEvent& keyEvent) { + const int sym = keyEvent.GetKeyCode(); return ( - (sym < 0x7F || sym == SDLK_LEFT || sym == SDLK_RIGHT) && - !(sym == SDLK_TAB || sym == SDLK_BACKQUOTE || sym == '[' || sym == '\\' || sym == SDLK_DELETE) && - !(sym == ']' && mod & KMOD_SHIFT) + (sym < 0x7F || sym == WXK_LEFT || sym == WXK_RIGHT) && + !(sym == WXK_TAB || sym == '`' || sym == '[' || sym == '\\' || sym == WXK_DELETE) && + !(sym == ']' && keyEvent.ShiftDown()) ); } -static bool translateKeysToAppleModernized(SDL_Keycode keycode, SDL_Keymod modifiers, unsigned char* key) { - if (keycode == SDLK_LEFT) { +// Take real-world keystrokes from SDL and filter them to emulate the Apple ][ keyboard +static bool translate_key(const wxKeyEvent& keyEvent, unsigned char* key) { + const int keycode = keyEvent.GetKeyCode(); + + if (keycode == WXK_LEFT) { *key = 8; return true; } - if (keycode == SDLK_RIGHT) { + if (keycode == WXK_RIGHT) { *key = 21; return true; } @@ -75,56 +81,56 @@ static bool translateKeysToAppleModernized(SDL_Keycode keycode, SDL_Keymod modif // 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 = '+'; + if (keyEvent.ShiftDown()) { + if (keycode == '`') *key = '~'; + else if (keycode == '1') *key = '!'; + else if (keycode == '2') *key = '@'; + else if (keycode == '3') *key = '#'; + else if (keycode == '4') *key = '$'; + else if (keycode == '5') *key = '%'; + else if (keycode == '6') *key = '^'; + else if (keycode == '7') *key = '&'; + else if (keycode == '8') *key = '*'; + else if (keycode == '9') *key = '('; + else if (keycode == '0') *key = ')'; + else if (keycode == '-') *key = '_'; + else if (keycode == '=') *key = '+'; - else if (keycode == SDLK_SEMICOLON) *key = ':'; - else if (keycode == SDLK_QUOTE) *key = '\"'; + else if (keycode == ';') *key = ':'; + else if (keycode == '\'') *key = '\"'; - else if (keycode == SDLK_COMMA) *key = '<'; - else if (keycode == SDLK_PERIOD) *key = '>'; - else if (keycode == SDLK_SLASH) *key = '?'; + else if (keycode == ',') *key = '<'; + else if (keycode == '.') *key = '>'; + else if (keycode == '/') *key = '?'; - else if (keycode == SDLK_m) *key = ']'; - else if (keycode == SDLK_n) *key = '^'; - else if (keycode == SDLK_p) *key = '@'; + else if (keycode == 'M') *key = ']'; + else if (keycode == 'N') *key = '^'; + else if (keycode == 'P') *key = '@'; } - if (modifiers & KMOD_CTRL) { + if (keyEvent.RawControlDown()) { if (('A' <= *key && *key <= 'Z') || (*key == ']') || (*key == '^') || (*key == '@')) { *key -= 64; } } - if ((modifiers & KMOD_SHIFT) && (modifiers & KMOD_CTRL) && keycode == ' ') { + if (keyEvent.ShiftDown() && keyEvent.RawControlDown() && keycode == ' ') { // Ctrl-Shift-Space is the same as Space *key = ' '; - } else if ((modifiers & KMOD_CTRL) && !(modifiers & KMOD_SHIFT) && (('0' <= keycode && keycode <= '9') || keycode == '/' || keycode == ' ')) { + } else if (keyEvent.RawControlDown() && !keyEvent.ShiftDown() && (('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) { + if (keyEvent.ShiftDown()) { // ignore '}' (shift ']') return false; } - if (modifiers & KMOD_CTRL) { + if (keyEvent.RawControlDown()) { // 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) { + else if (*key == 0 || keycode == WXK_TAB || keycode == '`' || keycode == '[' || keycode == '\\' || keycode == WXK_DELETE) { return false; } @@ -140,29 +146,26 @@ 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) { + +void KeyEventHandler::dispatchKeyDown(const wxKeyEvent& keyEvent) { + if (keyEvent.IsAutoRepeat()) { // 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; + const int sym = keyEvent.GetKeyCode(); //printf("keydown: mod: %04X sym: %08X scan:%04X name:%s\n", mod, sym, scan, SDL_GetKeyName(sym)); - if (isKeyDown(sym, mod)) { + if (is_key_down(keyEvent)) { ++this->keysDown; } - if (sym == SDLK_F10) { + if (sym == WXK_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); + const bool sendKey = translate_key(keyEvent, &key); if (sendKey) { //printf(" sending to apple as ASCII ------------------------------> %02X (%02X) (%d)\n", key, key | 0x80, key | 0x80); this->keypresses.push(key); @@ -171,18 +174,17 @@ void KeyEventHandler::dispatchKeyDown(const SDL_KeyboardEvent& keyEvent) { } } -void KeyEventHandler::dispatchKeyUp(const SDL_KeyboardEvent& keyEvent) { - const SDL_Keycode sym = keyEvent.keysym.sym; - const SDL_Keymod mod = (SDL_Keymod)keyEvent.keysym.mod; +void KeyEventHandler::dispatchKeyUp(const wxKeyEvent& keyEvent) { + const int sym = keyEvent.GetKeyCode(); - if (isKeyDown(sym, mod)) { + if (is_key_down(keyEvent)) { --this->keysDown; if (this->keysDown <= 0) { this->repeater.clearKey(); } } - if (sym == SDLK_F10) { + if (sym == WXK_F10) { this->repeater.release(); } } diff --git a/src/KeyEventHandler.h b/src/KeyEventHandler.h index 584465a..30d49c4 100644 --- a/src/KeyEventHandler.h +++ b/src/KeyEventHandler.h @@ -28,7 +28,7 @@ #include "KeyRepeatHandler.h" #include "keyboard.h" -#include +#include class KeyEventHandler { int keysDown; @@ -40,8 +40,8 @@ public: KeyEventHandler(KeypressQueue &keypresses, KeyRepeatHandler &repeater); virtual ~KeyEventHandler(); - void dispatchKeyDown(const SDL_KeyboardEvent& keyEvent); - void dispatchKeyUp(const SDL_KeyboardEvent& keyEvent); + void dispatchKeyDown(const wxKeyEvent& keyEvent); + void dispatchKeyUp(const wxKeyEvent& keyEvent); }; #endif /* KEYEVENTHANDLER_H */ diff --git a/src/PreferencesDialog.cpp b/src/PreferencesDialog.cpp index 936909c..753def5 100644 --- a/src/PreferencesDialog.cpp +++ b/src/PreferencesDialog.cpp @@ -327,6 +327,7 @@ void PreferencesDialog::OnRename(wxCommandEvent& evt) { } } +// TODO make two buttons: "Close & Restart" and just "Close" void PreferencesDialog::OnCloseButton(wxCommandEvent& evt) { CTRL(wxTreeCtrl, treItems); const TreeItemData *data = (TreeItemData*)treItems->GetItemData(treItems->GetSelection()); diff --git a/src/emulator.cpp b/src/emulator.cpp index ee2d2c2..89cc173 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -38,6 +38,7 @@ Emulator::Emulator() : + screenImage(keyEventHandler), display(screenImage), videoStatic(display), apple2(keypresses, paddleButtonStates, display, buffered, screenImage), @@ -60,31 +61,6 @@ void Emulator::config(E2Config& cfg) { -void Emulator::handleAnyPendingEvents() { - SDL_Event event; - while (SDL_PollEvent(&event)) { - switch (event.type) { - case SDL_QUIT: - // If SDL is going away... - // could be due to user closing the SDL window, pressing cmd-Q on Mac, - // ctrl-C from the command line on Linux, process being killed, etc. - wxGetApp().CloseMainFrame(); - break; - case SDL_KEYDOWN: - // we're collecting keypresses for the keyboard - // emulation (and thus the Apple ][ emulation itself) - this->keyEventHandler.dispatchKeyDown(event.key); - // People who have too many press-releases should be referred to as "keyboards" - break; - case SDL_KEYUP: - this->keyEventHandler.dispatchKeyUp(event.key); - break; - } - } -} - - - // 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 @@ -101,8 +77,6 @@ void Emulator::tick50ms() { } } - handleAnyPendingEvents(); - this->screenImage.displayHz((1000*CHECK_EVERY_CYCLE)/(SDL_GetTicks() - this->prev_ms)); this->prev_ms = SDL_GetTicks(); } @@ -228,8 +202,8 @@ void Emulator::toggleBuffered() { } void Emulator::toggleFullScreen() { - this->screenImage.toggleFullScreen(); - this->screenImage.drawPower(this->timable == &this->apple2); +// this->screenImage.toggleFullScreen(); +// this->screenImage.drawPower(this->timable == &this->apple2); } void Emulator::screenshot() { diff --git a/src/emulator.h b/src/emulator.h index 258e654..690479f 100644 --- a/src/emulator.h +++ b/src/emulator.h @@ -52,10 +52,6 @@ class Emulator { void powerOnComputer(); void powerOffComputer(); - void handleAnyPendingEvents(); - - void handleRepeatKey(); - public: Emulator(); virtual ~Emulator(); diff --git a/src/screenimage.cpp b/src/screenimage.cpp index 5fb3220..b36be1c 100644 --- a/src/screenimage.cpp +++ b/src/screenimage.cpp @@ -64,62 +64,69 @@ static const int WIDTH = AppleNTSC::H - AppleNTSC::PIC_START - 2; class ScreenException { }; -ScreenImage::ScreenImage() : - wxFrame(nullptr/*wxGetApp().GetFrame()*/, wxID_ANY, "Emulator", wxDefaultPosition, wxDefaultSize, - wxSYSTEM_MENU | wxCLOSE_BOX | wxCAPTION | wxCLIP_CHILDREN), +ScreenImage::ScreenImage(KeyEventHandler &k) : + wxFrame(nullptr, wxID_ANY, "Emulator"), fullscreen(false), buffer(true), display(AnalogTV::TV_OLD_COLOR), slotnames(8), cassInName(32, ' '), - cassOutName(32, ' ') { + cassOutName(32, ' '), + keyEventHandler(k) { createScreen(); Show(); + Bind(wxEVT_IDLE, &ScreenImage::OnIdle, this); } ScreenImage::~ScreenImage() { destroyScreen(); } -wxBEGIN_EVENT_TABLE(ScreenImage, wxFrame) -wxEND_EVENT_TABLE() -void ScreenImage::exitFullScreen() { - if (this->fullscreen) { - toggleFullScreen(); + +void ScreenImage::OnIdle(wxIdleEvent &evt) { + if (!this->FindFocus() || !this->sdl->HasFocus()) { + this->sdl->SetFocus(); } } +void ScreenImage::exitFullScreen() { +// if (this->fullscreen) { +// toggleFullScreen(); +// } +} + void ScreenImage::toggleFullScreen() { - this->fullscreen = !this->fullscreen; - const int flags = this->fullscreen ? SDL_WINDOW_FULLSCREEN : 0; - SDL_SetWindowFullscreen(this->window, flags); +// this->fullscreen = !this->fullscreen; +// const int flags = this->fullscreen ? SDL_WINDOW_FULLSCREEN : 0; +// SDL_SetWindowFullscreen(this->window, flags); } void ScreenImage::createScreen() { + this->sdl = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(SCRW,SCRH*ASPECT_RATIO)); + createSdlTexture(); + this->sdl->Bind(wxEVT_KEY_DOWN, &ScreenImage::OnKeyDown, this); + this->sdl->Bind(wxEVT_KEY_UP, &ScreenImage::OnKeyUp, this); + wxSizer *pszr = new wxBoxSizer(wxVERTICAL); - - this->panelTop = new wxPanel(this); - // TODO why won't shaped work? (Disabled frame resize as a workaround, for now.) - pszr->Add(this->panelTop, wxSizerFlags(0).Expand().Shaped().Center()); - - wxPanel *panelSdl = new wxPanel(this->panelTop, wxID_ANY, wxDefaultPosition, wxSize(SCRW,SCRH*ASPECT_RATIO)); - createSdlTexture(panelSdl); - - drawLabels(); - notifyObservers(); - + pszr->Add(this->sdl); SetSizer(pszr); pszr->SetSizeHints(this); + this->pixels = (unsigned int*) calloc(SCRW * SCRH, sizeof (unsigned int)); + this->screen_pitch = SCRW; + + drawLabels(); + notifyObservers(); } -void ScreenImage::createSdlTexture(wxPanel *panelSdl) { - WXWidget nativeSdl = panelSdl->GetHandle(); +void ScreenImage::createSdlTexture() { + WXWidget nativeSdl = this->sdl->GetHandle(); // TODO: do we need special gtk handling here, to get xid using: // GtkWidget* widget = panel->GetHandle(); // gtk_widget_realize(widget); // Window xid = GDK_WINDOW_XWINDOW(widget->window); + this->window = SDL_CreateWindowFrom(static_cast(nativeSdl)); if (this->window == NULL) { printf("Unable to create window: %s\n", SDL_GetError()); @@ -139,9 +146,6 @@ void ScreenImage::createSdlTexture(wxPanel *panelSdl) { std::cerr << SDL_GetError() << std::endl; throw ScreenException(); } - - this->pixels = (unsigned int*) calloc(SCRW * SCRH, sizeof (unsigned int)); - this->screen_pitch = SCRW; } void ScreenImage::destroyScreen() { @@ -320,25 +324,26 @@ void ScreenImage::drawPower(bool on) { } void ScreenImage::notifyObservers() { - const int e = SDL_UpdateTexture(this->texture, NULL, this->pixels, SCRW * sizeof (unsigned int)); + const int e = SDL_UpdateTexture(this->texture, NULL, this->pixels, SCRW*sizeof(unsigned int)); if (e) { std::cerr << SDL_GetError() << std::endl; } SDL_RenderClear(this->renderer); - SDL_RenderCopy(this->renderer,this->texture,NULL,NULL); + SDL_RenderCopy(this->renderer, this->texture, NULL, NULL); SDL_RenderPresent(this->renderer); + SDL_RenderSetLogicalSize(this->renderer, SCRW, SCRH*ASPECT_RATIO); } void ScreenImage::setElem(unsigned int i, const unsigned int val) { unsigned int* pn = this->pixels; - i += (i / WIDTH)*(SCRW - WIDTH); + i += (i/WIDTH)*(SCRW-WIDTH); pn += i; *pn = val; } void ScreenImage::blank() { for (int r = 0; r < HEIGHT; ++r) { - memset((char*) (this->pixels) + r * SCRW * 4, 0, WIDTH * 4); + memset((char*)(this->pixels)+r*SCRW*4, 0, WIDTH*4); } } @@ -539,3 +544,11 @@ void ScreenImage::saveBMP() { SDL_SaveBMP(screenshot, time); SDL_FreeSurface(screenshot); } + +void ScreenImage::OnKeyDown(wxKeyEvent &evt) { + this->keyEventHandler.dispatchKeyDown(evt); +} + +void ScreenImage::OnKeyUp(wxKeyEvent &evt) { + this->keyEventHandler.dispatchKeyUp(evt); +} diff --git a/src/screenimage.h b/src/screenimage.h index b89f992..d6c0e0d 100644 --- a/src/screenimage.h +++ b/src/screenimage.h @@ -18,10 +18,13 @@ #ifndef SCREENIMAGE_H #define SCREENIMAGE_H +#include "keyboard.h" #include "analogtv.h" +#include "KeyEventHandler.h" #include #include +#include #include #include @@ -34,7 +37,7 @@ struct SDL_Window; class ScreenImage : public wxFrame { private: - wxPanel *panelTop; + wxPanel *sdl; SDL_Window* window; SDL_Renderer* renderer; SDL_Texture* texture; @@ -44,19 +47,23 @@ private: bool buffer; AnalogTV::DisplayType display; void createScreen(); - void createSdlTexture(wxPanel *panelSdl); + void createSdlTexture(); void destroyScreen(); std::vector slotnames; std::string cassInName; std::string cassOutName; + KeyEventHandler &keyEventHandler; + static std::string truncateFilePath(const std::filesystem::path& filepath); - wxDECLARE_EVENT_TABLE(); + void OnIdle(wxIdleEvent &evt); + void OnKeyDown(wxKeyEvent &evt); + void OnKeyUp(wxKeyEvent &evt); // TODO some of these methods should be private public: - ScreenImage(); + ScreenImage(KeyEventHandler &keyEventHandler); ~ScreenImage(); void exitFullScreen();