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