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