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