fix kbd controls on Mac + misc.

After creating the drawing panel, call SetFocus() on it and use
Connect() to bind keyboard events from it. Add the wxWANTS_CHARS flag to
all DrawingArea subclasses so that wxEVT_CHAR_HOOK can be used instead
of wxEVT_KEY_DOWN, because it is more general and catches more keys.

Change the process_key_press function to return a bool indicating
whether a game control is currently pressed or not, this is used in the
key events to determine whether the event should be propagated or not.
If in a game key, do not propagate the event, otherwise it hits one of
the other controls and generates a beep sound.

The menu open/closed/highlighted events had to be turned off for Mac,
because the menubar is catching all keyboard events for some reason even
before they reach the drawing panel event handler. So on Mac the game
will not be paused when the menu is being used, this is not really a big
deal and can be fixed later.

Other improvements:

* do not bundle and link dylibs when CMAKE_BUILD_TYPE is not "Release",
  this makes for quicker debug builds

* finally make a generic PaintEv for the DrawingPanel abstract base
  class using dynamic_cast<> and Bind(), unfortunately this is not wx
  2.8 compatible

* set the default audio_buffers to 10 instead of 5, this completely or
  almost completely fixes sound stuttering during normal game play on
  Mac with OpenAL

* spew path info on startup only once
This commit is contained in:
Rafael Kitover 2016-11-02 18:14:58 -07:00
parent e609bb9c8c
commit a775cc409f
6 changed files with 65 additions and 69 deletions

View File

@ -247,8 +247,12 @@ if(APPLE)
SET(MACOSX_BUNDLE_ICON_FILE ${VBAM_ICON}) SET(MACOSX_BUNDLE_ICON_FILE ${VBAM_ICON})
SET_SOURCE_FILES_PROPERTIES(${VBAM_ICON_PATH} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) SET_SOURCE_FILES_PROPERTIES(${VBAM_ICON_PATH} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
ADD_CUSTOM_COMMAND(TARGET visualboyadvance-m POST_BUILD # budle dylibs and relink them for releasing .app
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/tools/osx/third_party_libs_tool "$<TARGET_FILE_DIR:visualboyadvance-m>/../..") # but only in Release mode
IF(CMAKE_BUILD_TYPE STREQUAL "Release")
ADD_CUSTOM_COMMAND(TARGET visualboyadvance-m POST_BUILD
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/tools/osx/third_party_libs_tool "$<TARGET_FILE_DIR:visualboyadvance-m>/../..")
ENDIF()
endif(APPLE) endif(APPLE)
SET(WX_EXE_NAME visualboyadvance-m-wx${CMAKE_EXECUTABLE_SUFFIX}) SET(WX_EXE_NAME visualboyadvance-m-wx${CMAKE_EXECUTABLE_SUFFIX})

View File

@ -8,14 +8,9 @@ public:
BasicDrawingPanel(wxWindow* parent, int _width, int _height); BasicDrawingPanel(wxWindow* parent, int _width, int _height);
protected: protected:
void PaintEv2(wxPaintEvent& ev)
{
PaintEv(ev);
}
void DrawArea(wxWindowDC& dc); void DrawArea(wxWindowDC& dc);
DECLARE_CLASS() DECLARE_CLASS()
DECLARE_EVENT_TABLE()
}; };
#ifndef NO_OGL #ifndef NO_OGL
@ -27,10 +22,6 @@ public:
virtual ~GLDrawingPanel(); virtual ~GLDrawingPanel();
protected: protected:
void PaintEv2(wxPaintEvent& ev)
{
PaintEv(ev);
}
void DrawArea(wxWindowDC& dc); void DrawArea(wxWindowDC& dc);
#if wxCHECK_VERSION(2, 9, 0) #if wxCHECK_VERSION(2, 9, 0)
wxGLContext* ctx; wxGLContext* ctx;
@ -40,7 +31,6 @@ protected:
int texsize; int texsize;
DECLARE_CLASS() DECLARE_CLASS()
DECLARE_EVENT_TABLE()
}; };
#endif #endif
@ -50,15 +40,10 @@ public:
DXDrawingPanel(wxWindow* parent, int _width, int _height); DXDrawingPanel(wxWindow* parent, int _width, int _height);
protected: protected:
void PaintEv2(wxPaintEvent& ev)
{
PaintEv(ev);
}
void DrawArea(wxWindowDC&); void DrawArea(wxWindowDC&);
void DrawingPanelInit(); void DrawingPanelInit();
DECLARE_CLASS() DECLARE_CLASS()
DECLARE_EVENT_TABLE()
}; };
#endif #endif
@ -71,15 +56,10 @@ public:
~CairoDrawingPanel(); ~CairoDrawingPanel();
protected: protected:
void PaintEv2(wxPaintEvent& ev)
{
PaintEv(ev);
}
void DrawArea(wxWindowDC&); void DrawArea(wxWindowDC&);
cairo_surface_t* conv_surf; cairo_surface_t* conv_surf;
DECLARE_CLASS() DECLARE_CLASS()
DECLARE_EVENT_TABLE()
}; };
#endif #endif

View File

@ -293,7 +293,10 @@ opts_t::opts_t()
if (max_threads < 0) if (max_threads < 0)
max_threads = 2; max_threads = 2;
audio_buffers = 5; // 10 fixes stuttering on mac with openal, as opposed to 5
// also should be better for modern hardware in general
audio_buffers = 10;
sound_en = 0x30f; sound_en = 0x30f;
sound_vol = 100; sound_vol = 100;
sound_qual = 1; sound_qual = 1;

View File

@ -1029,7 +1029,6 @@ void GameArea::OnIdle(wxIdleEvent& event)
wxWindow* w = panel->GetWindow(); wxWindow* w = panel->GetWindow();
w->SetBackgroundStyle(wxBG_STYLE_CUSTOM); w->SetBackgroundStyle(wxBG_STYLE_CUSTOM);
w->Enable(false); // never give it the keyboard focus
w->SetSize(wxSize(basic_width, basic_height)); w->SetSize(wxSize(basic_width, basic_height));
if (maxScale) if (maxScale)
@ -1045,6 +1044,13 @@ void GameArea::OnIdle(wxIdleEvent& event)
// if user changed Display/Scale config, this needs to run // if user changed Display/Scale config, this needs to run
AdjustMinSize(); AdjustMinSize();
AdjustSize(false); AdjustSize(false);
// set focus to panel
w->SetFocus();
// capture keyboard events
w->Connect(wxEVT_CHAR_HOOK, wxKeyEventHandler(GameArea::OnKeyDown), NULL, this);
w->Connect(wxEVT_KEY_UP, wxKeyEventHandler(GameArea::OnKeyUp), NULL, this);
} }
if (!paused && (!pauseWhenInactive || wxGetApp().frame->HasFocus())) { if (!paused && (!pauseWhenInactive || wxGetApp().frame->HasFocus())) {
@ -1125,8 +1131,10 @@ static uint32_t bmask[NUM_KEYS] = {
static wxJoyKeyBinding_v keys_pressed; static wxJoyKeyBinding_v keys_pressed;
static void process_key_press(bool down, int key, int mod, int joy = 0) static bool process_key_press(bool down, int key, int mod, int joy = 0)
{ {
static bool in_game_key = false;
// check if key is already pressed // check if key is already pressed
int kpno; int kpno;
@ -1137,14 +1145,14 @@ static void process_key_press(bool down, int key, int mod, int joy = 0)
if (kpno < keys_pressed.size()) { if (kpno < keys_pressed.size()) {
// double press is noop // double press is noop
if (down) if (down)
return; return in_game_key;
// otherwise forget it // otherwise forget it
keys_pressed.erase(keys_pressed.begin() + kpno); keys_pressed.erase(keys_pressed.begin() + kpno);
} else { } else {
// double release is noop // double release is noop
if (!down) if (!down)
return; return in_game_key;
// otherwise remember it // otherwise remember it
// c++0x // c++0x
@ -1153,6 +1161,8 @@ static void process_key_press(bool down, int key, int mod, int joy = 0)
keys_pressed.push_back(jb); keys_pressed.push_back(jb);
} }
bool matched_game_key = false;
// find all game keys this is bound to // find all game keys this is bound to
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
for (int j = 0; j < NUM_KEYS; j++) { for (int j = 0; j < NUM_KEYS; j++) {
@ -1160,8 +1170,10 @@ static void process_key_press(bool down, int key, int mod, int joy = 0)
for (int k = 0; k < b.size(); k++) for (int k = 0; k < b.size(); k++)
if (b[k].key == key && b[k].mod == mod && b[k].joy == joy) { if (b[k].key == key && b[k].mod == mod && b[k].joy == joy) {
if (down) if (down) {
joypress[i] |= bmask[j]; joypress[i] |= bmask[j];
matched_game_key = true;
}
else { else {
// only release if no others pressed // only release if no others pressed
int k2; int k2;
@ -1178,25 +1190,29 @@ static void process_key_press(bool down, int key, int mod, int joy = 0)
break; break;
} }
if (k2 == b.size()) if (k2 == b.size()) {
joypress[i] &= ~bmask[j]; joypress[i] &= ~bmask[j];
matched_game_key = true;
}
} }
break; break;
} }
} }
in_game_key = matched_game_key;
return in_game_key;
} }
void GameArea::OnKeyDown(wxKeyEvent& ev) void GameArea::OnKeyDown(wxKeyEvent& ev)
{ {
process_key_press(true, ev.GetKeyCode(), 0 /* ev.GetModifiers() */); ev.Skip(!process_key_press(true, ev.GetKeyCode(), 0 /* ev.GetModifiers() */));
ev.Skip(); // process accelerators
} }
void GameArea::OnKeyUp(wxKeyEvent& ev) void GameArea::OnKeyUp(wxKeyEvent& ev)
{ {
process_key_press(false, ev.GetKeyCode(), 0 /* ev.GetModifiers() */); ev.Skip(!process_key_press(false, ev.GetKeyCode(), 0 /* ev.GetModifiers() */));
ev.Skip(); // process accelerators
} }
void GameArea::OnSDLJoy(wxSDLJoyEvent& ev) void GameArea::OnSDLJoy(wxSDLJoyEvent& ev)
@ -1378,6 +1394,11 @@ DrawingPanel::DrawingPanel(int _width, int _height)
void DrawingPanel::DrawingPanelInit() void DrawingPanel::DrawingPanelInit()
{ {
wxWindow* w = dynamic_cast<wxWindow*>(this);
// this is not 2.8 compatible, sorry
w->Bind(wxEVT_PAINT, &DrawingPanel::PaintEv, this);
did_init = true; did_init = true;
} }
@ -1894,13 +1915,9 @@ DrawingPanel::~DrawingPanel()
IMPLEMENT_CLASS2(BasicDrawingPanel, DrawingPanel, wxPanel) IMPLEMENT_CLASS2(BasicDrawingPanel, DrawingPanel, wxPanel)
BEGIN_EVENT_TABLE(BasicDrawingPanel, wxPanel)
EVT_PAINT(BasicDrawingPanel::PaintEv2)
END_EVENT_TABLE()
BasicDrawingPanel::BasicDrawingPanel(wxWindow* parent, int _width, int _height) BasicDrawingPanel::BasicDrawingPanel(wxWindow* parent, int _width, int _height)
: wxPanel(parent, wxID_ANY, wxPoint(0, 0), parent->GetSize(), : wxPanel(parent, wxID_ANY, wxPoint(0, 0), parent->GetSize(),
wxFULL_REPAINT_ON_RESIZE) wxFULL_REPAINT_ON_RESIZE | wxWANTS_CHARS)
, DrawingPanel(_width, _height) , DrawingPanel(_width, _height)
{ {
// wxImage is 24-bit RGB, so 24-bit is preferred. Filters require // wxImage is 24-bit RGB, so 24-bit is preferred. Filters require
@ -1980,11 +1997,6 @@ void BasicDrawingPanel::DrawArea(wxWindowDC& dc)
IMPLEMENT_CLASS2(GLDrawingPanel, DrawingPanel, wxGLCanvas) IMPLEMENT_CLASS2(GLDrawingPanel, DrawingPanel, wxGLCanvas)
// this would be easier in 2.9
BEGIN_EVENT_TABLE(GLDrawingPanel, wxGLCanvas)
EVT_PAINT(GLDrawingPanel::PaintEv2)
END_EVENT_TABLE()
// This is supposed to be the default, but DOUBLEBUFFER doesn't seem to be // This is supposed to be the default, but DOUBLEBUFFER doesn't seem to be
// turned on by default for wxGTK. // turned on by default for wxGTK.
static int glopts[] = { static int glopts[] = {
@ -2001,7 +2013,7 @@ static int glopts[] = {
GLDrawingPanel::GLDrawingPanel(wxWindow* parent, int _width, int _height) GLDrawingPanel::GLDrawingPanel(wxWindow* parent, int _width, int _height)
: glc(parent, wxID_ANY, glopts, wxPoint(0, 0), parent->GetSize(), : glc(parent, wxID_ANY, glopts, wxPoint(0, 0), parent->GetSize(),
wxFULL_REPAINT_ON_RESIZE) wxFULL_REPAINT_ON_RESIZE | wxWANTS_CHARS)
, DrawingPanel(_width, _height) , DrawingPanel(_width, _height)
{ {
#ifdef __WXMAC__ #ifdef __WXMAC__
@ -2166,13 +2178,9 @@ void GLDrawingPanel::DrawArea(wxWindowDC& dc)
IMPLEMENT_CLASS(CairoDrawingPanel, DrawingPanel) IMPLEMENT_CLASS(CairoDrawingPanel, DrawingPanel)
BEGIN_EVENT_TABLE(CairoDrawingPanel, wxPanel)
EVT_PAINT(CairoDrawingPanel::PaintEv2)
END_EVENT_TABLE()
CairoDrawingPanel::CairoDrawingPanel(wxWindow* parent, int _width, int _height) CairoDrawingPanel::CairoDrawingPanel(wxWindow* parent, int _width, int _height)
: wxPanel(parent, wxID_ANY, wxPoint(0, 0), parent->GetSize(), : wxPanel(parent, wxID_ANY, wxPoint(0, 0), parent->GetSize(),
wxFULL_REPAINT_ON_RESIZE) wxFULL_REPAINT_ON_RESIZE | wxWANTS_CHARS)
, DrawingPanel(_width, _height) , DrawingPanel(_width, _height)
{ {
conv_surf = NULL; conv_surf = NULL;
@ -2295,13 +2303,9 @@ void CairoDrawingPanel::DrawArea(wxWindowDC& dc)
IMPLEMENT_CLASS(DXDrawingPanel, DrawingPanel) IMPLEMENT_CLASS(DXDrawingPanel, DrawingPanel)
BEGIN_EVENT_TABLE(DXDrawingPanel, wxPanel)
EVT_PAINT(DXDrawingPanel::PaintEv2)
END_EVENT_TABLE()
DXDrawingPanel::DXDrawingPanel(wxWindow* parent, int _width, int _height) DXDrawingPanel::DXDrawingPanel(wxWindow* parent, int _width, int _height)
: wxPanel(parent, wxID_ANY, wxPoint(0, 0), parent->GetSize(), : wxPanel(parent, wxID_ANY, wxPoint(0, 0), parent->GetSize(),
wxFULL_REPAINT_ON_RESIZE) wxFULL_REPAINT_ON_RESIZE | wxWANTS_CHARS)
, DrawingPanel(_width, _height) , DrawingPanel(_width, _height)
{ {
// FIXME: implement // FIXME: implement

View File

@ -71,13 +71,19 @@ static void get_config_path(wxPathList& path, bool exists = true)
path.Add(s); \ path.Add(s); \
} while (0) } while (0)
vbamDebug("GetUserLocalDataDir(): %s", static_cast<const char*>(stdp.GetUserLocalDataDir().utf8_str())); static bool debug_dumped = false;
vbamDebug("GetUserDataDir(): %s", static_cast<const char*>(stdp.GetUserDataDir().utf8_str()));
vbamDebug("GetLocalizedResourcesDir(wxGetApp().locale.GetCanonicalName()): %s", static_cast<const char*>(stdp.GetLocalizedResourcesDir(wxGetApp().locale.GetCanonicalName()).utf8_str())); if (!debug_dumped) {
vbamDebug("GetResourcesDir(): %s", static_cast<const char*>(stdp.GetResourcesDir().utf8_str())); vbamDebug("GetUserLocalDataDir(): %s", static_cast<const char*>(stdp.GetUserLocalDataDir().utf8_str()));
vbamDebug("GetDataDir(): %s", static_cast<const char*>(stdp.GetDataDir().utf8_str())); vbamDebug("GetUserDataDir(): %s", static_cast<const char*>(stdp.GetUserDataDir().utf8_str()));
vbamDebug("GetLocalDataDir(): %s", static_cast<const char*>(stdp.GetLocalDataDir().utf8_str())); vbamDebug("GetLocalizedResourcesDir(wxGetApp().locale.GetCanonicalName()): %s", static_cast<const char*>(stdp.GetLocalizedResourcesDir(wxGetApp().locale.GetCanonicalName()).utf8_str()));
vbamDebug("GetPluginsDir(): %s", static_cast<const char*>(stdp.GetPluginsDir().utf8_str())); vbamDebug("GetResourcesDir(): %s", static_cast<const char*>(stdp.GetResourcesDir().utf8_str()));
vbamDebug("GetDataDir(): %s", static_cast<const char*>(stdp.GetDataDir().utf8_str()));
vbamDebug("GetLocalDataDir(): %s", static_cast<const char*>(stdp.GetLocalDataDir().utf8_str()));
vbamDebug("GetPluginsDir(): %s", static_cast<const char*>(stdp.GetPluginsDir().utf8_str()));
debug_dumped = true;
}
// NOTE: this does not support XDG (freedesktop.org) paths // NOTE: this does not support XDG (freedesktop.org) paths
add_path(GetUserLocalDataDir()); add_path(GetUserLocalDataDir());
@ -591,10 +597,16 @@ EVT_CONTEXT_MENU(MainFrame::OnMenu)
EVT_ACTIVATE(MainFrame::OnActivate) EVT_ACTIVATE(MainFrame::OnActivate)
// requires DragAcceptFiles(true); even then may not do anything // requires DragAcceptFiles(true); even then may not do anything
EVT_DROP_FILES(MainFrame::OnDropFile) EVT_DROP_FILES(MainFrame::OnDropFile)
// pause game if menu pops up // pause game if menu pops up
//
// this causes problems with keyboard game keys on mac, disable for now
#ifndef __WXMAC__
EVT_MENU_OPEN(MainFrame::MenuPopped) EVT_MENU_OPEN(MainFrame::MenuPopped)
EVT_MENU_CLOSE(MainFrame::MenuPopped) EVT_MENU_CLOSE(MainFrame::MenuPopped)
EVT_MENU_HIGHLIGHT_ALL(MainFrame::MenuPopped) EVT_MENU_HIGHLIGHT_ALL(MainFrame::MenuPopped)
#endif
END_EVENT_TABLE() END_EVENT_TABLE()
void MainFrame::OnActivate(wxActivateEvent& event) void MainFrame::OnActivate(wxActivateEvent& event)

View File

@ -630,10 +630,10 @@ public:
void DrawArea(uint8_t** pixels); void DrawArea(uint8_t** pixels);
// using dynamic_cast<> to not force trivial reimplementation in concrete classes // using dynamic_cast<> to not force trivial reimplementation in concrete classes
// TODO: figure something out for PaintEv as well
virtual wxWindow* GetWindow() { return dynamic_cast<wxWindow*>(this); } virtual wxWindow* GetWindow() { return dynamic_cast<wxWindow*>(this); }
virtual void Delete() { (dynamic_cast<wxWindow*>(this))->Destroy(); } virtual void Delete() { (dynamic_cast<wxWindow*>(this))->Destroy(); }
void PaintEv(wxPaintEvent& ev);
protected: protected:
virtual void DrawArea(wxWindowDC&) = 0; virtual void DrawArea(wxWindowDC&) = 0;
virtual void DrawOSD(wxWindowDC&); virtual void DrawOSD(wxWindowDC&);
@ -651,13 +651,6 @@ protected:
// largest buffer required is 32-bit * (max width + 1) * (max height + 2) // largest buffer required is 32-bit * (max width + 1) * (max height + 2)
uint8_t delta[257 * 4 * 226]; uint8_t delta[257 * 4 * 226];
// following can't work in 2.8 as intended
// inheriting from wxEvtHandler is required, but also breaks subclasses
// due to lack of virtual inheritance (2.9 drops wxEvtHandler req)
// so each child must have a paint event handler (not override of this,
// but it's not virtual anyway, so that won't happen) that calls this
void PaintEv(wxPaintEvent& ev);
DECLARE_ABSTRACT_CLASS() DECLARE_ABSTRACT_CLASS()
}; };