]> git.saurik.com Git - wxWidgets.git/blob - src/unix/joystick.cpp
49a4cad688e7349d9cfaf6381fba283e21859f08
[wxWidgets.git] / src / unix / joystick.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/unix/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
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // for compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14
15 #if wxUSE_JOYSTICK
16
17 #include "wx/joystick.h"
18
19 #ifndef WX_PRECOMP
20 #include "wx/event.h"
21 #include "wx/window.h"
22 #endif //WX_PRECOMP
23
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>
31
32 #include "wx/unix/private.h"
33
34 enum {
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,
41
42 wxJS_AXIS_MAX = 32767,
43 wxJS_AXIS_MIN = -32767
44 };
45
46
47 IMPLEMENT_DYNAMIC_CLASS(wxJoystick, wxObject)
48
49
50 ////////////////////////////////////////////////////////////////////////////
51 // Background thread for reading the joystick device
52 ////////////////////////////////////////////////////////////////////////////
53
54 class wxJoystickThread : public wxThread
55 {
56 public:
57 wxJoystickThread(int device, int joystick);
58 void* Entry();
59
60 private:
61 int m_device;
62 int m_joystick;
63 wxPoint m_lastposition;
64 int m_axe[15];
65 int m_buttons;
66 wxWindow* m_catchwin;
67 int m_polling;
68
69 friend class wxJoystick;
70 };
71
72
73 wxJoystickThread::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)
80 {
81 for (int i=0; i<15; i++)
82 m_axe[i] = 0;
83 }
84
85
86 void* wxJoystickThread::Entry()
87 {
88 struct js_event j_evt;
89 fd_set read_fds;
90 struct timeval time_out = {0, 0};
91
92 wxFD_ZERO(&read_fds);
93 while (true)
94 {
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
104
105 wxFD_SET(m_device, &read_fds);
106 select(m_device+1, &read_fds, NULL, NULL, &time_out);
107 if (wxFD_ISSET(m_device, &read_fds))
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
115 wxJoystickEvent jwx_event;
116
117 if (j_evt.type & JS_EVENT_AXIS)
118 {
119 m_axe[j_evt.number] = j_evt.value;
120
121 switch (j_evt.number)
122 {
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;
139 }
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);
153 }
154
155 jwx_event.SetButtonChange(j_evt.number);
156
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
164 if (m_catchwin)
165 m_catchwin->AddPendingEvent(jwx_event);
166 }
167 }
168 }
169
170 close(m_device);
171 return NULL;
172 }
173
174
175 ////////////////////////////////////////////////////////////////////////////
176
177 wxJoystick::wxJoystick(int joystick)
178 : m_device(-1),
179 m_joystick(joystick),
180 m_thread(NULL)
181 {
182 wxString dev_name;
183
184 // old /dev structure
185 dev_name.Printf( wxT("/dev/js%d"), joystick);
186 m_device = open(dev_name.fn_str(), O_RDONLY);
187
188 // new /dev structure with "input" subdirectory
189 if (m_device == -1)
190 {
191 dev_name.Printf( wxT("/dev/input/js%d"), joystick);
192 m_device = open(dev_name.fn_str(), O_RDONLY);
193 }
194
195 if (m_device != -1)
196 {
197 m_thread = new wxJoystickThread(m_device, m_joystick);
198 m_thread->Create();
199 m_thread->Run();
200 }
201 }
202
203
204 wxJoystick::~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
213 ////////////////////////////////////////////////////////////////////////////
214 // State
215 ////////////////////////////////////////////////////////////////////////////
216
217 wxPoint wxJoystick::GetPosition() const
218 {
219 wxPoint pos(wxDefaultPosition);
220 if (m_thread) pos = m_thread->m_lastposition;
221 return pos;
222 }
223
224 int wxJoystick::GetZPosition() const
225 {
226 if (m_thread)
227 return m_thread->m_axe[wxJS_AXIS_Z];
228 return 0;
229 }
230
231 int wxJoystick::GetButtonState() const
232 {
233 if (m_thread)
234 return m_thread->m_buttons;
235 return 0;
236 }
237
238 int wxJoystick::GetPOVPosition() const
239 {
240 return -1;
241 }
242
243 int wxJoystick::GetPOVCTSPosition() const
244 {
245 return -1;
246 }
247
248 int wxJoystick::GetRudderPosition() const
249 {
250 if (m_thread)
251 return m_thread->m_axe[wxJS_AXIS_RUDDER];
252 return 0;
253 }
254
255 int wxJoystick::GetUPosition() const
256 {
257 if (m_thread)
258 return m_thread->m_axe[wxJS_AXIS_U];
259 return 0;
260 }
261
262 int wxJoystick::GetVPosition() const
263 {
264 if (m_thread)
265 return m_thread->m_axe[wxJS_AXIS_V];
266 return 0;
267 }
268
269 int wxJoystick::GetMovementThreshold() const
270 {
271 return 0;
272 }
273
274 void wxJoystick::SetMovementThreshold(int threshold)
275 {
276 }
277
278 ////////////////////////////////////////////////////////////////////////////
279 // Capabilities
280 ////////////////////////////////////////////////////////////////////////////
281
282 bool wxJoystick::IsOk() const
283 {
284 return (m_device != -1);
285 }
286
287 int wxJoystick::GetNumberJoysticks()
288 {
289 wxString dev_name;
290 int fd, j;
291
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)
296 break;
297 close(fd);
298 }
299
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 }
309
310 return j;
311 }
312
313 int wxJoystick::GetManufacturerId() const
314 {
315 return 0;
316 }
317
318 int wxJoystick::GetProductId() const
319 {
320 return 0;
321 }
322
323 wxString wxJoystick::GetProductName() const
324 {
325 char name[128];
326
327 if (ioctl(m_device, JSIOCGNAME(sizeof(name)), name) < 0)
328 strcpy(name, "Unknown");
329 return wxString(name, wxConvLibc);
330 }
331
332 int wxJoystick::GetXMin() const
333 {
334 return wxJS_AXIS_MIN;
335 }
336
337 int wxJoystick::GetYMin() const
338 {
339 return wxJS_AXIS_MIN;
340 }
341
342 int wxJoystick::GetZMin() const
343 {
344 return wxJS_AXIS_MIN;
345 }
346
347 int wxJoystick::GetXMax() const
348 {
349 return wxJS_AXIS_MAX;
350 }
351
352 int wxJoystick::GetYMax() const
353 {
354 return wxJS_AXIS_MAX;
355 }
356
357 int wxJoystick::GetZMax() const
358 {
359 return wxJS_AXIS_MAX;
360 }
361
362 int wxJoystick::GetNumberButtons() const
363 {
364 char nb=0;
365
366 if (m_device != -1)
367 ioctl(m_device, JSIOCGBUTTONS, &nb);
368
369 return nb;
370 }
371
372 int wxJoystick::GetNumberAxes() const
373 {
374 char nb=0;
375
376 if (m_device != -1)
377 ioctl(m_device, JSIOCGAXES, &nb);
378
379 return nb;
380 }
381
382 int wxJoystick::GetMaxButtons() const
383 {
384 return 15; // internal
385 }
386
387 int wxJoystick::GetMaxAxes() const
388 {
389 return 15; // internal
390 }
391
392 int wxJoystick::GetPollingMin() const
393 {
394 return 10;
395 }
396
397 int wxJoystick::GetPollingMax() const
398 {
399 return 1000;
400 }
401
402 int wxJoystick::GetRudderMin() const
403 {
404 return wxJS_AXIS_MIN;
405 }
406
407 int wxJoystick::GetRudderMax() const
408 {
409 return wxJS_AXIS_MAX;
410 }
411
412 int wxJoystick::GetUMin() const
413 {
414 return wxJS_AXIS_MIN;
415 }
416
417 int wxJoystick::GetUMax() const
418 {
419 return wxJS_AXIS_MAX;
420 }
421
422 int wxJoystick::GetVMin() const
423 {
424 return wxJS_AXIS_MIN;
425 }
426
427 int wxJoystick::GetVMax() const
428 {
429 return wxJS_AXIS_MAX;
430 }
431
432 bool wxJoystick::HasRudder() const
433 {
434 return GetNumberAxes() >= wxJS_AXIS_RUDDER;
435 }
436
437 bool wxJoystick::HasZ() const
438 {
439 return GetNumberAxes() >= wxJS_AXIS_Z;
440 }
441
442 bool wxJoystick::HasU() const
443 {
444 return GetNumberAxes() >= wxJS_AXIS_U;
445 }
446
447 bool wxJoystick::HasV() const
448 {
449 return GetNumberAxes() >= wxJS_AXIS_V;
450 }
451
452 bool wxJoystick::HasPOV() const
453 {
454 return false;
455 }
456
457 bool wxJoystick::HasPOV4Dir() const
458 {
459 return false;
460 }
461
462 bool wxJoystick::HasPOVCTS() const
463 {
464 return false;
465 }
466
467 ////////////////////////////////////////////////////////////////////////////
468 // Operations
469 ////////////////////////////////////////////////////////////////////////////
470
471 bool wxJoystick::SetCapture(wxWindow* win, int pollingFreq)
472 {
473 if (m_thread)
474 {
475 m_thread->m_catchwin = win;
476 m_thread->m_polling = pollingFreq;
477 return true;
478 }
479 return false;
480 }
481
482 bool wxJoystick::ReleaseCapture()
483 {
484 if (m_thread)
485 {
486 m_thread->m_catchwin = NULL;
487 m_thread->m_polling = 0;
488 return true;
489 }
490 return false;
491 }
492 #endif // wxUSE_JOYSTICK