]> git.saurik.com Git - wxWidgets.git/blame - src/unix/joystick.cpp
Fix of memory leak with generic file dialog (Patch #1017938)
[wxWidgets.git] / src / unix / joystick.cpp
CommitLineData
101ceb40
JS
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
65571936 9// Licence: wxWindows licence
101ceb40
JS
10/////////////////////////////////////////////////////////////////////////////
11
14f355c2 12#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
101ceb40
JS
13#pragma implementation "joystick.h"
14#endif
2b510feb 15
14f355c2
VS
16// for compilers that support precompilation, includes "wx.h".
17#include "wx/wxprec.h"
18
5260937e 19#include "wx/defs.h"
2b510feb 20
bb462424 21#if wxUSE_JOYSTICK
101ceb40 22
5260937e
VZ
23#include "wx/joystick.h"
24
101ceb40
JS
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>
2b510feb 32
101ceb40
JS
33#include "wx/event.h"
34#include "wx/window.h"
101ceb40 35
a800dc50
RD
36enum {
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};
101ceb40 47
101ceb40 48
a800dc50 49IMPLEMENT_DYNAMIC_CLASS(wxJoystick, wxObject)
101ceb40 50
101ceb40
JS
51
52////////////////////////////////////////////////////////////////////////////
a800dc50 53// Background thread for reading the joystick device
101ceb40 54////////////////////////////////////////////////////////////////////////////
101ceb40 55
a800dc50
RD
56class wxJoystickThread : public wxThread
57{
58public:
59 wxJoystickThread(int device, int joystick);
60 void* Entry();
61
62private:
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
75wxJoystickThread::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
88void* 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 if (TestDestroy())
97 break;
98
99 // We use select when either polling or 'blocking' as even in the
100 // blocking case we need to check TestDestroy periodically
101 if (m_polling)
102 time_out.tv_usec = m_polling * 1000;
103 else
104 time_out.tv_usec = 10 * 1000; // check at least every 10 msec in blocking case
105
106 FD_SET(m_device, &read_fds);
107 select(m_device+1, &read_fds, NULL, NULL, &time_out);
108 if (FD_ISSET(m_device, &read_fds))
109 {
110 memset(&j_evt, 0, sizeof(j_evt));
111 read(m_device, &j_evt, sizeof(j_evt));
112
113 //printf("time: %d\t value: %d\t type: %d\t number: %d\n",
114 // j_evt.time, j_evt.value, j_evt.type, j_evt.number);
115
116 if (m_catchwin)
117 {
118 wxJoystickEvent jwx_event;
119
120 if ((j_evt.type & JS_EVENT_AXIS) == JS_EVENT_AXIS) {
121
122 m_axe[j_evt.number] = j_evt.value;
123
124 switch (j_evt.number) {
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) == JS_EVENT_BUTTON) {
145 if (j_evt.value)
146 {
147 m_buttons |= (1 << j_evt.number);
148 jwx_event.SetEventType(wxEVT_JOY_BUTTON_DOWN);
149 }
150 else
151 {
152 m_buttons &= ~(1 << j_evt.number);
153 jwx_event.SetEventType(wxEVT_JOY_BUTTON_UP);
154 }
155
156 jwx_event.SetButtonChange(j_evt.number);
157 }
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
167 m_catchwin->AddPendingEvent(jwx_event);
168 }
169
170// if (m_polling)
171// wxThread::Sleep(m_polling);
172 }
101ceb40 173 }
a800dc50
RD
174
175 close(m_device);
176 return NULL;
177}
178
179
180////////////////////////////////////////////////////////////////////////////
181
182wxJoystick::wxJoystick(int joystick)
183 : m_device(-1),
184 m_joystick(joystick),
185 m_thread(NULL)
186{
187 wxString dev_name;
188
189 // Assume it's the same device name on all Linux systems ...
190 dev_name.Printf( wxT("/dev/js%d"), (joystick == wxJOYSTICK1) ? 0 : 1);
191 m_device = open(dev_name.fn_str(), O_RDONLY);
192
193 if (m_device != -1)
194 {
195 m_thread = new wxJoystickThread(m_device, m_joystick);
196 m_thread->Create();
197 m_thread->Run();
101ceb40 198 }
101ceb40
JS
199}
200
a800dc50
RD
201
202wxJoystick::~wxJoystick()
203{
204 ReleaseCapture();
205 if (m_thread)
206 m_thread->Delete(); // It's detached so it will delete itself
207 m_device = -1;
208}
209
210
101ceb40
JS
211////////////////////////////////////////////////////////////////////////////
212// State
213////////////////////////////////////////////////////////////////////////////
214
a800dc50 215wxPoint wxJoystick::GetPosition() const
101ceb40 216{
a800dc50
RD
217 wxPoint pos(wxDefaultPosition);
218 if (m_thread) pos = m_thread->m_lastposition;
219 return pos;
101ceb40
JS
220}
221
a800dc50 222int wxJoystick::GetZPosition() const
101ceb40 223{
a800dc50
RD
224 if (m_thread)
225 return m_thread->m_axe[wxJS_AXIS_Z];
226 return 0;
101ceb40
JS
227}
228
a800dc50 229int wxJoystick::GetButtonState() const
101ceb40 230{
a800dc50
RD
231 if (m_thread)
232 return m_thread->m_buttons;
233 return 0;
101ceb40
JS
234}
235
a800dc50 236int wxJoystick::GetPOVPosition() const
101ceb40 237{
a800dc50 238 return -1;
101ceb40
JS
239}
240
a800dc50 241int wxJoystick::GetPOVCTSPosition() const
101ceb40 242{
a800dc50 243 return -1;
101ceb40
JS
244}
245
a800dc50 246int wxJoystick::GetRudderPosition() const
101ceb40 247{
a800dc50
RD
248 if (m_thread)
249 return m_thread->m_axe[wxJS_AXIS_RUDDER];
250 return 0;
101ceb40
JS
251}
252
a800dc50 253int wxJoystick::GetUPosition() const
101ceb40 254{
a800dc50
RD
255 if (m_thread)
256 return m_thread->m_axe[wxJS_AXIS_U];
257 return 0;
101ceb40
JS
258}
259
a800dc50 260int wxJoystick::GetVPosition() const
101ceb40 261{
a800dc50
RD
262 if (m_thread)
263 return m_thread->m_axe[wxJS_AXIS_V];
264 return 0;
101ceb40
JS
265}
266
a800dc50 267int wxJoystick::GetMovementThreshold() const
101ceb40 268{
a800dc50 269 return 0;
101ceb40
JS
270}
271
272void wxJoystick::SetMovementThreshold(int threshold)
273{
274}
275
276////////////////////////////////////////////////////////////////////////////
277// Capabilities
278////////////////////////////////////////////////////////////////////////////
279
a800dc50 280bool wxJoystick::IsOk() const
101ceb40 281{
a800dc50 282 return (m_device != -1);
101ceb40
JS
283}
284
a800dc50 285int wxJoystick::GetNumberJoysticks() const
101ceb40 286{
a800dc50
RD
287 wxString dev_name;
288 int fd, j;
101ceb40 289
a800dc50
RD
290 for (j=0; j<4; j++) {
291 dev_name.Printf(wxT("/dev/js%d"), j);
292 fd = open(dev_name.fn_str(), O_RDONLY);
293 if (fd == -1)
294 return j;
295 close(fd);
296 }
297 return j;
101ceb40
JS
298}
299
a800dc50 300int wxJoystick::GetManufacturerId() const
101ceb40 301{
a800dc50 302 return 0;
101ceb40
JS
303}
304
a800dc50 305int wxJoystick::GetProductId() const
101ceb40 306{
a800dc50 307 return 0;
101ceb40
JS
308}
309
a800dc50 310wxString wxJoystick::GetProductName() const
101ceb40 311{
a800dc50
RD
312 char name[128];
313
314 if (ioctl(m_device, JSIOCGNAME(sizeof(name)), name) < 0)
315 strcpy(name, "Unknown");
316 return wxString(name, wxConvLibc);
101ceb40
JS
317}
318
a800dc50 319int wxJoystick::GetXMin() const
101ceb40 320{
a800dc50 321 return wxJS_AXIS_MIN;
101ceb40
JS
322}
323
a800dc50 324int wxJoystick::GetYMin() const
101ceb40 325{
a800dc50 326 return wxJS_AXIS_MIN;
101ceb40
JS
327}
328
a800dc50 329int wxJoystick::GetZMin() const
101ceb40 330{
a800dc50 331 return wxJS_AXIS_MIN;
101ceb40
JS
332}
333
a800dc50 334int wxJoystick::GetXMax() const
101ceb40 335{
a800dc50 336 return wxJS_AXIS_MAX;
101ceb40
JS
337}
338
a800dc50 339int wxJoystick::GetYMax() const
101ceb40 340{
a800dc50 341 return wxJS_AXIS_MAX;
101ceb40
JS
342}
343
a800dc50 344int wxJoystick::GetZMax() const
101ceb40 345{
a800dc50 346 return wxJS_AXIS_MAX;
101ceb40
JS
347}
348
a800dc50 349int wxJoystick::GetNumberButtons() const
101ceb40 350{
a800dc50 351 char nb=0;
101ceb40 352
a800dc50
RD
353 if (m_device != -1)
354 ioctl(m_device, JSIOCGBUTTONS, &nb);
101ceb40 355
a800dc50 356 return nb;
101ceb40
JS
357}
358
a800dc50 359int wxJoystick::GetNumberAxes() const
101ceb40 360{
a800dc50 361 char nb=0;
101ceb40 362
a800dc50
RD
363 if (m_device != -1)
364 ioctl(m_device, JSIOCGAXES, &nb);
101ceb40 365
a800dc50 366 return nb;
101ceb40
JS
367}
368
a800dc50 369int wxJoystick::GetMaxButtons() const
101ceb40 370{
a800dc50 371 return 15; // internal
101ceb40
JS
372}
373
a800dc50 374int wxJoystick::GetMaxAxes() const
101ceb40 375{
a800dc50 376 return 15; // internal
101ceb40
JS
377}
378
a800dc50 379int wxJoystick::GetPollingMin() const
101ceb40 380{
a800dc50 381 return 10;
101ceb40
JS
382}
383
a800dc50 384int wxJoystick::GetPollingMax() const
101ceb40 385{
a800dc50 386 return 1000;
101ceb40
JS
387}
388
a800dc50 389int wxJoystick::GetRudderMin() const
101ceb40 390{
a800dc50 391 return wxJS_AXIS_MIN;
101ceb40
JS
392}
393
a800dc50 394int wxJoystick::GetRudderMax() const
101ceb40 395{
a800dc50 396 return wxJS_AXIS_MAX;
101ceb40
JS
397}
398
a800dc50 399int wxJoystick::GetUMin() const
101ceb40 400{
a800dc50 401 return wxJS_AXIS_MIN;
101ceb40
JS
402}
403
a800dc50 404int wxJoystick::GetUMax() const
101ceb40 405{
a800dc50 406 return wxJS_AXIS_MAX;
101ceb40
JS
407}
408
a800dc50 409int wxJoystick::GetVMin() const
101ceb40 410{
a800dc50 411 return wxJS_AXIS_MIN;
101ceb40
JS
412}
413
a800dc50 414int wxJoystick::GetVMax() const
101ceb40 415{
a800dc50 416 return wxJS_AXIS_MAX;
101ceb40
JS
417}
418
a800dc50 419bool wxJoystick::HasRudder() const
101ceb40 420{
a800dc50 421 return GetNumberAxes() >= wxJS_AXIS_RUDDER;
101ceb40
JS
422}
423
a800dc50 424bool wxJoystick::HasZ() const
101ceb40 425{
a800dc50 426 return GetNumberAxes() >= wxJS_AXIS_Z;
101ceb40
JS
427}
428
a800dc50 429bool wxJoystick::HasU() const
101ceb40 430{
a800dc50 431 return GetNumberAxes() >= wxJS_AXIS_U;
101ceb40
JS
432}
433
a800dc50 434bool wxJoystick::HasV() const
101ceb40 435{
a800dc50 436 return GetNumberAxes() >= wxJS_AXIS_V;
101ceb40
JS
437}
438
a800dc50 439bool wxJoystick::HasPOV() const
101ceb40 440{
a800dc50 441 return false;
101ceb40
JS
442}
443
a800dc50 444bool wxJoystick::HasPOV4Dir() const
101ceb40 445{
a800dc50 446 return false;
101ceb40
JS
447}
448
a800dc50 449bool wxJoystick::HasPOVCTS() const
101ceb40 450{
a800dc50 451 return false;
101ceb40
JS
452}
453
454////////////////////////////////////////////////////////////////////////////
455// Operations
456////////////////////////////////////////////////////////////////////////////
457
be5fced5 458bool wxJoystick::SetCapture(wxWindow* win, int pollingFreq)
101ceb40 459{
a800dc50
RD
460 if (m_thread)
461 {
462 m_thread->m_catchwin = win;
463 m_thread->m_polling = pollingFreq;
464 return true;
465 }
466 return false;
101ceb40
JS
467}
468
a800dc50 469bool wxJoystick::ReleaseCapture()
101ceb40 470{
a800dc50
RD
471 if (m_thread)
472 {
473 m_thread->m_catchwin = NULL;
474 m_thread->m_polling = 0;
475 return true;
476 }
477 return false;
101ceb40 478}
f6bcfd97 479#endif // wxUSE_JOYSTICK
101ceb40 480