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