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