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