From: Robin Dunn Date: Fri, 14 May 2004 02:52:05 +0000 (+0000) Subject: Fixes so joystick not only compiles on Linux, but it actually works too! X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/a800dc50d47f5ecd1bcba7601f33843c01db9a57?ds=sidebyside;hp=89a94520ea3a77cd4b75a34c1007f850d49aa737 Fixes so joystick not only compiles on Linux, but it actually works too! git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@27265 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/include/wx/unix/joystick.h b/include/wx/unix/joystick.h index 131851f117..ec38965284 100644 --- a/include/wx/unix/joystick.h +++ b/include/wx/unix/joystick.h @@ -19,84 +19,82 @@ #include "wx/event.h" #include "wx/thread.h" -class WXDLLEXPORT wxJoystick: public wxObject, public wxThread +class WXDLLEXPORT wxJoystickThread; + +class WXDLLEXPORT wxJoystick: public wxObject { - DECLARE_DYNAMIC_CLASS(wxJoystick) - public: - /* - * Public interface - */ - - wxJoystick(int joystick = wxJOYSTICK1); - - // Attributes - //////////////////////////////////////////////////////////////////////////// - - wxPoint GetPosition(void) const; - int GetZPosition(void) const; - int GetButtonState(void) const; - int GetPOVPosition(void) const; - int GetPOVCTSPosition(void) const; - int GetRudderPosition(void) const; - int GetUPosition(void) const; - int GetVPosition(void) const; - int GetMovementThreshold(void) const; - void SetMovementThreshold(int threshold) ; - - // Capabilities - //////////////////////////////////////////////////////////////////////////// - - bool IsOk(void) const; // Checks that the joystick is functioning - int GetNumberJoysticks(void) const ; - int GetManufacturerId(void) const ; - int GetProductId(void) const ; - wxString GetProductName(void) const ; - int GetXMin(void) const; - int GetYMin(void) const; - int GetZMin(void) const; - int GetXMax(void) const; - int GetYMax(void) const; - int GetZMax(void) const; - int GetNumberButtons(void) const; - int GetNumberAxes(void) const; - int GetMaxButtons(void) const; - int GetMaxAxes(void) const; - int GetPollingMin(void) const; - int GetPollingMax(void) const; - int GetRudderMin(void) const; - int GetRudderMax(void) const; - int GetUMin(void) const; - int GetUMax(void) const; - int GetVMin(void) const; - int GetVMax(void) const; - - bool HasRudder(void) const; - bool HasZ(void) const; - bool HasU(void) const; - bool HasV(void) const; - bool HasPOV(void) const; - bool HasPOV4Dir(void) const; - bool HasPOVCTS(void) const; - - // Operations - //////////////////////////////////////////////////////////////////////////// - - // pollingFreq = 0 means that movement events are sent when above the threshold. - // If pollingFreq > 0, events are received every this many milliseconds. - bool SetCapture(wxWindow* win, int pollingFreq = 0); - bool ReleaseCapture(void); + DECLARE_DYNAMIC_CLASS(wxJoystick) + public: + /* + * Public interface + */ + + wxJoystick(int joystick = wxJOYSTICK1); + ~wxJoystick(); + + // Attributes + //////////////////////////////////////////////////////////////////////////// + + wxPoint GetPosition() const; + int GetZPosition() const; + int GetButtonState() const; + int GetPOVPosition() const; + int GetPOVCTSPosition() const; + int GetRudderPosition() const; + int GetUPosition() const; + int GetVPosition() const; + int GetMovementThreshold() const; + void SetMovementThreshold(int threshold) ; + + // Capabilities + //////////////////////////////////////////////////////////////////////////// + + bool IsOk() const; // Checks that the joystick is functioning + int GetNumberJoysticks() const ; + int GetManufacturerId() const ; + int GetProductId() const ; + wxString GetProductName() const ; + int GetXMin() const; + int GetYMin() const; + int GetZMin() const; + int GetXMax() const; + int GetYMax() const; + int GetZMax() const; + int GetNumberButtons() const; + int GetNumberAxes() const; + int GetMaxButtons() const; + int GetMaxAxes() const; + int GetPollingMin() const; + int GetPollingMax() const; + int GetRudderMin() const; + int GetRudderMax() const; + int GetUMin() const; + int GetUMax() const; + int GetVMin() const; + int GetVMax() const; + + bool HasRudder() const; + bool HasZ() const; + bool HasU() const; + bool HasV() const; + bool HasPOV() const; + bool HasPOV4Dir() const; + bool HasPOVCTS() const; + + // Operations + //////////////////////////////////////////////////////////////////////////// + + // pollingFreq = 0 means that movement events are sent when above the threshold. + // If pollingFreq > 0, events are received every this many milliseconds. + bool SetCapture(wxWindow* win, int pollingFreq = 0); + bool ReleaseCapture(); protected: - int m_joystick; - wxPoint m_lastposition; - int m_axe[15]; - int m_buttons; - wxWindow *m_catchwin; - int m_polling; - - void *Entry(void); + int m_device; + int m_joystick; + wxJoystickThread* m_thread; }; #endif - // __JOYSTICKH__ +// __JOYSTICKH__ diff --git a/samples/joytest/joytest.cpp b/samples/joytest/joytest.cpp index 4d5be8b350..bcc1dd71c5 100644 --- a/samples/joytest/joytest.cpp +++ b/samples/joytest/joytest.cpp @@ -57,6 +57,8 @@ bool MyApp::OnInit() m_fire.Create(_T("gun.wav")); #endif // wxUSE_SOUND + m_minX = stick.GetXMin(); + m_minY = stick.GetYMin(); m_maxX = stick.GetXMax(); m_maxY = stick.GetYMax(); @@ -103,14 +105,14 @@ END_EVENT_TABLE() MyCanvas::MyCanvas(wxWindow *parent, const wxPoint& pos, const wxSize& size): wxScrolledWindow(parent, -1, pos, size, wxSUNKEN_BORDER) { - wxJoystick joystick(wxJOYSTICK1); - joystick.SetCapture(this); + m_stick = new wxJoystick(wxJOYSTICK1); + m_stick->SetCapture(this, 10); } MyCanvas::~MyCanvas() { - wxJoystick joystick(wxJOYSTICK1); - joystick.ReleaseCapture(); + m_stick->ReleaseCapture(); + delete m_stick; } void MyCanvas::OnJoystickEvent(wxJoystickEvent& event) @@ -119,12 +121,28 @@ void MyCanvas::OnJoystickEvent(wxJoystickEvent& event) wxPoint pt(event.GetPosition()); + // if negative positions are possible then shift everything up + int xmin = wxGetApp().m_minX; + int xmax = wxGetApp().m_maxX; + int ymin = wxGetApp().m_minY; + int ymax = wxGetApp().m_maxY; + if (xmin < 0) { + xmax += abs(xmin); + pt.x += abs(xmin); + xmin = 0; + } + if (ymin < 0) { + ymax += abs(ymin); + pt.y += abs(ymin); + ymin = 0; + } + // Scale to canvas size int cw, ch; GetSize(&cw, &ch); - pt.x = (long) (((double)pt.x/(double)wxGetApp().m_maxX) * cw); - pt.y = (long) (((double)pt.y/(double)wxGetApp().m_maxY) * ch); + pt.x = (long) (((double)pt.x/(double)xmax) * cw); + pt.y = (long) (((double)pt.y/(double)ymax) * ch); if (xpos > -1 && ypos > -1 && event.IsMove() && event.ButtonIsDown()) { diff --git a/samples/joytest/joytest.h b/samples/joytest/joytest.h index aed89d553f..31bfa14e5b 100644 --- a/samples/joytest/joytest.h +++ b/samples/joytest/joytest.h @@ -16,6 +16,8 @@ public: bool OnInit(); // Joystick max values + int m_minX; + int m_minY; int m_maxX; int m_maxY; @@ -33,6 +35,7 @@ public: ~MyCanvas(); void OnJoystickEvent(wxJoystickEvent& event); + wxJoystick* m_stick; DECLARE_EVENT_TABLE() }; diff --git a/src/unix/joystick.cpp b/src/unix/joystick.cpp index 2ea86f9a8d..cb88e0add9 100644 --- a/src/unix/joystick.cpp +++ b/src/unix/joystick.cpp @@ -33,141 +33,240 @@ #include "wx/event.h" #include "wx/window.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, + + wxJS_AXIS_MAX = 32767, + wxJS_AXIS_MIN = -32767 +}; -IMPLEMENT_DYNAMIC_CLASS(wxJoystick, wxObject) -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? +IMPLEMENT_DYNAMIC_CLASS(wxJoystick, wxObject) - 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(); -} //////////////////////////////////////////////////////////////////////////// -// 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)); - } - 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]); +class wxJoystickThread : public wxThread +{ +public: + wxJoystickThread(int device, int joystick); + void* Entry(); + +private: + int m_device; + int m_joystick; + wxPoint m_lastposition; + int m_axe[15]; + int m_buttons; + wxWindow* m_catchwin; + int m_polling; + + 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) +{ + for (int i=0; i<15; i++) + m_axe[i] = 0; +} + + +void* wxJoystickThread::Entry() +{ + struct js_event j_evt; + fd_set read_fds; + struct timeval time_out = {0, 0}; + + FD_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 + + FD_SET(m_device, &read_fds); + select(m_device+1, &read_fds, NULL, NULL, &time_out); + if (FD_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 (m_catchwin) + { + wxJoystickEvent jwx_event; + + if ((j_evt.type & JS_EVENT_AXIS) == JS_EVENT_AXIS) { + + m_axe[j_evt.number] = j_evt.value; + + switch (j_evt.number) { + case wxJS_AXIS_X: + m_lastposition.x = j_evt.value; + jwx_event.SetEventType(wxEVT_JOY_MOVE); + break; + case wxJS_AXIS_Y: + m_lastposition.y = j_evt.value; + jwx_event.SetEventType(wxEVT_JOY_MOVE); + break; + case wxJS_AXIS_Z: + jwx_event.SetEventType(wxEVT_JOY_ZMOVE); + break; + default: + jwx_event.SetEventType(wxEVT_JOY_MOVE); + // TODO: There should be a way to indicate that the event + // is for some other axes. + break; + } + } + + if ((j_evt.type & JS_EVENT_BUTTON) == JS_EVENT_BUTTON) { + if (j_evt.value) + { + m_buttons |= (1 << j_evt.number); + jwx_event.SetEventType(wxEVT_JOY_BUTTON_DOWN); + } + else + { + m_buttons &= ~(1 << j_evt.number); + jwx_event.SetEventType(wxEVT_JOY_BUTTON_UP); + } + + jwx_event.SetButtonChange(j_evt.number); + } + + jwx_event.SetTimestamp(j_evt.time); + jwx_event.SetJoystick(m_joystick); + jwx_event.SetButtonState(m_buttons); + jwx_event.SetPosition(m_lastposition); + jwx_event.SetZPosition(m_axe[3]); + jwx_event.SetEventObject(m_catchwin); + + + m_catchwin->AddPendingEvent(jwx_event); + } + +// if (m_polling) +// wxThread::Sleep(m_polling); + } } - 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); + + close(m_device); + return NULL; +} + + +//////////////////////////////////////////////////////////////////////////// + +wxJoystick::wxJoystick(int joystick) + : m_device(-1), + m_joystick(joystick), + m_thread(NULL) +{ + 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); + m_device = open(dev_name.fn_str(), O_RDONLY); + + 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 { - return m_lastposition; + wxPoint pos(wxDefaultPosition); + if (m_thread) pos = m_thread->m_lastposition; + return pos; } -int wxJoystick::GetZPosition(void) const +int wxJoystick::GetZPosition() const { - return m_axe[3]; + if (m_thread) + return m_thread->m_axe[wxJS_AXIS_Z]; + return 0; } -int wxJoystick::GetButtonState(void) const +int wxJoystick::GetButtonState() const { - return m_buttons; + if (m_thread) + return m_thread->m_buttons; + return 0; } -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; + return 0; } void wxJoystick::SetMovementThreshold(int threshold) @@ -178,176 +277,178 @@ void wxJoystick::SetMovementThreshold(int 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() const { - wxString dev_name; - int fd, j; + wxString dev_name; + int fd, j; - 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; + 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) + 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; + return nb; } -int wxJoystick::GetNumberAxes(void) const +int wxJoystick::GetNumberAxes() const { - int nb; + char nb=0; - ioctl(m_joystick, JSIOCGAXES, &nb); + if (m_device != -1) + ioctl(m_device, JSIOCGAXES, &nb); - return nb; + return nb; } -int wxJoystick::GetMaxButtons(void) const +int wxJoystick::GetMaxButtons() const { - return 15; // internal + return 15; // internal } -int wxJoystick::GetMaxAxes(void) const +int wxJoystick::GetMaxAxes() const { - return 15; // internal + return 15; // 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 +457,24 @@ 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