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