1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/unix/joystick.cpp 
   3 // Purpose:     wxJoystick class 
   4 // Author:      Ported to Linux by Guilhem Lavaux 
   8 // Copyright:   (c) Guilhem Lavaux 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // for compilers that support precompilation, includes "wx.h". 
  13 #include "wx/wxprec.h" 
  17 #include "wx/joystick.h" 
  21     #include "wx/window.h" 
  24 #include <linux/joystick.h> 
  25 #include <sys/types.h> 
  28 #include <sys/ioctl.h> 
  32 #ifdef HAVE_SYS_SELECT_H 
  33 #   include <sys/select.h> 
  36 #include "wx/unix/private.h" 
  46     wxJS_AXIS_MAX 
= 32767, 
  47     wxJS_AXIS_MIN 
= -32767 
  51 IMPLEMENT_DYNAMIC_CLASS(wxJoystick
, wxObject
) 
  54 //////////////////////////////////////////////////////////////////////////// 
  55 // Background thread for reading the joystick device 
  56 //////////////////////////////////////////////////////////////////////////// 
  58 class wxJoystickThread 
: public wxThread
 
  61     wxJoystickThread(int device
, int joystick
); 
  67     wxPoint   m_lastposition
; 
  73     friend class wxJoystick
; 
  77 wxJoystickThread::wxJoystickThread(int device
, int joystick
) 
  80       m_lastposition(wxDefaultPosition
), 
  85     for (int i
=0; i
<15; i
++) 
  90 void* wxJoystickThread::Entry() 
  92     struct js_event j_evt
; 
  94     struct timeval time_out 
= {0, 0}; 
 102         // We use select when either polling or 'blocking' as even in the 
 103         // blocking case we need to check TestDestroy periodically 
 105             time_out
.tv_usec 
= m_polling 
* 1000; 
 107             time_out
.tv_usec 
= 10 * 1000; // check at least every 10 msec in blocking case 
 109         wxFD_SET(m_device
, &read_fds
); 
 110         select(m_device
+1, &read_fds
, NULL
, NULL
, &time_out
); 
 111         if (wxFD_ISSET(m_device
, &read_fds
)) 
 113             memset(&j_evt
, 0, sizeof(j_evt
)); 
 114             read(m_device
, &j_evt
, sizeof(j_evt
)); 
 116             //printf("time: %d\t value: %d\t type: %d\t number: %d\n", 
 117             //       j_evt.time, j_evt.value, j_evt.type, j_evt.number); 
 119             wxJoystickEvent jwx_event
; 
 121             if (j_evt
.type 
& JS_EVENT_AXIS
) 
 123                 m_axe
[j_evt
.number
] = j_evt
.value
; 
 125                 switch (j_evt
.number
) 
 128                         m_lastposition
.x 
= j_evt
.value
; 
 129                         jwx_event
.SetEventType(wxEVT_JOY_MOVE
); 
 132                         m_lastposition
.y 
= j_evt
.value
; 
 133                         jwx_event
.SetEventType(wxEVT_JOY_MOVE
); 
 136                         jwx_event
.SetEventType(wxEVT_JOY_ZMOVE
); 
 139                         jwx_event
.SetEventType(wxEVT_JOY_MOVE
); 
 140                         // TODO: There should be a way to indicate that the event 
 141                         //       is for some other axes. 
 146             if (j_evt
.type 
& JS_EVENT_BUTTON
) 
 150                     m_buttons 
|= (1 << j_evt
.number
); 
 151                     jwx_event
.SetEventType(wxEVT_JOY_BUTTON_DOWN
); 
 155                     m_buttons 
&= ~(1 << j_evt
.number
); 
 156                     jwx_event
.SetEventType(wxEVT_JOY_BUTTON_UP
); 
 159                 jwx_event
.SetButtonChange(j_evt
.number
); 
 161                 jwx_event
.SetTimestamp(j_evt
.time
); 
 162                 jwx_event
.SetJoystick(m_joystick
); 
 163                 jwx_event
.SetButtonState(m_buttons
); 
 164                 jwx_event
.SetPosition(m_lastposition
); 
 165                 jwx_event
.SetZPosition(m_axe
[3]); 
 166                 jwx_event
.SetEventObject(m_catchwin
); 
 169                     m_catchwin
->AddPendingEvent(jwx_event
); 
 179 //////////////////////////////////////////////////////////////////////////// 
 181 wxJoystick::wxJoystick(int joystick
) 
 183       m_joystick(joystick
), 
 188      // old /dev structure 
 189     dev_name
.Printf( wxT("/dev/js%d"), joystick
); 
 190     m_device 
= open(dev_name
.fn_str(), O_RDONLY
); 
 192     // new /dev structure with "input" subdirectory 
 195         dev_name
.Printf( wxT("/dev/input/js%d"), joystick
); 
 196         m_device 
= open(dev_name
.fn_str(), O_RDONLY
); 
 201         m_thread 
= new wxJoystickThread(m_device
, m_joystick
); 
 208 wxJoystick::~wxJoystick() 
 212         m_thread
->Delete();  // It's detached so it will delete itself 
 217 //////////////////////////////////////////////////////////////////////////// 
 219 //////////////////////////////////////////////////////////////////////////// 
 221 wxPoint 
wxJoystick::GetPosition() const 
 223     wxPoint 
pos(wxDefaultPosition
); 
 224     if (m_thread
) pos 
= m_thread
->m_lastposition
; 
 228 int wxJoystick::GetZPosition() const 
 231         return m_thread
->m_axe
[wxJS_AXIS_Z
]; 
 235 int wxJoystick::GetButtonState() const 
 238         return m_thread
->m_buttons
; 
 242 int wxJoystick::GetPOVPosition() const 
 247 int wxJoystick::GetPOVCTSPosition() const 
 252 int wxJoystick::GetRudderPosition() const 
 255         return m_thread
->m_axe
[wxJS_AXIS_RUDDER
]; 
 259 int wxJoystick::GetUPosition() const 
 262         return m_thread
->m_axe
[wxJS_AXIS_U
]; 
 266 int wxJoystick::GetVPosition() const 
 269         return m_thread
->m_axe
[wxJS_AXIS_V
]; 
 273 int wxJoystick::GetMovementThreshold() const 
 278 void wxJoystick::SetMovementThreshold(int threshold
) 
 282 //////////////////////////////////////////////////////////////////////////// 
 284 //////////////////////////////////////////////////////////////////////////// 
 286 bool wxJoystick::IsOk() const 
 288     return (m_device 
!= -1); 
 291 int wxJoystick::GetNumberJoysticks() 
 296     for (j
=0; j
<4; j
++) { 
 297         dev_name
.Printf(wxT("/dev/js%d"), j
); 
 298         fd 
= open(dev_name
.fn_str(), O_RDONLY
); 
 305         for (j
=0; j
<4; j
++) { 
 306             dev_name
.Printf(wxT("/dev/input/js%d"), j
); 
 307             fd 
= open(dev_name
.fn_str(), O_RDONLY
); 
 317 int wxJoystick::GetManufacturerId() const 
 322 int wxJoystick::GetProductId() const 
 327 wxString 
wxJoystick::GetProductName() const 
 331     if (ioctl(m_device
, JSIOCGNAME(sizeof(name
)), name
) < 0) 
 332         strcpy(name
, "Unknown"); 
 333     return wxString(name
, wxConvLibc
); 
 336 int wxJoystick::GetXMin() const 
 338     return wxJS_AXIS_MIN
; 
 341 int wxJoystick::GetYMin() const 
 343     return wxJS_AXIS_MIN
; 
 346 int wxJoystick::GetZMin() const 
 348     return wxJS_AXIS_MIN
; 
 351 int wxJoystick::GetXMax() const 
 353     return wxJS_AXIS_MAX
; 
 356 int wxJoystick::GetYMax() const 
 358     return wxJS_AXIS_MAX
; 
 361 int wxJoystick::GetZMax() const 
 363     return wxJS_AXIS_MAX
; 
 366 int wxJoystick::GetNumberButtons() const 
 371         ioctl(m_device
, JSIOCGBUTTONS
, &nb
); 
 376 int wxJoystick::GetNumberAxes() const 
 381         ioctl(m_device
, JSIOCGAXES
, &nb
); 
 386 int wxJoystick::GetMaxButtons() const 
 388     return 15; // internal 
 391 int wxJoystick::GetMaxAxes() const 
 393     return 15; // internal 
 396 int wxJoystick::GetPollingMin() const 
 401 int wxJoystick::GetPollingMax() const 
 406 int wxJoystick::GetRudderMin() const 
 408     return wxJS_AXIS_MIN
; 
 411 int wxJoystick::GetRudderMax() const 
 413     return wxJS_AXIS_MAX
; 
 416 int wxJoystick::GetUMin() const 
 418     return wxJS_AXIS_MIN
; 
 421 int wxJoystick::GetUMax() const 
 423     return wxJS_AXIS_MAX
; 
 426 int wxJoystick::GetVMin() const 
 428     return wxJS_AXIS_MIN
; 
 431 int wxJoystick::GetVMax() const 
 433     return wxJS_AXIS_MAX
; 
 436 bool wxJoystick::HasRudder() const 
 438     return GetNumberAxes() >= wxJS_AXIS_RUDDER
; 
 441 bool wxJoystick::HasZ() const 
 443     return GetNumberAxes() >= wxJS_AXIS_Z
; 
 446 bool wxJoystick::HasU() const 
 448     return GetNumberAxes() >= wxJS_AXIS_U
; 
 451 bool wxJoystick::HasV() const 
 453     return GetNumberAxes() >= wxJS_AXIS_V
; 
 456 bool wxJoystick::HasPOV() const 
 461 bool wxJoystick::HasPOV4Dir() const 
 466 bool wxJoystick::HasPOVCTS() const 
 471 //////////////////////////////////////////////////////////////////////////// 
 473 //////////////////////////////////////////////////////////////////////////// 
 475 bool wxJoystick::SetCapture(wxWindow
* win
, int pollingFreq
) 
 479         m_thread
->m_catchwin 
= win
; 
 480         m_thread
->m_polling 
= pollingFreq
; 
 486 bool wxJoystick::ReleaseCapture() 
 490         m_thread
->m_catchwin 
= NULL
; 
 491         m_thread
->m_polling 
= 0; 
 496 #endif  // wxUSE_JOYSTICK