1 /////////////////////////////////////////////////////////////////////////////
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"
19 #include "wx/joystick.h"
21 #include <linux/joystick.h>
22 #include <sys/types.h>
25 #include <sys/ioctl.h>
30 #include "wx/window.h"
40 wxJS_AXIS_MAX
= 32767,
41 wxJS_AXIS_MIN
= -32767
45 IMPLEMENT_DYNAMIC_CLASS(wxJoystick
, wxObject
)
48 ////////////////////////////////////////////////////////////////////////////
49 // Background thread for reading the joystick device
50 ////////////////////////////////////////////////////////////////////////////
52 class wxJoystickThread
: public wxThread
55 wxJoystickThread(int device
, int joystick
);
61 wxPoint m_lastposition
;
67 friend class wxJoystick
;
71 wxJoystickThread::wxJoystickThread(int device
, int joystick
)
74 m_lastposition(wxDefaultPosition
),
79 for (int i
=0; i
<15; i
++)
84 void* wxJoystickThread::Entry()
86 struct js_event j_evt
;
88 struct timeval time_out
= {0, 0};
96 // We use select when either polling or 'blocking' as even in the
97 // blocking case we need to check TestDestroy periodically
99 time_out
.tv_usec
= m_polling
* 1000;
101 time_out
.tv_usec
= 10 * 1000; // check at least every 10 msec in blocking case
103 FD_SET(m_device
, &read_fds
);
104 select(m_device
+1, &read_fds
, NULL
, NULL
, &time_out
);
105 if (FD_ISSET(m_device
, &read_fds
))
107 memset(&j_evt
, 0, sizeof(j_evt
));
108 read(m_device
, &j_evt
, sizeof(j_evt
));
110 //printf("time: %d\t value: %d\t type: %d\t number: %d\n",
111 // j_evt.time, j_evt.value, j_evt.type, j_evt.number);
113 wxJoystickEvent jwx_event
;
115 if (j_evt
.type
& JS_EVENT_AXIS
)
117 m_axe
[j_evt
.number
] = j_evt
.value
;
119 switch (j_evt
.number
)
122 m_lastposition
.x
= j_evt
.value
;
123 jwx_event
.SetEventType(wxEVT_JOY_MOVE
);
126 m_lastposition
.y
= j_evt
.value
;
127 jwx_event
.SetEventType(wxEVT_JOY_MOVE
);
130 jwx_event
.SetEventType(wxEVT_JOY_ZMOVE
);
133 jwx_event
.SetEventType(wxEVT_JOY_MOVE
);
134 // TODO: There should be a way to indicate that the event
135 // is for some other axes.
140 if (j_evt
.type
& JS_EVENT_BUTTON
)
144 m_buttons
|= (1 << j_evt
.number
);
145 jwx_event
.SetEventType(wxEVT_JOY_BUTTON_DOWN
);
149 m_buttons
&= ~(1 << j_evt
.number
);
150 jwx_event
.SetEventType(wxEVT_JOY_BUTTON_UP
);
153 jwx_event
.SetButtonChange(j_evt
.number
);
155 jwx_event
.SetTimestamp(j_evt
.time
);
156 jwx_event
.SetJoystick(m_joystick
);
157 jwx_event
.SetButtonState(m_buttons
);
158 jwx_event
.SetPosition(m_lastposition
);
159 jwx_event
.SetZPosition(m_axe
[3]);
160 jwx_event
.SetEventObject(m_catchwin
);
163 m_catchwin
->AddPendingEvent(jwx_event
);
173 ////////////////////////////////////////////////////////////////////////////
175 wxJoystick::wxJoystick(int joystick
)
177 m_joystick(joystick
),
182 // old /dev structure
183 dev_name
.Printf( wxT("/dev/js%d"), joystick
);
184 m_device
= open(dev_name
.fn_str(), O_RDONLY
);
186 // new /dev structure with "input" subdirectory
189 dev_name
.Printf( wxT("/dev/input/js%d"), joystick
);
190 m_device
= open(dev_name
.fn_str(), O_RDONLY
);
195 m_thread
= new wxJoystickThread(m_device
, m_joystick
);
202 wxJoystick::~wxJoystick()
206 m_thread
->Delete(); // It's detached so it will delete itself
211 ////////////////////////////////////////////////////////////////////////////
213 ////////////////////////////////////////////////////////////////////////////
215 wxPoint
wxJoystick::GetPosition() const
217 wxPoint
pos(wxDefaultPosition
);
218 if (m_thread
) pos
= m_thread
->m_lastposition
;
222 int wxJoystick::GetZPosition() const
225 return m_thread
->m_axe
[wxJS_AXIS_Z
];
229 int wxJoystick::GetButtonState() const
232 return m_thread
->m_buttons
;
236 int wxJoystick::GetPOVPosition() const
241 int wxJoystick::GetPOVCTSPosition() const
246 int wxJoystick::GetRudderPosition() const
249 return m_thread
->m_axe
[wxJS_AXIS_RUDDER
];
253 int wxJoystick::GetUPosition() const
256 return m_thread
->m_axe
[wxJS_AXIS_U
];
260 int wxJoystick::GetVPosition() const
263 return m_thread
->m_axe
[wxJS_AXIS_V
];
267 int wxJoystick::GetMovementThreshold() const
272 void wxJoystick::SetMovementThreshold(int threshold
)
276 ////////////////////////////////////////////////////////////////////////////
278 ////////////////////////////////////////////////////////////////////////////
280 bool wxJoystick::IsOk() const
282 return (m_device
!= -1);
285 int wxJoystick::GetNumberJoysticks() const
290 for (j
=0; j
<4; j
++) {
291 dev_name
.Printf(wxT("/dev/js%d"), j
);
292 fd
= open(dev_name
.fn_str(), O_RDONLY
);
299 for (j
=0; j
<4; j
++) {
300 dev_name
.Printf(wxT("/dev/input/js%d"), j
);
301 fd
= open(dev_name
.fn_str(), O_RDONLY
);
311 int wxJoystick::GetManufacturerId() const
316 int wxJoystick::GetProductId() const
321 wxString
wxJoystick::GetProductName() const
325 if (ioctl(m_device
, JSIOCGNAME(sizeof(name
)), name
) < 0)
326 strcpy(name
, "Unknown");
327 return wxString(name
, wxConvLibc
);
330 int wxJoystick::GetXMin() const
332 return wxJS_AXIS_MIN
;
335 int wxJoystick::GetYMin() const
337 return wxJS_AXIS_MIN
;
340 int wxJoystick::GetZMin() const
342 return wxJS_AXIS_MIN
;
345 int wxJoystick::GetXMax() const
347 return wxJS_AXIS_MAX
;
350 int wxJoystick::GetYMax() const
352 return wxJS_AXIS_MAX
;
355 int wxJoystick::GetZMax() const
357 return wxJS_AXIS_MAX
;
360 int wxJoystick::GetNumberButtons() const
365 ioctl(m_device
, JSIOCGBUTTONS
, &nb
);
370 int wxJoystick::GetNumberAxes() const
375 ioctl(m_device
, JSIOCGAXES
, &nb
);
380 int wxJoystick::GetMaxButtons() const
382 return 15; // internal
385 int wxJoystick::GetMaxAxes() const
387 return 15; // internal
390 int wxJoystick::GetPollingMin() const
395 int wxJoystick::GetPollingMax() const
400 int wxJoystick::GetRudderMin() const
402 return wxJS_AXIS_MIN
;
405 int wxJoystick::GetRudderMax() const
407 return wxJS_AXIS_MAX
;
410 int wxJoystick::GetUMin() const
412 return wxJS_AXIS_MIN
;
415 int wxJoystick::GetUMax() const
417 return wxJS_AXIS_MAX
;
420 int wxJoystick::GetVMin() const
422 return wxJS_AXIS_MIN
;
425 int wxJoystick::GetVMax() const
427 return wxJS_AXIS_MAX
;
430 bool wxJoystick::HasRudder() const
432 return GetNumberAxes() >= wxJS_AXIS_RUDDER
;
435 bool wxJoystick::HasZ() const
437 return GetNumberAxes() >= wxJS_AXIS_Z
;
440 bool wxJoystick::HasU() const
442 return GetNumberAxes() >= wxJS_AXIS_U
;
445 bool wxJoystick::HasV() const
447 return GetNumberAxes() >= wxJS_AXIS_V
;
450 bool wxJoystick::HasPOV() const
455 bool wxJoystick::HasPOV4Dir() const
460 bool wxJoystick::HasPOVCTS() const
465 ////////////////////////////////////////////////////////////////////////////
467 ////////////////////////////////////////////////////////////////////////////
469 bool wxJoystick::SetCapture(wxWindow
* win
, int pollingFreq
)
473 m_thread
->m_catchwin
= win
;
474 m_thread
->m_polling
= pollingFreq
;
480 bool wxJoystick::ReleaseCapture()
484 m_thread
->m_catchwin
= NULL
;
485 m_thread
->m_polling
= 0;
490 #endif // wxUSE_JOYSTICK