]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/unix/joystick.cpp
Fixes for building wxOS2 shared with OpenWatcom.
[wxWidgets.git] / src / unix / joystick.cpp
... / ...
CommitLineData
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
33enum {
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
46IMPLEMENT_DYNAMIC_CLASS(wxJoystick, wxObject)
47
48
49////////////////////////////////////////////////////////////////////////////
50// Background thread for reading the joystick device
51////////////////////////////////////////////////////////////////////////////
52
53class wxJoystickThread : public wxThread
54{
55public:
56 wxJoystickThread(int device, int joystick);
57 void* Entry();
58
59private:
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
72wxJoystickThread::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
85void* 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
176wxJoystick::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
203wxJoystick::~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
216wxPoint wxJoystick::GetPosition() const
217{
218 wxPoint pos(wxDefaultPosition);
219 if (m_thread) pos = m_thread->m_lastposition;
220 return pos;
221}
222
223int wxJoystick::GetZPosition() const
224{
225 if (m_thread)
226 return m_thread->m_axe[wxJS_AXIS_Z];
227 return 0;
228}
229
230int wxJoystick::GetButtonState() const
231{
232 if (m_thread)
233 return m_thread->m_buttons;
234 return 0;
235}
236
237int wxJoystick::GetPOVPosition() const
238{
239 return -1;
240}
241
242int wxJoystick::GetPOVCTSPosition() const
243{
244 return -1;
245}
246
247int wxJoystick::GetRudderPosition() const
248{
249 if (m_thread)
250 return m_thread->m_axe[wxJS_AXIS_RUDDER];
251 return 0;
252}
253
254int wxJoystick::GetUPosition() const
255{
256 if (m_thread)
257 return m_thread->m_axe[wxJS_AXIS_U];
258 return 0;
259}
260
261int wxJoystick::GetVPosition() const
262{
263 if (m_thread)
264 return m_thread->m_axe[wxJS_AXIS_V];
265 return 0;
266}
267
268int wxJoystick::GetMovementThreshold() const
269{
270 return 0;
271}
272
273void wxJoystick::SetMovementThreshold(int threshold)
274{
275}
276
277////////////////////////////////////////////////////////////////////////////
278// Capabilities
279////////////////////////////////////////////////////////////////////////////
280
281bool wxJoystick::IsOk() const
282{
283 return (m_device != -1);
284}
285
286int 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
312int wxJoystick::GetManufacturerId() const
313{
314 return 0;
315}
316
317int wxJoystick::GetProductId() const
318{
319 return 0;
320}
321
322wxString 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
331int wxJoystick::GetXMin() const
332{
333 return wxJS_AXIS_MIN;
334}
335
336int wxJoystick::GetYMin() const
337{
338 return wxJS_AXIS_MIN;
339}
340
341int wxJoystick::GetZMin() const
342{
343 return wxJS_AXIS_MIN;
344}
345
346int wxJoystick::GetXMax() const
347{
348 return wxJS_AXIS_MAX;
349}
350
351int wxJoystick::GetYMax() const
352{
353 return wxJS_AXIS_MAX;
354}
355
356int wxJoystick::GetZMax() const
357{
358 return wxJS_AXIS_MAX;
359}
360
361int 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
371int 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
381int wxJoystick::GetMaxButtons() const
382{
383 return 15; // internal
384}
385
386int wxJoystick::GetMaxAxes() const
387{
388 return 15; // internal
389}
390
391int wxJoystick::GetPollingMin() const
392{
393 return 10;
394}
395
396int wxJoystick::GetPollingMax() const
397{
398 return 1000;
399}
400
401int wxJoystick::GetRudderMin() const
402{
403 return wxJS_AXIS_MIN;
404}
405
406int wxJoystick::GetRudderMax() const
407{
408 return wxJS_AXIS_MAX;
409}
410
411int wxJoystick::GetUMin() const
412{
413 return wxJS_AXIS_MIN;
414}
415
416int wxJoystick::GetUMax() const
417{
418 return wxJS_AXIS_MAX;
419}
420
421int wxJoystick::GetVMin() const
422{
423 return wxJS_AXIS_MIN;
424}
425
426int wxJoystick::GetVMax() const
427{
428 return wxJS_AXIS_MAX;
429}
430
431bool wxJoystick::HasRudder() const
432{
433 return GetNumberAxes() >= wxJS_AXIS_RUDDER;
434}
435
436bool wxJoystick::HasZ() const
437{
438 return GetNumberAxes() >= wxJS_AXIS_Z;
439}
440
441bool wxJoystick::HasU() const
442{
443 return GetNumberAxes() >= wxJS_AXIS_U;
444}
445
446bool wxJoystick::HasV() const
447{
448 return GetNumberAxes() >= wxJS_AXIS_V;
449}
450
451bool wxJoystick::HasPOV() const
452{
453 return false;
454}
455
456bool wxJoystick::HasPOV4Dir() const
457{
458 return false;
459}
460
461bool wxJoystick::HasPOVCTS() const
462{
463 return false;
464}
465
466////////////////////////////////////////////////////////////////////////////
467// Operations
468////////////////////////////////////////////////////////////////////////////
469
470bool 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
481bool 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