1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxJoystick class
4 // Author: Ported to Linux by Guilhem Lavaux
8 // Copyright: (c) Guilhem Lavaux
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
13 #pragma implementation "joystick.h"
16 // for compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
23 #include "wx/joystick.h"
25 #include <linux/joystick.h>
26 #include <sys/types.h>
29 #include <sys/ioctl.h>
34 #include "wx/window.h"
44 wxJS_AXIS_MAX
= 32767,
45 wxJS_AXIS_MIN
= -32767
49 IMPLEMENT_DYNAMIC_CLASS(wxJoystick
, wxObject
)
52 ////////////////////////////////////////////////////////////////////////////
53 // Background thread for reading the joystick device
54 ////////////////////////////////////////////////////////////////////////////
56 class wxJoystickThread
: public wxThread
59 wxJoystickThread(int device
, int joystick
);
65 wxPoint m_lastposition
;
71 friend class wxJoystick
;
75 wxJoystickThread::wxJoystickThread(int device
, int joystick
)
78 m_lastposition(wxDefaultPosition
),
83 for (int i
=0; i
<15; i
++)
88 void* wxJoystickThread::Entry()
90 struct js_event j_evt
;
92 struct timeval time_out
= {0, 0};
100 // We use select when either polling or 'blocking' as even in the
101 // blocking case we need to check TestDestroy periodically
103 time_out
.tv_usec
= m_polling
* 1000;
105 time_out
.tv_usec
= 10 * 1000; // check at least every 10 msec in blocking case
107 FD_SET(m_device
, &read_fds
);
108 select(m_device
+1, &read_fds
, NULL
, NULL
, &time_out
);
109 if (FD_ISSET(m_device
, &read_fds
))
111 memset(&j_evt
, 0, sizeof(j_evt
));
112 read(m_device
, &j_evt
, sizeof(j_evt
));
114 //printf("time: %d\t value: %d\t type: %d\t number: %d\n",
115 // j_evt.time, j_evt.value, j_evt.type, j_evt.number);
117 wxJoystickEvent jwx_event
;
119 if (j_evt
.type
& JS_EVENT_AXIS
)
121 m_axe
[j_evt
.number
] = j_evt
.value
;
123 switch (j_evt
.number
)
126 m_lastposition
.x
= j_evt
.value
;
127 jwx_event
.SetEventType(wxEVT_JOY_MOVE
);
130 m_lastposition
.y
= j_evt
.value
;
131 jwx_event
.SetEventType(wxEVT_JOY_MOVE
);
134 jwx_event
.SetEventType(wxEVT_JOY_ZMOVE
);
137 jwx_event
.SetEventType(wxEVT_JOY_MOVE
);
138 // TODO: There should be a way to indicate that the event
139 // is for some other axes.
144 if (j_evt
.type
& JS_EVENT_BUTTON
)
148 m_buttons
|= (1 << j_evt
.number
);
149 jwx_event
.SetEventType(wxEVT_JOY_BUTTON_DOWN
);
153 m_buttons
&= ~(1 << j_evt
.number
);
154 jwx_event
.SetEventType(wxEVT_JOY_BUTTON_UP
);
157 jwx_event
.SetButtonChange(j_evt
.number
);
159 jwx_event
.SetTimestamp(j_evt
.time
);
160 jwx_event
.SetJoystick(m_joystick
);
161 jwx_event
.SetButtonState(m_buttons
);
162 jwx_event
.SetPosition(m_lastposition
);
163 jwx_event
.SetZPosition(m_axe
[3]);
164 jwx_event
.SetEventObject(m_catchwin
);
167 m_catchwin
->AddPendingEvent(jwx_event
);
177 ////////////////////////////////////////////////////////////////////////////
179 wxJoystick::wxJoystick(int joystick
)
181 m_joystick(joystick
),
186 // old /dev structure
187 dev_name
.Printf( wxT("/dev/js%d"), (joystick
== wxJOYSTICK1
) ? 0 : 1);
188 m_device
= open(dev_name
.fn_str(), O_RDONLY
);
190 // new /dev structure with "input" subdirectory
193 dev_name
.Printf( wxT("/dev/input/js%d"), (joystick
== wxJOYSTICK1
) ? 0 : 1);
194 m_device
= open(dev_name
.fn_str(), O_RDONLY
);
199 m_thread
= new wxJoystickThread(m_device
, m_joystick
);
206 wxJoystick::~wxJoystick()
210 m_thread
->Delete(); // It's detached so it will delete itself
215 ////////////////////////////////////////////////////////////////////////////
217 ////////////////////////////////////////////////////////////////////////////
219 wxPoint
wxJoystick::GetPosition() const
221 wxPoint
pos(wxDefaultPosition
);
222 if (m_thread
) pos
= m_thread
->m_lastposition
;
226 int wxJoystick::GetZPosition() const
229 return m_thread
->m_axe
[wxJS_AXIS_Z
];
233 int wxJoystick::GetButtonState() const
236 return m_thread
->m_buttons
;
240 int wxJoystick::GetPOVPosition() const
245 int wxJoystick::GetPOVCTSPosition() const
250 int wxJoystick::GetRudderPosition() const
253 return m_thread
->m_axe
[wxJS_AXIS_RUDDER
];
257 int wxJoystick::GetUPosition() const
260 return m_thread
->m_axe
[wxJS_AXIS_U
];
264 int wxJoystick::GetVPosition() const
267 return m_thread
->m_axe
[wxJS_AXIS_V
];
271 int wxJoystick::GetMovementThreshold() const
276 void wxJoystick::SetMovementThreshold(int threshold
)
280 ////////////////////////////////////////////////////////////////////////////
282 ////////////////////////////////////////////////////////////////////////////
284 bool wxJoystick::IsOk() const
286 return (m_device
!= -1);
289 int wxJoystick::GetNumberJoysticks() const
294 for (j
=0; j
<4; j
++) {
295 dev_name
.Printf(wxT("/dev/js%d"), j
);
296 fd
= open(dev_name
.fn_str(), O_RDONLY
);
304 int wxJoystick::GetManufacturerId() const
309 int wxJoystick::GetProductId() const
314 wxString
wxJoystick::GetProductName() const
318 if (ioctl(m_device
, JSIOCGNAME(sizeof(name
)), name
) < 0)
319 strcpy(name
, "Unknown");
320 return wxString(name
, wxConvLibc
);
323 int wxJoystick::GetXMin() const
325 return wxJS_AXIS_MIN
;
328 int wxJoystick::GetYMin() const
330 return wxJS_AXIS_MIN
;
333 int wxJoystick::GetZMin() const
335 return wxJS_AXIS_MIN
;
338 int wxJoystick::GetXMax() const
340 return wxJS_AXIS_MAX
;
343 int wxJoystick::GetYMax() const
345 return wxJS_AXIS_MAX
;
348 int wxJoystick::GetZMax() const
350 return wxJS_AXIS_MAX
;
353 int wxJoystick::GetNumberButtons() const
358 ioctl(m_device
, JSIOCGBUTTONS
, &nb
);
363 int wxJoystick::GetNumberAxes() const
368 ioctl(m_device
, JSIOCGAXES
, &nb
);
373 int wxJoystick::GetMaxButtons() const
375 return 15; // internal
378 int wxJoystick::GetMaxAxes() const
380 return 15; // internal
383 int wxJoystick::GetPollingMin() const
388 int wxJoystick::GetPollingMax() const
393 int wxJoystick::GetRudderMin() const
395 return wxJS_AXIS_MIN
;
398 int wxJoystick::GetRudderMax() const
400 return wxJS_AXIS_MAX
;
403 int wxJoystick::GetUMin() const
405 return wxJS_AXIS_MIN
;
408 int wxJoystick::GetUMax() const
410 return wxJS_AXIS_MAX
;
413 int wxJoystick::GetVMin() const
415 return wxJS_AXIS_MIN
;
418 int wxJoystick::GetVMax() const
420 return wxJS_AXIS_MAX
;
423 bool wxJoystick::HasRudder() const
425 return GetNumberAxes() >= wxJS_AXIS_RUDDER
;
428 bool wxJoystick::HasZ() const
430 return GetNumberAxes() >= wxJS_AXIS_Z
;
433 bool wxJoystick::HasU() const
435 return GetNumberAxes() >= wxJS_AXIS_U
;
438 bool wxJoystick::HasV() const
440 return GetNumberAxes() >= wxJS_AXIS_V
;
443 bool wxJoystick::HasPOV() const
448 bool wxJoystick::HasPOV4Dir() const
453 bool wxJoystick::HasPOVCTS() const
458 ////////////////////////////////////////////////////////////////////////////
460 ////////////////////////////////////////////////////////////////////////////
462 bool wxJoystick::SetCapture(wxWindow
* win
, int pollingFreq
)
466 m_thread
->m_catchwin
= win
;
467 m_thread
->m_polling
= pollingFreq
;
473 bool wxJoystick::ReleaseCapture()
477 m_thread
->m_catchwin
= NULL
;
478 m_thread
->m_polling
= 0;
483 #endif // wxUSE_JOYSTICK