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