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