/////////////////////////////////////////////////////////////////////////////
-// Name: joystick.cpp
+// Name: src/unix/joystick.cpp
// Purpose: wxJoystick class
// Author: Ported to Linux by Guilhem Lavaux
// Modified by:
// Created: 05/23/98
// RCS-ID: $Id$
// Copyright: (c) Guilhem Lavaux
-// Licence: wxWidgets licence
+// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
-#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
-#pragma implementation "joystick.h"
-#endif
-
// for compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
-#include "wx/defs.h"
-
#if wxUSE_JOYSTICK
#include "wx/joystick.h"
+#ifndef WX_PRECOMP
+ #include "wx/event.h"
+ #include "wx/window.h"
+#endif //WX_PRECOMP
+
+#include "wx/thread.h"
+
#include <linux/joystick.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
-#include "wx/event.h"
-#include "wx/window.h"
+#ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#endif
+
+#include "wx/unix/private.h"
enum {
wxJS_AXIS_X = 0,
wxJS_AXIS_RUDDER,
wxJS_AXIS_U,
wxJS_AXIS_V,
-
+
wxJS_AXIS_MAX = 32767,
- wxJS_AXIS_MIN = -32767
+ wxJS_AXIS_MIN = -32767,
+ wxJS_MAX_AXES = 15,
+ wxJS_MAX_BUTTONS = sizeof(int) * 8
};
void* Entry();
private:
+ void SendEvent(wxEventType type, long ts, int change = 0);
int m_device;
int m_joystick;
wxPoint m_lastposition;
- int m_axe[15];
- int m_buttons;
+ int m_axe[wxJS_MAX_AXES];
+ int m_buttons;
wxWindow* m_catchwin;
- int m_polling;
+ int m_polling;
+ int m_threshold;
friend class wxJoystick;
};
m_lastposition(wxDefaultPosition),
m_buttons(0),
m_catchwin(NULL),
- m_polling(0)
-{
- for (int i=0; i<15; i++)
- m_axe[i] = 0;
+ m_polling(0),
+ m_threshold(0)
+{
+ memset(m_axe, 0, sizeof(m_axe));
}
+void wxJoystickThread::SendEvent(wxEventType type, long ts, int change)
+{
+ wxJoystickEvent jwx_event(type, m_buttons, m_joystick, change);
+
+ jwx_event.SetTimestamp(ts);
+ jwx_event.SetPosition(m_lastposition);
+ jwx_event.SetZPosition(m_axe[wxJS_AXIS_Z]);
+ jwx_event.SetEventObject(m_catchwin);
+
+ if (m_catchwin)
+ m_catchwin->AddPendingEvent(jwx_event);
+}
void* wxJoystickThread::Entry()
{
fd_set read_fds;
struct timeval time_out = {0, 0};
- FD_ZERO(&read_fds);
- while (true) {
+ wxFD_ZERO(&read_fds);
+ while (true)
+ {
if (TestDestroy())
break;
time_out.tv_usec = m_polling * 1000;
else
time_out.tv_usec = 10 * 1000; // check at least every 10 msec in blocking case
-
- FD_SET(m_device, &read_fds);
+
+ wxFD_SET(m_device, &read_fds);
select(m_device+1, &read_fds, NULL, NULL, &time_out);
- if (FD_ISSET(m_device, &read_fds))
+ if (wxFD_ISSET(m_device, &read_fds))
{
memset(&j_evt, 0, sizeof(j_evt));
read(m_device, &j_evt, sizeof(j_evt));
//printf("time: %d\t value: %d\t type: %d\t number: %d\n",
// j_evt.time, j_evt.value, j_evt.type, j_evt.number);
- if (m_catchwin)
+ if ((j_evt.type & JS_EVENT_AXIS) && (j_evt.number < wxJS_MAX_AXES))
{
- wxJoystickEvent jwx_event;
-
- if ((j_evt.type & JS_EVENT_AXIS) == JS_EVENT_AXIS) {
-
- m_axe[j_evt.number] = j_evt.value;
+ if ( (m_axe[j_evt.number] + m_threshold < j_evt.value)
+ || (m_axe[j_evt.number] - m_threshold > j_evt.value) )
+ {
+ m_axe[j_evt.number] = j_evt.value;
- switch (j_evt.number) {
+ switch (j_evt.number)
+ {
case wxJS_AXIS_X:
m_lastposition.x = j_evt.value;
- jwx_event.SetEventType(wxEVT_JOY_MOVE);
+ SendEvent(wxEVT_JOY_MOVE, j_evt.time);
break;
case wxJS_AXIS_Y:
m_lastposition.y = j_evt.value;
- jwx_event.SetEventType(wxEVT_JOY_MOVE);
+ SendEvent(wxEVT_JOY_MOVE, j_evt.time);
break;
case wxJS_AXIS_Z:
- jwx_event.SetEventType(wxEVT_JOY_ZMOVE);
+ SendEvent(wxEVT_JOY_ZMOVE, j_evt.time);
break;
default:
- jwx_event.SetEventType(wxEVT_JOY_MOVE);
+ SendEvent(wxEVT_JOY_MOVE, j_evt.time);
// TODO: There should be a way to indicate that the event
// is for some other axes.
break;
- }
}
-
- if ((j_evt.type & JS_EVENT_BUTTON) == JS_EVENT_BUTTON) {
- if (j_evt.value)
- {
- m_buttons |= (1 << j_evt.number);
- jwx_event.SetEventType(wxEVT_JOY_BUTTON_DOWN);
- }
- else
- {
- m_buttons &= ~(1 << j_evt.number);
- jwx_event.SetEventType(wxEVT_JOY_BUTTON_UP);
- }
-
- jwx_event.SetButtonChange(j_evt.number);
- }
-
- jwx_event.SetTimestamp(j_evt.time);
- jwx_event.SetJoystick(m_joystick);
- jwx_event.SetButtonState(m_buttons);
- jwx_event.SetPosition(m_lastposition);
- jwx_event.SetZPosition(m_axe[3]);
- jwx_event.SetEventObject(m_catchwin);
+ }
+ }
-
- m_catchwin->AddPendingEvent(jwx_event);
+ if ( (j_evt.type & JS_EVENT_BUTTON) && (j_evt.number < wxJS_MAX_BUTTONS) )
+ {
+ if (j_evt.value)
+ {
+ m_buttons |= (1 << j_evt.number);
+ SendEvent(wxEVT_JOY_BUTTON_DOWN, j_evt.time, j_evt.number);
+ }
+ else
+ {
+ m_buttons &= ~(1 << j_evt.number);
+ SendEvent(wxEVT_JOY_BUTTON_UP, j_evt.time, j_evt.number);
+ }
}
-
-// if (m_polling)
-// wxThread::Sleep(m_polling);
}
}
-
+
close(m_device);
return NULL;
}
m_thread(NULL)
{
wxString dev_name;
-
- // Assume it's the same device name on all Linux systems ...
- dev_name.Printf( wxT("/dev/js%d"), (joystick == wxJOYSTICK1) ? 0 : 1);
+
+ // old /dev structure
+ dev_name.Printf( wxT("/dev/js%d"), joystick);
m_device = open(dev_name.fn_str(), O_RDONLY);
+ // new /dev structure with "input" subdirectory
+ if (m_device == -1)
+ {
+ dev_name.Printf( wxT("/dev/input/js%d"), joystick);
+ m_device = open(dev_name.fn_str(), O_RDONLY);
+ }
+
if (m_device != -1)
{
m_thread = new wxJoystickThread(m_device, m_joystick);
return pos;
}
+int wxJoystick::GetPosition(unsigned axis) const
+{
+ if (m_thread && (axis < wxJS_MAX_AXES))
+ return m_thread->m_axe[axis];
+ return 0;
+}
+
int wxJoystick::GetZPosition() const
{
- if (m_thread)
+ if (m_thread)
return m_thread->m_axe[wxJS_AXIS_Z];
return 0;
}
int wxJoystick::GetButtonState() const
{
- if (m_thread)
+ if (m_thread)
return m_thread->m_buttons;
return 0;
}
+bool wxJoystick::GetButtonState(unsigned id) const
+{
+ if (m_thread && (id < wxJS_MAX_BUTTONS))
+ return (m_thread->m_buttons & (1 << id)) != 0;
+ return false;
+}
+
int wxJoystick::GetPOVPosition() const
{
return -1;
int wxJoystick::GetRudderPosition() const
{
- if (m_thread)
+ if (m_thread)
return m_thread->m_axe[wxJS_AXIS_RUDDER];
return 0;
}
int wxJoystick::GetUPosition() const
{
- if (m_thread)
+ if (m_thread)
return m_thread->m_axe[wxJS_AXIS_U];
return 0;
}
int wxJoystick::GetVPosition() const
{
- if (m_thread)
+ if (m_thread)
return m_thread->m_axe[wxJS_AXIS_V];
return 0;
}
int wxJoystick::GetMovementThreshold() const
{
+ if (m_thread)
+ return m_thread->m_threshold;
return 0;
}
void wxJoystick::SetMovementThreshold(int threshold)
{
+ if (m_thread)
+ m_thread->m_threshold = threshold;
}
////////////////////////////////////////////////////////////////////////////
return (m_device != -1);
}
-int wxJoystick::GetNumberJoysticks() const
+int wxJoystick::GetNumberJoysticks()
{
wxString dev_name;
int fd, j;
dev_name.Printf(wxT("/dev/js%d"), j);
fd = open(dev_name.fn_str(), O_RDONLY);
if (fd == -1)
- return j;
+ break;
close(fd);
}
+
+ if (j == 0) {
+ for (j=0; j<4; j++) {
+ dev_name.Printf(wxT("/dev/input/js%d"), j);
+ fd = open(dev_name.fn_str(), O_RDONLY);
+ if (fd == -1)
+ return j;
+ close(fd);
+ }
+ }
+
return j;
}
wxString wxJoystick::GetProductName() const
{
char name[128];
-
+
if (ioctl(m_device, JSIOCGNAME(sizeof(name)), name) < 0)
strcpy(name, "Unknown");
- return wxString(name, wxConvLibc);
+ return wxString(name, wxConvLibc);
}
int wxJoystick::GetXMin() const
if (m_device != -1)
ioctl(m_device, JSIOCGBUTTONS, &nb);
+ if ((int)nb > wxJS_MAX_BUTTONS)
+ nb = wxJS_MAX_BUTTONS;
+
return nb;
}
if (m_device != -1)
ioctl(m_device, JSIOCGAXES, &nb);
+ if ((int)nb > wxJS_MAX_AXES)
+ nb = wxJS_MAX_AXES;
+
return nb;
}
int wxJoystick::GetMaxButtons() const
{
- return 15; // internal
+ return wxJS_MAX_BUTTONS; // internal
}
int wxJoystick::GetMaxAxes() const
{
- return 15; // internal
+ return wxJS_MAX_AXES; // internal
}
int wxJoystick::GetPollingMin() const
return false;
}
#endif // wxUSE_JOYSTICK
-