X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/14f355c2b5c71fc7c3d680aea366582d2ac60f7b..6f026b5b63fe7ccb025e84509886f74772b9df13:/src/unix/joystick.cpp diff --git a/src/unix/joystick.cpp b/src/unix/joystick.cpp index 2ea86f9a8d..cf9cc33b3e 100644 --- a/src/unix/joystick.cpp +++ b/src/unix/joystick.cpp @@ -1,27 +1,28 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: joystick.cpp +// Name: src/unix/joystick.cpp // Purpose: wxJoystick class // Author: Ported to Linux by Guilhem Lavaux // Modified by: // Created: 05/23/98 -// RCS-ID: $Id$ // Copyright: (c) Guilhem Lavaux -// Licence: wxWindows licence +// Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// -#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) -#pragma implementation "joystick.h" -#endif - // for compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" -#include "wx/defs.h" - #if wxUSE_JOYSTICK #include "wx/joystick.h" +#ifndef WX_PRECOMP + #include "wx/event.h" + #include "wx/window.h" + #include "wx/log.h" +#endif //WX_PRECOMP + +#include "wx/thread.h" + #include #include #include @@ -30,324 +31,481 @@ #include #include -#include "wx/event.h" -#include "wx/window.h" +#ifdef HAVE_SYS_SELECT_H +# include +#endif + +#include "wx/unix/private.h" -#define JOYSTICK_AXE_MAX 32767 -#define JOYSTICK_AXE_MIN -32767 +enum { + wxJS_AXIS_X = 0, + wxJS_AXIS_Y, + wxJS_AXIS_Z, + wxJS_AXIS_RUDDER, + wxJS_AXIS_U, + wxJS_AXIS_V, -IMPLEMENT_DYNAMIC_CLASS(wxJoystick, wxObject) + wxJS_AXIS_MAX = 32767, + wxJS_AXIS_MIN = -32767, + wxJS_MAX_AXES = 15, + wxJS_MAX_BUTTONS = sizeof(int) * 8 +}; -wxJoystick::wxJoystick(int joystick) -{ - wxString dev_name; - // Assume it's the same device name on all Linux systems ... - dev_name.Printf( wxT("/dev/js%d"), (joystick == wxJOYSTICK1) ? 0 : 1); // FIXME Unicode? - m_joystick = open(dev_name.fn_str(), O_RDWR); - m_lastposition = wxPoint(-1, -1); - for (int i=0;i<15;i++) - m_axe[i] = 0; - if (m_joystick != -1) - Create(); -} +IMPLEMENT_DYNAMIC_CLASS(wxJoystick, wxObject) + //////////////////////////////////////////////////////////////////////////// -// Background thread +// Background thread for reading the joystick device //////////////////////////////////////////////////////////////////////////// -void *wxJoystick::Entry(void) -{ - struct js_event j_evt; - wxJoystickEvent jwx_event; - fd_set read_fds; - struct timeval time_out = {0, 0}; - - FD_ZERO(&read_fds); - while (1) { - TestDestroy(); - - if (m_polling) { - FD_SET(m_joystick, &read_fds); - select(m_joystick+1, &read_fds, NULL, NULL, &time_out); - if (FD_ISSET(m_joystick, &read_fds)) - read(m_joystick, &j_evt, sizeof(j_evt)); - else - j_evt.type = 0; - } else { - read(m_joystick, &j_evt, sizeof(j_evt)); + +class wxJoystickThread : public wxThread +{ +public: + wxJoystickThread(int device, int joystick); + void* Entry(); + +private: + void SendEvent(wxEventType type, long ts, int change = 0); + int m_device; + int m_joystick; + wxPoint m_lastposition; + int m_axe[wxJS_MAX_AXES]; + int m_buttons; + wxWindow* m_catchwin; + int m_polling; + int m_threshold; + + friend class wxJoystick; +}; + + +wxJoystickThread::wxJoystickThread(int device, int joystick) + : m_device(device), + m_joystick(joystick), + m_lastposition(wxDefaultPosition), + m_buttons(0), + m_catchwin(NULL), + m_polling(0), + m_threshold(0) +{ + memset(m_axe, 0, sizeof(m_axe)); +} + +void wxJoystickThread::SendEvent(wxEventType type, long ts, int change) +{ + wxJoystickEvent jwx_event(type, m_buttons, m_joystick, change); + + jwx_event.SetTimestamp(ts); + jwx_event.SetPosition(m_lastposition); + jwx_event.SetZPosition(m_axe[wxJS_AXIS_Z]); + jwx_event.SetEventObject(m_catchwin); + + if (m_catchwin) + m_catchwin->GetEventHandler()->AddPendingEvent(jwx_event); +} + +void* wxJoystickThread::Entry() +{ + struct js_event j_evt; + fd_set read_fds; + struct timeval time_out = {0, 0}; + + wxFD_ZERO(&read_fds); + while (true) + { + if (TestDestroy()) + break; + + // We use select when either polling or 'blocking' as even in the + // blocking case we need to check TestDestroy periodically + if (m_polling) + time_out.tv_usec = m_polling * 1000; + else + time_out.tv_usec = 10 * 1000; // check at least every 10 msec in blocking case + + wxFD_SET(m_device, &read_fds); + select(m_device+1, &read_fds, NULL, NULL, &time_out); + if (wxFD_ISSET(m_device, &read_fds)) + { + memset(&j_evt, 0, sizeof(j_evt)); + read(m_device, &j_evt, sizeof(j_evt)); + + //printf("time: %d\t value: %d\t type: %d\t number: %d\n", + // j_evt.time, j_evt.value, j_evt.type, j_evt.number); + + if ((j_evt.type & JS_EVENT_AXIS) && (j_evt.number < wxJS_MAX_AXES)) + { + // Ignore invalid axis. + if ( j_evt.number >= wxJS_MAX_AXES ) + { + wxLogDebug(wxS("Invalid axis index %d in joystick message."), + j_evt.number); + continue; + } + + if ( (m_axe[j_evt.number] + m_threshold < j_evt.value) + || (m_axe[j_evt.number] - m_threshold > j_evt.value) ) + { + m_axe[j_evt.number] = j_evt.value; + + switch (j_evt.number) + { + case wxJS_AXIS_X: + m_lastposition.x = j_evt.value; + SendEvent(wxEVT_JOY_MOVE, j_evt.time); + break; + case wxJS_AXIS_Y: + m_lastposition.y = j_evt.value; + SendEvent(wxEVT_JOY_MOVE, j_evt.time); + break; + case wxJS_AXIS_Z: + SendEvent(wxEVT_JOY_ZMOVE, j_evt.time); + break; + default: + SendEvent(wxEVT_JOY_MOVE, j_evt.time); + // TODO: There should be a way to indicate that the event + // is for some other axes. + break; + } + } + } + + if ( (j_evt.type & JS_EVENT_BUTTON) && (j_evt.number < wxJS_MAX_BUTTONS) ) + { + if (j_evt.value) + { + m_buttons |= (1 << j_evt.number); + SendEvent(wxEVT_JOY_BUTTON_DOWN, j_evt.time, j_evt.number); + } + else + { + m_buttons &= ~(1 << j_evt.number); + SendEvent(wxEVT_JOY_BUTTON_UP, j_evt.time, j_evt.number); + } + } + } } - if ((j_evt.type & JS_EVENT_AXIS) == JS_EVENT_AXIS) { - switch (j_evt.number) { - case 1: - m_lastposition.x = j_evt.value; - jwx_event.SetEventType(wxEVT_JOY_MOVE); - break; - case 2: - m_lastposition.y = j_evt.value; - jwx_event.SetEventType(wxEVT_JOY_MOVE); - break; - case 3: - m_axe[3] = j_evt.value; - jwx_event.SetEventType(wxEVT_JOY_ZMOVE); - break; - default: - m_axe[j_evt.number] = j_evt.value; - jwx_event.SetEventType(wxEVT_JOY_MOVE); - break; - } - jwx_event.SetPosition(m_lastposition); - jwx_event.SetZPosition(m_axe[3]); + close(m_device); + return NULL; +} + + +//////////////////////////////////////////////////////////////////////////// + +wxJoystick::wxJoystick(int joystick) + : m_device(-1), + m_joystick(joystick), + m_thread(NULL) +{ + wxString dev_name; + + // old /dev structure + dev_name.Printf( wxT("/dev/js%d"), joystick); + m_device = open(dev_name.fn_str(), O_RDONLY); + + // new /dev structure with "input" subdirectory + if (m_device == -1) + { + dev_name.Printf( wxT("/dev/input/js%d"), joystick); + m_device = open(dev_name.fn_str(), O_RDONLY); } - if ((j_evt.type & JS_EVENT_BUTTON) == JS_EVENT_BUTTON) { - register int mask = 1 << j_evt.number; - char button = m_buttons & mask; - - m_buttons &= ~mask; - if (button) { - jwx_event.SetEventType(wxEVT_JOY_BUTTON_UP); - } else { - jwx_event.SetEventType(wxEVT_JOY_BUTTON_DOWN); - m_buttons |= mask; - } - - jwx_event.SetButtonState(m_buttons); - jwx_event.SetButtonChange(j_evt.number); + + if (m_device != -1) + { + m_thread = new wxJoystickThread(m_device, m_joystick); + m_thread->Create(); + m_thread->Run(); } - } - if (m_catchwin) - m_catchwin->ProcessEvent(jwx_event); - if (m_polling) - usleep(m_polling*1000); } + +wxJoystick::~wxJoystick() +{ + ReleaseCapture(); + if (m_thread) + m_thread->Delete(); // It's detached so it will delete itself + m_device = -1; +} + + //////////////////////////////////////////////////////////////////////////// // State //////////////////////////////////////////////////////////////////////////// -wxPoint wxJoystick::GetPosition(void) const +wxPoint wxJoystick::GetPosition() const +{ + wxPoint pos(wxDefaultPosition); + if (m_thread) pos = m_thread->m_lastposition; + return pos; +} + +int wxJoystick::GetPosition(unsigned axis) const +{ + if (m_thread && (axis < wxJS_MAX_AXES)) + return m_thread->m_axe[axis]; + return 0; +} + +int wxJoystick::GetZPosition() const { - return m_lastposition; + if (m_thread) + return m_thread->m_axe[wxJS_AXIS_Z]; + return 0; } -int wxJoystick::GetZPosition(void) const +int wxJoystick::GetButtonState() const { - return m_axe[3]; + if (m_thread) + return m_thread->m_buttons; + return 0; } -int wxJoystick::GetButtonState(void) const +bool wxJoystick::GetButtonState(unsigned id) const { - return m_buttons; + if (m_thread && (id < wxJS_MAX_BUTTONS)) + return (m_thread->m_buttons & (1 << id)) != 0; + return false; } -int wxJoystick::GetPOVPosition(void) const +int wxJoystick::GetPOVPosition() const { - return -1; + return -1; } -int wxJoystick::GetPOVCTSPosition(void) const +int wxJoystick::GetPOVCTSPosition() const { - return -1; + return -1; } -int wxJoystick::GetRudderPosition(void) const +int wxJoystick::GetRudderPosition() const { - return m_axe[4]; + if (m_thread) + return m_thread->m_axe[wxJS_AXIS_RUDDER]; + return 0; } -int wxJoystick::GetUPosition(void) const +int wxJoystick::GetUPosition() const { - return m_axe[5]; + if (m_thread) + return m_thread->m_axe[wxJS_AXIS_U]; + return 0; } -int wxJoystick::GetVPosition(void) const +int wxJoystick::GetVPosition() const { - return m_axe[6]; + if (m_thread) + return m_thread->m_axe[wxJS_AXIS_V]; + return 0; } -int wxJoystick::GetMovementThreshold(void) const +int wxJoystick::GetMovementThreshold() const { - return 0; + if (m_thread) + return m_thread->m_threshold; + return 0; } void wxJoystick::SetMovementThreshold(int threshold) { + if (m_thread) + m_thread->m_threshold = threshold; } //////////////////////////////////////////////////////////////////////////// // Capabilities //////////////////////////////////////////////////////////////////////////// -bool wxJoystick::IsOk(void) const +bool wxJoystick::IsOk() const { - return (m_joystick != -1); + return (m_device != -1); } -int wxJoystick::GetNumberJoysticks(void) const +int wxJoystick::GetNumberJoysticks() { - wxString dev_name; - int fd, j; + wxString dev_name; + int fd, j; + + for (j=0; j<4; j++) { + dev_name.Printf(wxT("/dev/js%d"), j); + fd = open(dev_name.fn_str(), O_RDONLY); + if (fd == -1) + break; + close(fd); + } - for (j=0;j<2;j++) { - dev_name.Printf(wxT("/dev/js%d"), j); - fd = open(dev_name.fn_str(), O_RDONLY); - if (fd == -1) - return j; - close(fd); - } - return j; + if (j == 0) { + for (j=0; j<4; j++) { + dev_name.Printf(wxT("/dev/input/js%d"), j); + fd = open(dev_name.fn_str(), O_RDONLY); + if (fd == -1) + return j; + close(fd); + } + } + + return j; } -int wxJoystick::GetManufacturerId(void) const +int wxJoystick::GetManufacturerId() const { - return 0; + return 0; } -int wxJoystick::GetProductId(void) const +int wxJoystick::GetProductId() const { - return 0; + return 0; } -wxString wxJoystick::GetProductName(void) const +wxString wxJoystick::GetProductName() const { - wxString dev_name; - // 2002-08-20 johan@linkdata.se - // Return the device name in lieu of a better one - dev_name.Printf( wxT("/dev/js%d"), (m_joystick == wxJOYSTICK1) ? 0 : 1); // FIXME Unicode? - return dev_name; + char name[128]; + + if (ioctl(m_device, JSIOCGNAME(sizeof(name)), name) < 0) + strcpy(name, "Unknown"); + return wxString(name, wxConvLibc); } -int wxJoystick::GetXMin(void) const +int wxJoystick::GetXMin() const { - return JOYSTICK_AXE_MAX; + return wxJS_AXIS_MIN; } -int wxJoystick::GetYMin(void) const +int wxJoystick::GetYMin() const { - return JOYSTICK_AXE_MAX; + return wxJS_AXIS_MIN; } -int wxJoystick::GetZMin(void) const +int wxJoystick::GetZMin() const { - return JOYSTICK_AXE_MAX; + return wxJS_AXIS_MIN; } -int wxJoystick::GetXMax(void) const +int wxJoystick::GetXMax() const { - return JOYSTICK_AXE_MAX; + return wxJS_AXIS_MAX; } -int wxJoystick::GetYMax(void) const +int wxJoystick::GetYMax() const { - return JOYSTICK_AXE_MAX; + return wxJS_AXIS_MAX; } -int wxJoystick::GetZMax(void) const +int wxJoystick::GetZMax() const { - return JOYSTICK_AXE_MAX; + return wxJS_AXIS_MAX; } -int wxJoystick::GetNumberButtons(void) const +int wxJoystick::GetNumberButtons() const { - int nb; + char nb=0; - ioctl(m_joystick, JSIOCGBUTTONS, &nb); + if (m_device != -1) + ioctl(m_device, JSIOCGBUTTONS, &nb); - return nb; + if ((int)nb > wxJS_MAX_BUTTONS) + nb = wxJS_MAX_BUTTONS; + + return nb; } -int wxJoystick::GetNumberAxes(void) const +int wxJoystick::GetNumberAxes() const { - int nb; + char nb=0; + + if (m_device != -1) + ioctl(m_device, JSIOCGAXES, &nb); - ioctl(m_joystick, JSIOCGAXES, &nb); + if ((int)nb > wxJS_MAX_AXES) + nb = wxJS_MAX_AXES; - return nb; + return nb; } -int wxJoystick::GetMaxButtons(void) const +int wxJoystick::GetMaxButtons() const { - return 15; // internal + return wxJS_MAX_BUTTONS; // internal } -int wxJoystick::GetMaxAxes(void) const +int wxJoystick::GetMaxAxes() const { - return 15; // internal + return wxJS_MAX_AXES; // internal } -int wxJoystick::GetPollingMin(void) const +int wxJoystick::GetPollingMin() const { - return -1; + return 10; } -int wxJoystick::GetPollingMax(void) const +int wxJoystick::GetPollingMax() const { - return -1; + return 1000; } -int wxJoystick::GetRudderMin(void) const +int wxJoystick::GetRudderMin() const { - return JOYSTICK_AXE_MIN; + return wxJS_AXIS_MIN; } -int wxJoystick::GetRudderMax(void) const +int wxJoystick::GetRudderMax() const { - return JOYSTICK_AXE_MAX; + return wxJS_AXIS_MAX; } -int wxJoystick::GetUMin(void) const +int wxJoystick::GetUMin() const { - return JOYSTICK_AXE_MIN; + return wxJS_AXIS_MIN; } -int wxJoystick::GetUMax(void) const +int wxJoystick::GetUMax() const { - return JOYSTICK_AXE_MAX; + return wxJS_AXIS_MAX; } -int wxJoystick::GetVMin(void) const +int wxJoystick::GetVMin() const { - return JOYSTICK_AXE_MIN; + return wxJS_AXIS_MIN; } -int wxJoystick::GetVMax(void) const +int wxJoystick::GetVMax() const { - return JOYSTICK_AXE_MAX; + return wxJS_AXIS_MAX; } -bool wxJoystick::HasRudder(void) const +bool wxJoystick::HasRudder() const { - return GetNumberAxes() >= 4; + return GetNumberAxes() >= wxJS_AXIS_RUDDER; } -bool wxJoystick::HasZ(void) const +bool wxJoystick::HasZ() const { - return GetNumberAxes() >= 3; + return GetNumberAxes() >= wxJS_AXIS_Z; } -bool wxJoystick::HasU(void) const +bool wxJoystick::HasU() const { - return GetNumberAxes() >= 5; + return GetNumberAxes() >= wxJS_AXIS_U; } -bool wxJoystick::HasV(void) const +bool wxJoystick::HasV() const { - return GetNumberAxes() >= 6; + return GetNumberAxes() >= wxJS_AXIS_V; } -bool wxJoystick::HasPOV(void) const +bool wxJoystick::HasPOV() const { - return FALSE; + return false; } -bool wxJoystick::HasPOV4Dir(void) const +bool wxJoystick::HasPOV4Dir() const { - return FALSE; + return false; } -bool wxJoystick::HasPOVCTS(void) const +bool wxJoystick::HasPOVCTS() const { - return FALSE; + return false; } //////////////////////////////////////////////////////////////////////////// @@ -356,16 +514,23 @@ bool wxJoystick::HasPOVCTS(void) const bool wxJoystick::SetCapture(wxWindow* win, int pollingFreq) { - m_catchwin = win; - m_polling = pollingFreq; - return TRUE; + if (m_thread) + { + m_thread->m_catchwin = win; + m_thread->m_polling = pollingFreq; + return true; + } + return false; } -bool wxJoystick::ReleaseCapture(void) +bool wxJoystick::ReleaseCapture() { - m_catchwin = NULL; - m_polling = 0; - return TRUE; + if (m_thread) + { + m_thread->m_catchwin = NULL; + m_thread->m_polling = 0; + return true; + } + return false; } #endif // wxUSE_JOYSTICK -