]> git.saurik.com Git - wxWidgets.git/blame - src/unix/joystick.cpp
Applied patch from Bo, WIP
[wxWidgets.git] / src / unix / joystick.cpp
CommitLineData
101ceb40 1/////////////////////////////////////////////////////////////////////////////
7520f3da 2// Name: src/unix/joystick.cpp
101ceb40
JS
3// Purpose: wxJoystick class
4// Author: Ported to Linux by Guilhem Lavaux
5// Modified by:
6// Created: 05/23/98
7// RCS-ID: $Id$
8// Copyright: (c) Guilhem Lavaux
627b2b2a 9// Licence: wxWindows licence
101ceb40
JS
10/////////////////////////////////////////////////////////////////////////////
11
14f355c2
VS
12// for compilers that support precompilation, includes "wx.h".
13#include "wx/wxprec.h"
14
bb462424 15#if wxUSE_JOYSTICK
101ceb40 16
5260937e
VZ
17#include "wx/joystick.h"
18
d5da0ce7
WS
19#ifndef WX_PRECOMP
20 #include "wx/event.h"
cdccdfab 21 #include "wx/window.h"
d5da0ce7
WS
22#endif //WX_PRECOMP
23
101ceb40
JS
24#include <linux/joystick.h>
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <sys/time.h>
28#include <sys/ioctl.h>
29#include <fcntl.h>
30#include <unistd.h>
2b510feb 31
bc023abb
MW
32#ifdef HAVE_SYS_SELECT_H
33# include <sys/select.h>
34#endif
35
17a1ebd1 36#include "wx/unix/private.h"
101ceb40 37
a800dc50
RD
38enum {
39 wxJS_AXIS_X = 0,
40 wxJS_AXIS_Y,
41 wxJS_AXIS_Z,
42 wxJS_AXIS_RUDDER,
43 wxJS_AXIS_U,
44 wxJS_AXIS_V,
627b2b2a 45
a800dc50 46 wxJS_AXIS_MAX = 32767,
e6733873
VZ
47 wxJS_AXIS_MIN = -32767,
48 wxJS_MAX_AXES = 15,
49 wxJS_MAX_BUTTONS = sizeof(int) * 8
a800dc50 50};
101ceb40 51
101ceb40 52
a800dc50 53IMPLEMENT_DYNAMIC_CLASS(wxJoystick, wxObject)
101ceb40 54
101ceb40
JS
55
56////////////////////////////////////////////////////////////////////////////
a800dc50 57// Background thread for reading the joystick device
101ceb40 58////////////////////////////////////////////////////////////////////////////
101ceb40 59
a800dc50
RD
60class wxJoystickThread : public wxThread
61{
62public:
63 wxJoystickThread(int device, int joystick);
64 void* Entry();
65
66private:
e6733873 67 void SendEvent(wxEventType type, long ts, int change = 0);
a800dc50
RD
68 int m_device;
69 int m_joystick;
70 wxPoint m_lastposition;
e6733873 71 int m_axe[wxJS_MAX_AXES];
627b2b2a 72 int m_buttons;
a800dc50 73 wxWindow* m_catchwin;
627b2b2a 74 int m_polling;
e6733873 75 int m_threshold;
a800dc50
RD
76
77 friend class wxJoystick;
78};
79
80
81wxJoystickThread::wxJoystickThread(int device, int joystick)
82 : m_device(device),
83 m_joystick(joystick),
84 m_lastposition(wxDefaultPosition),
85 m_buttons(0),
86 m_catchwin(NULL),
e6733873
VZ
87 m_polling(0),
88 m_threshold(0)
627b2b2a 89{
e6733873 90 memset(m_axe, 0, sizeof(m_axe));
a800dc50
RD
91}
92
e6733873
VZ
93void wxJoystickThread::SendEvent(wxEventType type, long ts, int change)
94{
95 wxJoystickEvent jwx_event(type, m_buttons, m_joystick, change);
96
97 jwx_event.SetTimestamp(ts);
98 jwx_event.SetPosition(m_lastposition);
99 jwx_event.SetZPosition(m_axe[wxJS_AXIS_Z]);
100 jwx_event.SetEventObject(m_catchwin);
101
102 if (m_catchwin)
103 m_catchwin->AddPendingEvent(jwx_event);
104}
a800dc50
RD
105
106void* wxJoystickThread::Entry()
107{
108 struct js_event j_evt;
109 fd_set read_fds;
110 struct timeval time_out = {0, 0};
111
17a1ebd1 112 wxFD_ZERO(&read_fds);
627b2b2a
VZ
113 while (true)
114 {
a800dc50
RD
115 if (TestDestroy())
116 break;
117
118 // We use select when either polling or 'blocking' as even in the
119 // blocking case we need to check TestDestroy periodically
120 if (m_polling)
121 time_out.tv_usec = m_polling * 1000;
122 else
123 time_out.tv_usec = 10 * 1000; // check at least every 10 msec in blocking case
627b2b2a 124
17a1ebd1 125 wxFD_SET(m_device, &read_fds);
a800dc50 126 select(m_device+1, &read_fds, NULL, NULL, &time_out);
17a1ebd1 127 if (wxFD_ISSET(m_device, &read_fds))
a800dc50
RD
128 {
129 memset(&j_evt, 0, sizeof(j_evt));
130 read(m_device, &j_evt, sizeof(j_evt));
131
132 //printf("time: %d\t value: %d\t type: %d\t number: %d\n",
133 // j_evt.time, j_evt.value, j_evt.type, j_evt.number);
134
e6733873
VZ
135 if ((j_evt.type & JS_EVENT_AXIS) && (j_evt.number < wxJS_MAX_AXES))
136 {
137 if ( (m_axe[j_evt.number] + m_threshold < j_evt.value)
138 || (m_axe[j_evt.number] - m_threshold > j_evt.value) )
627b2b2a
VZ
139 {
140 m_axe[j_evt.number] = j_evt.value;
a800dc50 141
627b2b2a
VZ
142 switch (j_evt.number)
143 {
a800dc50
RD
144 case wxJS_AXIS_X:
145 m_lastposition.x = j_evt.value;
e6733873 146 SendEvent(wxEVT_JOY_MOVE, j_evt.time);
a800dc50
RD
147 break;
148 case wxJS_AXIS_Y:
149 m_lastposition.y = j_evt.value;
e6733873 150 SendEvent(wxEVT_JOY_MOVE, j_evt.time);
a800dc50
RD
151 break;
152 case wxJS_AXIS_Z:
e6733873 153 SendEvent(wxEVT_JOY_ZMOVE, j_evt.time);
a800dc50
RD
154 break;
155 default:
e6733873 156 SendEvent(wxEVT_JOY_MOVE, j_evt.time);
a800dc50
RD
157 // TODO: There should be a way to indicate that the event
158 // is for some other axes.
159 break;
a800dc50 160 }
627b2b2a 161 }
e6733873 162 }
627b2b2a 163
e6733873 164 if ( (j_evt.type & JS_EVENT_BUTTON) && (j_evt.number < wxJS_MAX_BUTTONS) )
627b2b2a
VZ
165 {
166 if (j_evt.value)
167 {
168 m_buttons |= (1 << j_evt.number);
e6733873 169 SendEvent(wxEVT_JOY_BUTTON_DOWN, j_evt.time, j_evt.number);
627b2b2a
VZ
170 }
171 else
172 {
173 m_buttons &= ~(1 << j_evt.number);
e6733873 174 SendEvent(wxEVT_JOY_BUTTON_UP, j_evt.time, j_evt.number);
a800dc50 175 }
a800dc50 176 }
a800dc50 177 }
101ceb40 178 }
627b2b2a 179
a800dc50
RD
180 close(m_device);
181 return NULL;
182}
183
184
185////////////////////////////////////////////////////////////////////////////
186
187wxJoystick::wxJoystick(int joystick)
188 : m_device(-1),
189 m_joystick(joystick),
190 m_thread(NULL)
191{
192 wxString dev_name;
627b2b2a 193
dcd5c3d0 194 // old /dev structure
f50de150 195 dev_name.Printf( wxT("/dev/js%d"), joystick);
a800dc50
RD
196 m_device = open(dev_name.fn_str(), O_RDONLY);
197
dcd5c3d0
JS
198 // new /dev structure with "input" subdirectory
199 if (m_device == -1)
200 {
f50de150 201 dev_name.Printf( wxT("/dev/input/js%d"), joystick);
7520f3da 202 m_device = open(dev_name.fn_str(), O_RDONLY);
dcd5c3d0
JS
203 }
204
a800dc50
RD
205 if (m_device != -1)
206 {
207 m_thread = new wxJoystickThread(m_device, m_joystick);
208 m_thread->Create();
209 m_thread->Run();
101ceb40 210 }
101ceb40
JS
211}
212
a800dc50
RD
213
214wxJoystick::~wxJoystick()
215{
216 ReleaseCapture();
217 if (m_thread)
218 m_thread->Delete(); // It's detached so it will delete itself
219 m_device = -1;
220}
221
222
101ceb40
JS
223////////////////////////////////////////////////////////////////////////////
224// State
225////////////////////////////////////////////////////////////////////////////
226
a800dc50 227wxPoint wxJoystick::GetPosition() const
101ceb40 228{
a800dc50
RD
229 wxPoint pos(wxDefaultPosition);
230 if (m_thread) pos = m_thread->m_lastposition;
231 return pos;
101ceb40
JS
232}
233
e6733873
VZ
234int wxJoystick::GetPosition(unsigned axis) const
235{
236 if (m_thread && (axis < wxJS_MAX_AXES))
237 return m_thread->m_axe[axis];
238 return 0;
239}
240
a800dc50 241int wxJoystick::GetZPosition() const
101ceb40 242{
627b2b2a 243 if (m_thread)
a800dc50
RD
244 return m_thread->m_axe[wxJS_AXIS_Z];
245 return 0;
101ceb40
JS
246}
247
a800dc50 248int wxJoystick::GetButtonState() const
101ceb40 249{
627b2b2a 250 if (m_thread)
a800dc50
RD
251 return m_thread->m_buttons;
252 return 0;
101ceb40
JS
253}
254
e6733873
VZ
255bool wxJoystick::GetButtonState(unsigned id) const
256{
257 if (m_thread && (id < wxJS_MAX_BUTTONS))
258 return (m_thread->m_buttons & (1 << id)) != 0;
259 return false;
260}
261
a800dc50 262int wxJoystick::GetPOVPosition() const
101ceb40 263{
a800dc50 264 return -1;
101ceb40
JS
265}
266
a800dc50 267int wxJoystick::GetPOVCTSPosition() const
101ceb40 268{
a800dc50 269 return -1;
101ceb40
JS
270}
271
a800dc50 272int wxJoystick::GetRudderPosition() const
101ceb40 273{
627b2b2a 274 if (m_thread)
a800dc50
RD
275 return m_thread->m_axe[wxJS_AXIS_RUDDER];
276 return 0;
101ceb40
JS
277}
278
a800dc50 279int wxJoystick::GetUPosition() const
101ceb40 280{
627b2b2a 281 if (m_thread)
a800dc50
RD
282 return m_thread->m_axe[wxJS_AXIS_U];
283 return 0;
101ceb40
JS
284}
285
a800dc50 286int wxJoystick::GetVPosition() const
101ceb40 287{
627b2b2a 288 if (m_thread)
a800dc50
RD
289 return m_thread->m_axe[wxJS_AXIS_V];
290 return 0;
101ceb40
JS
291}
292
a800dc50 293int wxJoystick::GetMovementThreshold() const
101ceb40 294{
e6733873
VZ
295 if (m_thread)
296 return m_thread->m_threshold;
a800dc50 297 return 0;
101ceb40
JS
298}
299
300void wxJoystick::SetMovementThreshold(int threshold)
301{
e6733873
VZ
302 if (m_thread)
303 m_thread->m_threshold = threshold;
101ceb40
JS
304}
305
306////////////////////////////////////////////////////////////////////////////
307// Capabilities
308////////////////////////////////////////////////////////////////////////////
309
a800dc50 310bool wxJoystick::IsOk() const
101ceb40 311{
a800dc50 312 return (m_device != -1);
101ceb40
JS
313}
314
da9e9563 315int wxJoystick::GetNumberJoysticks()
101ceb40 316{
a800dc50
RD
317 wxString dev_name;
318 int fd, j;
101ceb40 319
a800dc50
RD
320 for (j=0; j<4; j++) {
321 dev_name.Printf(wxT("/dev/js%d"), j);
322 fd = open(dev_name.fn_str(), O_RDONLY);
323 if (fd == -1)
f50de150 324 break;
a800dc50
RD
325 close(fd);
326 }
7520f3da 327
f50de150
JS
328 if (j == 0) {
329 for (j=0; j<4; j++) {
330 dev_name.Printf(wxT("/dev/input/js%d"), j);
331 fd = open(dev_name.fn_str(), O_RDONLY);
332 if (fd == -1)
333 return j;
334 close(fd);
335 }
336 }
7520f3da 337
a800dc50 338 return j;
101ceb40
JS
339}
340
a800dc50 341int wxJoystick::GetManufacturerId() const
101ceb40 342{
a800dc50 343 return 0;
101ceb40
JS
344}
345
a800dc50 346int wxJoystick::GetProductId() const
101ceb40 347{
a800dc50 348 return 0;
101ceb40
JS
349}
350
a800dc50 351wxString wxJoystick::GetProductName() const
101ceb40 352{
a800dc50 353 char name[128];
627b2b2a 354
a800dc50
RD
355 if (ioctl(m_device, JSIOCGNAME(sizeof(name)), name) < 0)
356 strcpy(name, "Unknown");
627b2b2a 357 return wxString(name, wxConvLibc);
101ceb40
JS
358}
359
a800dc50 360int wxJoystick::GetXMin() const
101ceb40 361{
a800dc50 362 return wxJS_AXIS_MIN;
101ceb40
JS
363}
364
a800dc50 365int wxJoystick::GetYMin() const
101ceb40 366{
a800dc50 367 return wxJS_AXIS_MIN;
101ceb40
JS
368}
369
a800dc50 370int wxJoystick::GetZMin() const
101ceb40 371{
a800dc50 372 return wxJS_AXIS_MIN;
101ceb40
JS
373}
374
a800dc50 375int wxJoystick::GetXMax() const
101ceb40 376{
a800dc50 377 return wxJS_AXIS_MAX;
101ceb40
JS
378}
379
a800dc50 380int wxJoystick::GetYMax() const
101ceb40 381{
a800dc50 382 return wxJS_AXIS_MAX;
101ceb40
JS
383}
384
a800dc50 385int wxJoystick::GetZMax() const
101ceb40 386{
a800dc50 387 return wxJS_AXIS_MAX;
101ceb40
JS
388}
389
a800dc50 390int wxJoystick::GetNumberButtons() const
101ceb40 391{
a800dc50 392 char nb=0;
101ceb40 393
a800dc50
RD
394 if (m_device != -1)
395 ioctl(m_device, JSIOCGBUTTONS, &nb);
101ceb40 396
c9f78968 397 if ((int)nb > wxJS_MAX_BUTTONS)
e6733873
VZ
398 nb = wxJS_MAX_BUTTONS;
399
a800dc50 400 return nb;
101ceb40
JS
401}
402
a800dc50 403int wxJoystick::GetNumberAxes() const
101ceb40 404{
a800dc50 405 char nb=0;
101ceb40 406
a800dc50
RD
407 if (m_device != -1)
408 ioctl(m_device, JSIOCGAXES, &nb);
101ceb40 409
c9f78968 410 if ((int)nb > wxJS_MAX_AXES)
e6733873
VZ
411 nb = wxJS_MAX_AXES;
412
a800dc50 413 return nb;
101ceb40
JS
414}
415
a800dc50 416int wxJoystick::GetMaxButtons() const
101ceb40 417{
e6733873 418 return wxJS_MAX_BUTTONS; // internal
101ceb40
JS
419}
420
a800dc50 421int wxJoystick::GetMaxAxes() const
101ceb40 422{
e6733873 423 return wxJS_MAX_AXES; // internal
101ceb40
JS
424}
425
a800dc50 426int wxJoystick::GetPollingMin() const
101ceb40 427{
a800dc50 428 return 10;
101ceb40
JS
429}
430
a800dc50 431int wxJoystick::GetPollingMax() const
101ceb40 432{
a800dc50 433 return 1000;
101ceb40
JS
434}
435
a800dc50 436int wxJoystick::GetRudderMin() const
101ceb40 437{
a800dc50 438 return wxJS_AXIS_MIN;
101ceb40
JS
439}
440
a800dc50 441int wxJoystick::GetRudderMax() const
101ceb40 442{
a800dc50 443 return wxJS_AXIS_MAX;
101ceb40
JS
444}
445
a800dc50 446int wxJoystick::GetUMin() const
101ceb40 447{
a800dc50 448 return wxJS_AXIS_MIN;
101ceb40
JS
449}
450
a800dc50 451int wxJoystick::GetUMax() const
101ceb40 452{
a800dc50 453 return wxJS_AXIS_MAX;
101ceb40
JS
454}
455
a800dc50 456int wxJoystick::GetVMin() const
101ceb40 457{
a800dc50 458 return wxJS_AXIS_MIN;
101ceb40
JS
459}
460
a800dc50 461int wxJoystick::GetVMax() const
101ceb40 462{
a800dc50 463 return wxJS_AXIS_MAX;
101ceb40
JS
464}
465
a800dc50 466bool wxJoystick::HasRudder() const
101ceb40 467{
a800dc50 468 return GetNumberAxes() >= wxJS_AXIS_RUDDER;
101ceb40
JS
469}
470
a800dc50 471bool wxJoystick::HasZ() const
101ceb40 472{
a800dc50 473 return GetNumberAxes() >= wxJS_AXIS_Z;
101ceb40
JS
474}
475
a800dc50 476bool wxJoystick::HasU() const
101ceb40 477{
a800dc50 478 return GetNumberAxes() >= wxJS_AXIS_U;
101ceb40
JS
479}
480
a800dc50 481bool wxJoystick::HasV() const
101ceb40 482{
a800dc50 483 return GetNumberAxes() >= wxJS_AXIS_V;
101ceb40
JS
484}
485
a800dc50 486bool wxJoystick::HasPOV() const
101ceb40 487{
a800dc50 488 return false;
101ceb40
JS
489}
490
a800dc50 491bool wxJoystick::HasPOV4Dir() const
101ceb40 492{
a800dc50 493 return false;
101ceb40
JS
494}
495
a800dc50 496bool wxJoystick::HasPOVCTS() const
101ceb40 497{
a800dc50 498 return false;
101ceb40
JS
499}
500
501////////////////////////////////////////////////////////////////////////////
502// Operations
503////////////////////////////////////////////////////////////////////////////
504
be5fced5 505bool wxJoystick::SetCapture(wxWindow* win, int pollingFreq)
101ceb40 506{
a800dc50
RD
507 if (m_thread)
508 {
509 m_thread->m_catchwin = win;
510 m_thread->m_polling = pollingFreq;
511 return true;
512 }
513 return false;
101ceb40
JS
514}
515
a800dc50 516bool wxJoystick::ReleaseCapture()
101ceb40 517{
a800dc50
RD
518 if (m_thread)
519 {
520 m_thread->m_catchwin = NULL;
521 m_thread->m_polling = 0;
522 return true;
523 }
524 return false;
101ceb40 525}
f6bcfd97 526#endif // wxUSE_JOYSTICK