add wx menu handling for F1,F7,F9; fix initial value (random) of keyboard latch

This commit is contained in:
Christopher A. Mosher 2022-12-12 13:03:30 -05:00
parent 7552b0ce11
commit b064d06efd
9 changed files with 91 additions and 76 deletions

View File

@ -360,7 +360,6 @@ void E2wxApp::StartEmulator() {
this->emu = new Emulator(); this->emu = new Emulator();
E2Config cfg{this->arg_configfile, this->opt_config_from_prefs_only}; E2Config cfg{this->arg_configfile, this->opt_config_from_prefs_only};
this->emu->config(cfg); this->emu->config(cfg);
this->emu->init();
this->emu_timer = new EmuTimer{this->emu}; this->emu_timer = new EmuTimer{this->emu};
this->emu_timer->begin(); this->emu_timer->begin();
@ -373,3 +372,9 @@ bool E2wxApp::EnsureCanQuit() {
} }
return ok; return ok;
} }
void E2wxApp::Paste() {
if (this->emu) {
this->emu->handlePaste();
}
}

View File

@ -83,6 +83,7 @@ public:
bool CloseMainFrame(); bool CloseMainFrame();
bool EnsureCanQuit(); bool EnsureCanQuit();
void Paste();
virtual bool OnInit() override; virtual bool OnInit() override;
virtual int OnExit() override; virtual int OnExit() override;

View File

@ -23,18 +23,19 @@
#include "PreferencesDialog.h" #include "PreferencesDialog.h"
#include "gui.h" #include "gui.h"
#include <wx/menu.h> #include <wx/menu.h>
#include <wx/accel.h>
#include <wx/msgdlg.h> #include <wx/msgdlg.h>
#include <wx/event.h> #include <wx/event.h>
#include <wx/persist/toplevel.h> #include <wx/persist/toplevel.h>
enum E2MenuID { enum E2MenuID {
ID_MENUITEM_POWER = wxID_HIGHEST+1 ID_MENUITEM_POWER = wxID_HIGHEST+1
}; };
wxBEGIN_EVENT_TABLE(E2wxFrame, wxFrame) wxBEGIN_EVENT_TABLE(E2wxFrame, wxFrame)
EVT_MENU(wxID_EXIT, E2wxFrame::OnExit) EVT_MENU(wxID_EXIT, E2wxFrame::OnExit)
EVT_MENU(wxID_PASTE, E2wxFrame::OnPaste)
EVT_MENU(wxID_PREFERENCES, E2wxFrame::OnPreferences) EVT_MENU(wxID_PREFERENCES, E2wxFrame::OnPreferences)
EVT_MENU(wxID_ABOUT, E2wxFrame::OnAbout) EVT_MENU(wxID_ABOUT, E2wxFrame::OnAbout)
EVT_MENU(ID_MENUITEM_POWER, E2wxFrame::OnTogglePower) EVT_MENU(ID_MENUITEM_POWER, E2wxFrame::OnTogglePower)
@ -65,15 +66,20 @@ void E2wxFrame::InitMenuBar() {
wxMenu *menuFile = new wxMenu(); wxMenu *menuFile = new wxMenu();
menuBar->Append(menuFile, "&File"); menuBar->Append(menuFile, "&File");
menuFile->Append(wxID_EXIT); wxMenuItem *miExit = menuFile->Append(wxID_EXIT);
miExit->AddExtraAccel(wxAcceleratorEntry(wxACCEL_NORMAL, WXK_F9));
wxMenu *menuEdit = new wxMenu(); wxMenu *menuEdit = new wxMenu();
menuBar->Append(menuEdit, "&Edit"); menuBar->Append(menuEdit, "&Edit");
wxMenuItem *miPaste = menuEdit->Append(wxID_PASTE);
miPaste->AddExtraAccel(wxAcceleratorEntry(wxACCEL_NORMAL, WXK_F7));
menuEdit->AppendSeparator();
menuEdit->Append(wxID_PREFERENCES); menuEdit->Append(wxID_PREFERENCES);
wxMenu *menuMachine = new wxMenu(); wxMenu *menuMachine = new wxMenu();
menuBar->Append(menuMachine, "&Machine"); menuBar->Append(menuMachine, "&Machine");
menuMachine->Append(ID_MENUITEM_POWER, "Toggle Power"); wxMenuItem *miPower = menuMachine->Append(ID_MENUITEM_POWER, "Toggle Power");
miPower->SetAccel(new wxAcceleratorEntry(wxACCEL_NORMAL, WXK_F1));
wxMenu *menuHelp = new wxMenu(); wxMenu *menuHelp = new wxMenu();
menuBar->Append(menuHelp, "&Help"); menuBar->Append(menuHelp, "&Help");
@ -104,6 +110,10 @@ void E2wxFrame::OnAbout(wxCommandEvent& event) {
wxMessageBox(msg, "About "+wxGetApp().GetID(), wxOK | wxICON_INFORMATION); wxMessageBox(msg, "About "+wxGetApp().GetID(), wxOK | wxICON_INFORMATION);
} }
void E2wxFrame::OnPaste(wxCommandEvent& event) {
wxGetApp().Paste();
}
void E2wxFrame::OnPreferences(wxCommandEvent& event) { void E2wxFrame::OnPreferences(wxCommandEvent& event) {
PreferencesDialog *dlg = new PreferencesDialog(this); PreferencesDialog *dlg = new PreferencesDialog(this);
dlg->OnInit(); dlg->OnInit();

View File

@ -34,6 +34,7 @@ public:
private: private:
void OnExit(wxCommandEvent& event); void OnExit(wxCommandEvent& event);
void OnPaste(wxCommandEvent& event);
void OnPreferences(wxCommandEvent& event); void OnPreferences(wxCommandEvent& event);
void OnAbout(wxCommandEvent& event); void OnAbout(wxCommandEvent& event);
void OnTogglePower(wxCommandEvent& event); void OnTogglePower(wxCommandEvent& event);

View File

@ -94,6 +94,7 @@ void Apple2::powerOn() {
this->video.powerOn(); this->video.powerOn();
this->picgen.powerOn(); this->picgen.powerOn();
this->powerUpReset.powerOn(); this->powerUpReset.powerOn();
this->kbd.powerOn();
} }
void Apple2::powerOff() { void Apple2::powerOff() {

View File

@ -52,11 +52,6 @@ void Emulator::toggleComputerPower() {
} }
void Emulator::powerOnComputer() { void Emulator::powerOnComputer() {
if (this->apple2.revision == 0) {
unsigned char key = 33u + rand()%94;
this->keypresses.push(key);
this->lastKeyDown = key;
}
this->apple2.powerOn(); this->apple2.powerOn();
this->screenImage.drawPower(true); this->screenImage.drawPower(true);
this->display.setNoise(false); this->display.setNoise(false);
@ -78,9 +73,6 @@ void Emulator::powerOffComputer() {
void Emulator::config(E2Config& cfg) { void Emulator::config(E2Config& cfg) {
cfg.parse(this->apple2.ram, this->apple2.rom, this->apple2.slts, this->apple2.revision, this->screenImage, this->apple2.cassetteIn, this->apple2.cassetteOut, &this->apple2); cfg.parse(this->apple2.ram, this->apple2.rom, this->apple2.slts, this->apple2.revision, this->screenImage, this->apple2.cassetteIn, this->apple2.cassetteOut, &this->apple2);
this->apple2.ram.dump_config(); this->apple2.ram.dump_config();
}
void Emulator::init() {
powerOffComputer(); powerOffComputer();
this->display.powerOn(true); this->display.powerOn(true);
} }
@ -299,23 +291,15 @@ void Emulator::dispatchKeypress(const SDL_KeyboardEvent& keyEvent) {
* First handle the key presses that are for commands, as opposed to * First handle the key presses that are for commands, as opposed to
* simple key-presses that we send to the apple. * simple key-presses that we send to the apple.
*/ */
// TODO remove all function key handling from here, and
// instead redirect them to the main frame, which will call back
// our appropriate handler functions
// Note: REPT key is special (need to track key-up event)
if (sym == SDLK_F6) { if (sym == SDLK_F6) {
this->apple2.reset(); this->apple2.reset();
return; return;
} else if (sym == SDLK_F7) { } else if (sym == SDLK_F7) {
// Feed input from the clipboard to the Apple keyboard handlePaste();
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; return;
}// ...else if this is the emulated REPT key on the Apple keyboard... }// ...else if this is the emulated REPT key on the Apple keyboard...
else if (sym == SDLK_F10) { else if (sym == SDLK_F10) {
@ -325,7 +309,7 @@ void Emulator::dispatchKeypress(const SDL_KeyboardEvent& keyEvent) {
return; return;
}// ...else if the user wants to run at full speed instead of emulating }// ...else if the user wants to run at full speed instead of emulating
// the Apple's speed... // the Apple's speed...
else if (sym == SDLK_F11) { else if (sym == SDLK_F11) { // TODO remove hyper
this->fhyper.toggleHyper(); this->fhyper.toggleHyper();
this->screenImage.toggleHyperLabel(); this->screenImage.toggleHyperLabel();
return; return;
@ -350,12 +334,12 @@ void Emulator::dispatchKeypress(const SDL_KeyboardEvent& keyEvent) {
return; return;
}// ...else if the user wants to switch between the interlaced extension }// ...else if the user wants to switch between the interlaced extension
// of the display and the non-interlaced historically correct display... // of the display and the non-interlaced historically correct display...
else if (sym == SDLK_F4) { else if (sym == SDLK_F4) { // TODO remove bleed-down
this->display.toggleBleedDown(); this->display.toggleBleedDown();
this->screenImage.toggleFillLinesLabel(); this->screenImage.toggleFillLinesLabel();
return; return;
}// ...else initiate command line entry at the bottom of the emulator window }// ...else initiate command line entry at the bottom of the emulator window
else if (sym == SDLK_F5) { else if (sym == SDLK_F5) { // TODO re-do user-entered command line
this->command = true; this->command = true;
this->screenImage.enterCommandMode(); this->screenImage.enterCommandMode();
return; return;
@ -474,3 +458,18 @@ bool Emulator::isSafeToQuit() {
void Emulator::handleUserQuitRequest() { void Emulator::handleUserQuitRequest() {
wxGetApp().CloseMainFrame(); wxGetApp().CloseMainFrame();
} }
void Emulator::handlePaste() {
// 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);
}
}

View File

@ -61,6 +61,8 @@ class Emulator {
void dispatchKeyUp(const SDL_KeyboardEvent& keyEvent); void dispatchKeyUp(const SDL_KeyboardEvent& keyEvent);
void cmdKey(const SDL_KeyboardEvent& keyEvent); void cmdKey(const SDL_KeyboardEvent& keyEvent);
void processCommand(); void processCommand();
void powerOnComputer();
void powerOffComputer();
void handleRepeatKey(); void handleRepeatKey();
void handleAnyPendingEvents(); void handleAnyPendingEvents();
@ -72,15 +74,11 @@ public:
void config(E2Config& cfg); void config(E2Config& cfg);
void init();
void powerOnComputer();
void powerOffComputer();
void toggleComputerPower();
void cycleDisplayType();
bool isSafeToQuit();
void tick50ms(); void tick50ms();
void toggleComputerPower();
void handlePaste();
bool isSafeToQuit();
}; };
#endif #endif

View File

@ -14,32 +14,34 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "keyboard.h" #include "keyboard.h"
#include "hypermode.h" #include "hypermode.h"
#include "keyboardbuffermode.h" #include "keyboardbuffermode.h"
#include <cstdlib>
Keyboard::Keyboard(KeypressQueue& q, HyperMode& fhyper, KeyboardBufferMode& buffered):
Keyboard::Keyboard(KeypressQueue& q, HyperMode& fhyper, KeyboardBufferMode& buffered) :
keys(q), keys(q),
fhyper(fhyper), fhyper(fhyper),
buffered(buffered), buffered(buffered),
latch(0xC1u), // TODO: randomize this a little latch(0),
cGet(0) cGet(0) {
{
} }
void Keyboard::clear() void Keyboard::powerOn() {
{ this->latch = 0xA1u + std::rand() % (0xFEu-0xA1+1u);
}
void Keyboard::clear() {
this->latch &= 0x7F; this->latch &= 0x7F;
} }
unsigned char Keyboard::get() unsigned char Keyboard::get() {
{
waitIfTooFast(); waitIfTooFast();
if (!this->buffered.isBuffered() || !(this->latch & 0x80)) if (!this->buffered.isBuffered() || !(this->latch & 0x80)) {
{ if (!this->keys.empty()) {
if (!this->keys.empty())
{
this->latch = this->keys.front() | 0x80; this->latch = this->keys.front() | 0x80;
this->keys.pop(); this->keys.pop();
} }
@ -47,28 +49,27 @@ unsigned char Keyboard::get()
return this->latch; return this->latch;
} }
void Keyboard::waitIfTooFast() void Keyboard::waitIfTooFast() {
{ // TODO remove all hyper stuff; it doesn't do anything anymore,
if (this->fhyper.isHyper()) // since the new architecture with wxTimer
{
return;
}
++this->cGet; // if (this->fhyper.isHyper()) {
if (!this->cGet) // return;
{ // }
if (SDL_GetTicks() - this->lastGet <= 1000) //
{ // ++this->cGet;
/* // if (!this->cGet) {
* Check every 256 gets to see if they are // if (SDL_GetTicks() - this->lastGet <= 1000) {
* happening too fast (within one second). // /*
* If so, it means we are probably just // * Check every 256 gets to see if they are
* looping waiting for a keypress, so // * happening too fast (within one second).
* wait a millisecond (or so) just to // * If so, it means we are probably just
* prevent us from using 100% of CPU time. // * looping waiting for a keypress, so
*/ // * wait a millisecond (or so) just to
SDL_Delay(1); // * prevent us from using 100% of CPU time.
} // */
} // SDL_Delay(1);
this->lastGet = SDL_GetTicks(); // }
// }
// this->lastGet = SDL_GetTicks();
} }

View File

@ -14,7 +14,7 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef KEYBOARD_H #ifndef KEYBOARD_H
#define KEYBOARD_H #define KEYBOARD_H
@ -26,9 +26,7 @@ typedef std::queue<unsigned char> KeypressQueue;
class HyperMode; class HyperMode;
class KeyboardBufferMode; class KeyboardBufferMode;
class Keyboard class Keyboard {
{
private:
KeypressQueue& keys; KeypressQueue& keys;
HyperMode& fhyper; HyperMode& fhyper;
KeyboardBufferMode& buffered; KeyboardBufferMode& buffered;
@ -41,6 +39,7 @@ private:
public: public:
Keyboard(KeypressQueue& q, HyperMode& fhyper, KeyboardBufferMode& buffered); Keyboard(KeypressQueue& q, HyperMode& fhyper, KeyboardBufferMode& buffered);
void powerOn();
void clear(); void clear();
unsigned char get(); unsigned char get();
}; };