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