///////////////////////////////////////////////////////////////////////////// // Name: src/msw/joystick.cpp // Purpose: wxJoystick class // Author: Julian Smart // Modified by: // Created: 04/01/98 // Copyright: (c) Julian Smart // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" #if wxUSE_JOYSTICK #include "wx/joystick.h" #ifndef WX_PRECOMP #include "wx/string.h" #include "wx/window.h" #endif #include "wx/msw/private.h" #include #include "wx/msw/registry.h" #include 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; int 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, deltaUp); if (deltaDown) SendEvent(wxEVT_JOY_BUTTON_DOWN, ts, deltaDown); 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 //////////////////////////////////////////////////////////////////////////// /** johan@linkdata.se 2002-08-20: Now returns only valid, functioning joysticks, counting from the first available and upwards. */ wxJoystick::wxJoystick(int joystick) { JOYINFO joyInfo; int i, maxsticks; m_thread = NULL; maxsticks = joyGetNumDevs(); for( i=0; iRun(); return; } joystick --; } } /* No such joystick, return ID 0 */ m_joystick = 0; return; } wxJoystick::~wxJoystick() { ReleaseCapture(); if (m_thread) m_thread->Delete(); // It's detached so it will delete itself } wxPoint wxJoystick::GetPosition() const { JOYINFO joyInfo; MMRESULT res = joyGetPos(m_joystick, & joyInfo); if (res == JOYERR_NOERROR ) return wxPoint(joyInfo.wXpos, joyInfo.wYpos); else return wxPoint(0,0); } int wxJoystick::GetPosition(unsigned axis) const { switch (axis) { case 0: return GetPosition().x; case 1: return GetPosition().y; case 2: return GetZPosition(); case 3: return GetRudderPosition(); case 4: return GetUPosition(); case 5: return GetVPosition(); default: return 0; } } int wxJoystick::GetZPosition() const { JOYINFO joyInfo; MMRESULT res = joyGetPos(m_joystick, & joyInfo); if (res == JOYERR_NOERROR ) return joyInfo.wZpos; else return 0; } /** johan@linkdata.se 2002-08-20: Return a bitmap with all button states in it, like the GTK version does and Win32 does. */ int wxJoystick::GetButtonState() const { JOYINFO joyInfo; MMRESULT res = joyGetPos(m_joystick, & joyInfo); if (res == JOYERR_NOERROR ) { return joyInfo.wButtons; #if 0 int buttons = 0; if (joyInfo.wButtons & JOY_BUTTON1) buttons |= wxJOY_BUTTON1; if (joyInfo.wButtons & JOY_BUTTON2) buttons |= wxJOY_BUTTON2; if (joyInfo.wButtons & JOY_BUTTON3) buttons |= wxJOY_BUTTON3; if (joyInfo.wButtons & JOY_BUTTON4) buttons |= wxJOY_BUTTON4; return buttons; #endif } else return 0; } bool wxJoystick::GetButtonState(unsigned id) const { if (id >= sizeof(int) * 8) return false; return (GetButtonState() & (1 << id)) != 0; } /** JLI 2002-08-20: Returns -1 to signify error. */ int wxJoystick::GetPOVPosition() const { #ifndef NO_JOYGETPOSEX JOYINFOEX joyInfo; joyInfo.dwFlags = JOY_RETURNPOV; joyInfo.dwSize = sizeof(joyInfo); MMRESULT res = joyGetPosEx(m_joystick, & joyInfo); if (res == JOYERR_NOERROR ) { return joyInfo.dwPOV; } else return -1; #else return -1; #endif } /** johan@linkdata.se 2002-08-20: Returns -1 to signify error. */ int wxJoystick::GetPOVCTSPosition() const { #ifndef NO_JOYGETPOSEX JOYINFOEX joyInfo; joyInfo.dwFlags = JOY_RETURNPOVCTS; joyInfo.dwSize = sizeof(joyInfo); MMRESULT res = joyGetPosEx(m_joystick, & joyInfo); if (res == JOYERR_NOERROR ) { return joyInfo.dwPOV; } else return -1; #else return -1; #endif } int wxJoystick::GetRudderPosition() const { #ifndef NO_JOYGETPOSEX JOYINFOEX joyInfo; joyInfo.dwFlags = JOY_RETURNR; joyInfo.dwSize = sizeof(joyInfo); MMRESULT res = joyGetPosEx(m_joystick, & joyInfo); if (res == JOYERR_NOERROR ) { return joyInfo.dwRpos; } else return 0; #else return 0; #endif } int wxJoystick::GetUPosition() const { #ifndef NO_JOYGETPOSEX JOYINFOEX joyInfo; joyInfo.dwFlags = JOY_RETURNU; joyInfo.dwSize = sizeof(joyInfo); MMRESULT res = joyGetPosEx(m_joystick, & joyInfo); if (res == JOYERR_NOERROR ) { return joyInfo.dwUpos; } else return 0; #else return 0; #endif } int wxJoystick::GetVPosition() const { #ifndef NO_JOYGETPOSEX JOYINFOEX joyInfo; joyInfo.dwFlags = JOY_RETURNV; joyInfo.dwSize = sizeof(joyInfo); MMRESULT res = joyGetPosEx(m_joystick, & joyInfo); if (res == JOYERR_NOERROR ) { return joyInfo.dwVpos; } else return 0; #else return 0; #endif } int wxJoystick::GetMovementThreshold() const { UINT thresh = 0; MMRESULT res = joyGetThreshold(m_joystick, & thresh); if (res == JOYERR_NOERROR ) { return (int)thresh; } else return 0; } void wxJoystick::SetMovementThreshold(int threshold) { joySetThreshold(m_joystick, (UINT)threshold); } // Capabilities //////////////////////////////////////////////////////////////////////////// /** johan@linkdata.se 2002-08-20: Now returns the number of connected, functioning joysticks, as intended. */ int wxJoystick::GetNumberJoysticks() { JOYINFO joyInfo; int i, maxsticks, actualsticks; maxsticks = joyGetNumDevs(); actualsticks = 0; for( i=0; iSetPolling(win, pollingFreq); return true; } return false; } bool wxJoystick::ReleaseCapture() { if (m_thread) { m_thread->SetPolling(NULL, 0); return true; } return false; } #endif // wxUSE_JOYSTICK