Add support for more than 4 joystick buttons under MSW
Use polling thread instead of relying on MM_JOYXXX events to allow receiving events from all the supported buttons. See https://github.com/wxWidgets/wxWidgets/pull/942 Closes #1142.
This commit is contained in:
parent
7872b9fd38
commit
a02ed536e6
@ -141,6 +141,7 @@ wxMSW:
|
||||
- Add experimental support for Windows 10/ARM64 platform (Simon Rozman).
|
||||
- Fix hang after clearing wxTAB_TRAVERSAL style on a window with children.
|
||||
- Fix handling of AUX2 mouse button events (Timon Rozmanrylz).
|
||||
- Implement support for more than 4 joystick buttons (Mick Phillips).
|
||||
- Fix saving/restoring window position for maximized windows.
|
||||
- Fix stack corruption when using wxStackWalker (srfisk).
|
||||
- Fix positioning windows at positions >= SHORT_MAX (Cătălin Răceanu).
|
||||
|
@ -13,6 +13,8 @@
|
||||
|
||||
#include "wx/event.h"
|
||||
|
||||
class wxJoystickThread;
|
||||
|
||||
class WXDLLIMPEXP_ADV wxJoystick: public wxObject
|
||||
{
|
||||
wxDECLARE_DYNAMIC_CLASS(wxJoystick);
|
||||
@ -22,6 +24,7 @@ public:
|
||||
*/
|
||||
|
||||
wxJoystick(int joystick = wxJOYSTICK1);
|
||||
virtual ~wxJoystick();
|
||||
|
||||
// Attributes
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
@ -85,6 +88,7 @@ public:
|
||||
|
||||
protected:
|
||||
int m_joystick;
|
||||
wxJoystickThread* m_thread;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -37,8 +37,129 @@
|
||||
|
||||
#include <regstr.h>
|
||||
|
||||
// Use optimised count trailing zeros where available.
|
||||
static int wxCtz(unsigned x)
|
||||
{
|
||||
wxCHECK_MSG(x > 0, 0, "Undefined for x == 0.");
|
||||
#ifdef __GNUC__
|
||||
return __builtin_ctz(x);
|
||||
#else
|
||||
int n;
|
||||
n = 1;
|
||||
if ((x & 0x0000FFFF) == 0) {n = n +16; x = x >>16;}
|
||||
if ((x & 0x000000FF) == 0) {n = n + 8; x = x >> 8;}
|
||||
if ((x & 0x0000000F) == 0) {n = n + 4; x = x >> 4;}
|
||||
if ((x & 0x00000003) == 0) {n = n + 2; x = x >> 2;}
|
||||
return n - (x & 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
enum {
|
||||
wxJS_AXIS_X = 0,
|
||||
wxJS_AXIS_Y,
|
||||
wxJS_AXIS_Z,
|
||||
wxJS_AXIS_RUDDER,
|
||||
wxJS_AXIS_U,
|
||||
wxJS_AXIS_V,
|
||||
|
||||
wxJS_AXIS_MAX = 32767,
|
||||
wxJS_AXIS_MIN = -32767,
|
||||
wxJS_MAX_AXES = 6, // WinMM supports up to 6 axes.
|
||||
wxJS_MAX_BUTTONS = 32, // WinMM supports up to 32 buttons.
|
||||
};
|
||||
|
||||
wxIMPLEMENT_DYNAMIC_CLASS(wxJoystick, wxObject);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Background thread for reading the joystick device
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class wxJoystickThread : public wxThread
|
||||
{
|
||||
public:
|
||||
explicit wxJoystickThread(int joystick);
|
||||
void* Entry() wxOVERRIDE;
|
||||
void SetPolling(wxWindow* win, int pollingFreq)
|
||||
{
|
||||
m_catchwin = win;
|
||||
m_polling = pollingFreq;
|
||||
};
|
||||
|
||||
|
||||
private:
|
||||
void SendEvent(wxEventType type, long ts, int change = 0);
|
||||
int m_joystick;
|
||||
UINT m_buttons;
|
||||
wxWindow* m_catchwin;
|
||||
int m_polling;
|
||||
JOYINFO m_joyInfo;
|
||||
JOYINFO m_lastJoyInfo;
|
||||
};
|
||||
|
||||
|
||||
wxJoystickThread::wxJoystickThread(int joystick)
|
||||
: m_joystick(joystick),
|
||||
m_buttons(0),
|
||||
m_catchwin(NULL),
|
||||
m_polling(0),
|
||||
m_joyInfo(),
|
||||
m_lastJoyInfo()
|
||||
{
|
||||
}
|
||||
|
||||
void wxJoystickThread::SendEvent(wxEventType type, long ts, int change)
|
||||
{
|
||||
wxJoystickEvent joystickEvent(type, (int)m_buttons, m_joystick, change);
|
||||
|
||||
joystickEvent.SetTimestamp(ts);
|
||||
joystickEvent.SetPosition(wxPoint( (int)m_joyInfo.wXpos, (int)m_joyInfo.wYpos) );
|
||||
joystickEvent.SetZPosition( (int)m_joyInfo.wZpos );
|
||||
joystickEvent.SetEventObject(m_catchwin);
|
||||
|
||||
if (m_catchwin)
|
||||
m_catchwin->GetEventHandler()->ProcessThreadEvent(joystickEvent);
|
||||
}
|
||||
|
||||
void* wxJoystickThread::Entry()
|
||||
{
|
||||
joyGetPos(m_joystick, &m_lastJoyInfo);
|
||||
|
||||
while (!TestDestroy())
|
||||
{
|
||||
Sleep(m_polling);
|
||||
long ts = GetTickCount();
|
||||
|
||||
joyGetPos(m_joystick, &m_joyInfo);
|
||||
m_buttons = m_joyInfo.wButtons;
|
||||
UINT delta = m_buttons ^ m_lastJoyInfo.wButtons;
|
||||
UINT deltaUp = delta & !m_buttons;
|
||||
UINT deltaDown = delta & m_buttons;
|
||||
|
||||
// Use count trailing zeros to determine which button changed.
|
||||
// Was using JOYINFOEX.dwButtons, because the docs state this is
|
||||
// "Current button number that is pressed.", but it turns out
|
||||
// it is the *total* number of buttons pressed.
|
||||
if (deltaUp)
|
||||
SendEvent(wxEVT_JOY_BUTTON_UP, ts, wxCtz(deltaUp)+1);
|
||||
if (deltaDown)
|
||||
SendEvent(wxEVT_JOY_BUTTON_DOWN, ts, wxCtz(deltaDown)+1);
|
||||
|
||||
if ((m_joyInfo.wXpos != m_lastJoyInfo.wXpos) ||
|
||||
(m_joyInfo.wYpos != m_lastJoyInfo.wYpos) ||
|
||||
(m_joyInfo.wZpos != m_lastJoyInfo.wZpos) )
|
||||
{
|
||||
SendEvent(wxEVT_JOY_MOVE, ts);
|
||||
}
|
||||
|
||||
m_lastJoyInfo = m_joyInfo;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Attributes
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -62,6 +183,8 @@ wxJoystick::wxJoystick(int joystick)
|
||||
{
|
||||
/* Found the one we want, store actual OS id and return */
|
||||
m_joystick = i;
|
||||
m_thread = new wxJoystickThread(m_joystick);
|
||||
m_thread->Run();
|
||||
return;
|
||||
}
|
||||
joystick --;
|
||||
@ -73,6 +196,15 @@ wxJoystick::wxJoystick(int joystick)
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
wxJoystick::~wxJoystick()
|
||||
{
|
||||
ReleaseCapture();
|
||||
if (m_thread)
|
||||
m_thread->Delete(); // It's detached so it will delete itself
|
||||
}
|
||||
|
||||
|
||||
wxPoint wxJoystick::GetPosition() const
|
||||
{
|
||||
JOYINFO joyInfo;
|
||||
@ -256,7 +388,7 @@ int wxJoystick::GetMovementThreshold() const
|
||||
MMRESULT res = joyGetThreshold(m_joystick, & thresh);
|
||||
if (res == JOYERR_NOERROR )
|
||||
{
|
||||
return thresh;
|
||||
return (int)thresh;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
@ -264,8 +396,7 @@ int wxJoystick::GetMovementThreshold() const
|
||||
|
||||
void wxJoystick::SetMovementThreshold(int threshold)
|
||||
{
|
||||
UINT thresh = threshold;
|
||||
joySetThreshold(m_joystick, thresh);
|
||||
joySetThreshold(m_joystick, (UINT)threshold);
|
||||
}
|
||||
|
||||
// Capabilities
|
||||
@ -578,26 +709,28 @@ bool wxJoystick::HasPOVCTS() const
|
||||
return ((joyCaps.wCaps & JOYCAPS_POVCTS) == JOYCAPS_POVCTS);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Operations
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool wxJoystick::SetCapture(wxWindow* win, int pollingFreq)
|
||||
{
|
||||
#ifdef __WXMSW__
|
||||
BOOL changed = (pollingFreq == 0);
|
||||
MMRESULT res = joySetCapture((HWND) win->GetHWND(), m_joystick, pollingFreq, changed);
|
||||
return (res == JOYERR_NOERROR);
|
||||
#else
|
||||
wxUnusedVar(win);
|
||||
wxUnusedVar(pollingFreq);
|
||||
if (m_thread)
|
||||
{
|
||||
m_thread->SetPolling(win, pollingFreq);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool wxJoystick::ReleaseCapture()
|
||||
{
|
||||
MMRESULT res = joyReleaseCapture(m_joystick);
|
||||
return (res == JOYERR_NOERROR);
|
||||
if (m_thread)
|
||||
{
|
||||
m_thread->SetPolling(NULL, 0);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif // wxUSE_JOYSTICK
|
||||
|
@ -3133,19 +3133,6 @@ wxWindowMSW::MSWHandleMessage(WXLRESULT *result,
|
||||
}
|
||||
break;
|
||||
|
||||
case MM_JOY1MOVE:
|
||||
case MM_JOY2MOVE:
|
||||
case MM_JOY1ZMOVE:
|
||||
case MM_JOY2ZMOVE:
|
||||
case MM_JOY1BUTTONDOWN:
|
||||
case MM_JOY2BUTTONDOWN:
|
||||
case MM_JOY1BUTTONUP:
|
||||
case MM_JOY2BUTTONUP:
|
||||
processed = HandleJoystickEvent(message,
|
||||
LOWORD(lParam),
|
||||
HIWORD(lParam),
|
||||
wParam);
|
||||
break;
|
||||
|
||||
case WM_COMMAND:
|
||||
{
|
||||
@ -6162,92 +6149,6 @@ bool wxWindowMSW::HandleClipboardEvent(WXUINT nMsg)
|
||||
return HandleWindowEvent(evt);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// joystick
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
bool wxWindowMSW::HandleJoystickEvent(WXUINT msg, int x, int y, WXUINT flags)
|
||||
{
|
||||
int change = 0;
|
||||
if ( flags & JOY_BUTTON1CHG )
|
||||
change = wxJOY_BUTTON1;
|
||||
if ( flags & JOY_BUTTON2CHG )
|
||||
change = wxJOY_BUTTON2;
|
||||
if ( flags & JOY_BUTTON3CHG )
|
||||
change = wxJOY_BUTTON3;
|
||||
if ( flags & JOY_BUTTON4CHG )
|
||||
change = wxJOY_BUTTON4;
|
||||
|
||||
int buttons = 0;
|
||||
if ( flags & JOY_BUTTON1 )
|
||||
buttons |= wxJOY_BUTTON1;
|
||||
if ( flags & JOY_BUTTON2 )
|
||||
buttons |= wxJOY_BUTTON2;
|
||||
if ( flags & JOY_BUTTON3 )
|
||||
buttons |= wxJOY_BUTTON3;
|
||||
if ( flags & JOY_BUTTON4 )
|
||||
buttons |= wxJOY_BUTTON4;
|
||||
|
||||
// the event ids aren't consecutive so we can't use table based lookup
|
||||
int joystick;
|
||||
wxEventType eventType;
|
||||
switch ( msg )
|
||||
{
|
||||
case MM_JOY1MOVE:
|
||||
joystick = 1;
|
||||
eventType = wxEVT_JOY_MOVE;
|
||||
break;
|
||||
|
||||
case MM_JOY2MOVE:
|
||||
joystick = 2;
|
||||
eventType = wxEVT_JOY_MOVE;
|
||||
break;
|
||||
|
||||
case MM_JOY1ZMOVE:
|
||||
joystick = 1;
|
||||
eventType = wxEVT_JOY_ZMOVE;
|
||||
break;
|
||||
|
||||
case MM_JOY2ZMOVE:
|
||||
joystick = 2;
|
||||
eventType = wxEVT_JOY_ZMOVE;
|
||||
break;
|
||||
|
||||
case MM_JOY1BUTTONDOWN:
|
||||
joystick = 1;
|
||||
eventType = wxEVT_JOY_BUTTON_DOWN;
|
||||
break;
|
||||
|
||||
case MM_JOY2BUTTONDOWN:
|
||||
joystick = 2;
|
||||
eventType = wxEVT_JOY_BUTTON_DOWN;
|
||||
break;
|
||||
|
||||
case MM_JOY1BUTTONUP:
|
||||
joystick = 1;
|
||||
eventType = wxEVT_JOY_BUTTON_UP;
|
||||
break;
|
||||
|
||||
case MM_JOY2BUTTONUP:
|
||||
joystick = 2;
|
||||
eventType = wxEVT_JOY_BUTTON_UP;
|
||||
break;
|
||||
|
||||
default:
|
||||
wxFAIL_MSG(wxT("no such joystick event"));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
wxJoystickEvent event(eventType, buttons, joystick, change);
|
||||
if ( eventType == wxEVT_JOY_ZMOVE )
|
||||
event.SetZPosition(x);
|
||||
else
|
||||
event.SetPosition(wxPoint(x, y));
|
||||
event.SetEventObject(this);
|
||||
|
||||
return HandleWindowEvent(event);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// scrolling
|
||||
|
Loading…
Reference in New Issue
Block a user