Fixes so joystick not only compiles on Linux, but it actually works too!

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@27265 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Robin Dunn
2004-05-14 02:52:05 +00:00
parent 89a94520ea
commit a800dc50d4
4 changed files with 379 additions and 251 deletions

View File

@@ -19,7 +19,9 @@
#include "wx/event.h" #include "wx/event.h"
#include "wx/thread.h" #include "wx/thread.h"
class WXDLLEXPORT wxJoystick: public wxObject, public wxThread class WXDLLEXPORT wxJoystickThread;
class WXDLLEXPORT wxJoystick: public wxObject
{ {
DECLARE_DYNAMIC_CLASS(wxJoystick) DECLARE_DYNAMIC_CLASS(wxJoystick)
public: public:
@@ -28,55 +30,56 @@ class WXDLLEXPORT wxJoystick: public wxObject, public wxThread
*/ */
wxJoystick(int joystick = wxJOYSTICK1); wxJoystick(int joystick = wxJOYSTICK1);
~wxJoystick();
// Attributes // Attributes
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
wxPoint GetPosition(void) const; wxPoint GetPosition() const;
int GetZPosition(void) const; int GetZPosition() const;
int GetButtonState(void) const; int GetButtonState() const;
int GetPOVPosition(void) const; int GetPOVPosition() const;
int GetPOVCTSPosition(void) const; int GetPOVCTSPosition() const;
int GetRudderPosition(void) const; int GetRudderPosition() const;
int GetUPosition(void) const; int GetUPosition() const;
int GetVPosition(void) const; int GetVPosition() const;
int GetMovementThreshold(void) const; int GetMovementThreshold() const;
void SetMovementThreshold(int threshold) ; void SetMovementThreshold(int threshold) ;
// Capabilities // Capabilities
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
bool IsOk(void) const; // Checks that the joystick is functioning bool IsOk() const; // Checks that the joystick is functioning
int GetNumberJoysticks(void) const ; int GetNumberJoysticks() const ;
int GetManufacturerId(void) const ; int GetManufacturerId() const ;
int GetProductId(void) const ; int GetProductId() const ;
wxString GetProductName(void) const ; wxString GetProductName() const ;
int GetXMin(void) const; int GetXMin() const;
int GetYMin(void) const; int GetYMin() const;
int GetZMin(void) const; int GetZMin() const;
int GetXMax(void) const; int GetXMax() const;
int GetYMax(void) const; int GetYMax() const;
int GetZMax(void) const; int GetZMax() const;
int GetNumberButtons(void) const; int GetNumberButtons() const;
int GetNumberAxes(void) const; int GetNumberAxes() const;
int GetMaxButtons(void) const; int GetMaxButtons() const;
int GetMaxAxes(void) const; int GetMaxAxes() const;
int GetPollingMin(void) const; int GetPollingMin() const;
int GetPollingMax(void) const; int GetPollingMax() const;
int GetRudderMin(void) const; int GetRudderMin() const;
int GetRudderMax(void) const; int GetRudderMax() const;
int GetUMin(void) const; int GetUMin() const;
int GetUMax(void) const; int GetUMax() const;
int GetVMin(void) const; int GetVMin() const;
int GetVMax(void) const; int GetVMax() const;
bool HasRudder(void) const; bool HasRudder() const;
bool HasZ(void) const; bool HasZ() const;
bool HasU(void) const; bool HasU() const;
bool HasV(void) const; bool HasV() const;
bool HasPOV(void) const; bool HasPOV() const;
bool HasPOV4Dir(void) const; bool HasPOV4Dir() const;
bool HasPOVCTS(void) const; bool HasPOVCTS() const;
// Operations // Operations
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
@@ -84,19 +87,14 @@ class WXDLLEXPORT wxJoystick: public wxObject, public wxThread
// pollingFreq = 0 means that movement events are sent when above the threshold. // pollingFreq = 0 means that movement events are sent when above the threshold.
// If pollingFreq > 0, events are received every this many milliseconds. // If pollingFreq > 0, events are received every this many milliseconds.
bool SetCapture(wxWindow* win, int pollingFreq = 0); bool SetCapture(wxWindow* win, int pollingFreq = 0);
bool ReleaseCapture(void); bool ReleaseCapture();
protected: protected:
int m_device;
int m_joystick; int m_joystick;
wxPoint m_lastposition; wxJoystickThread* m_thread;
int m_axe[15];
int m_buttons;
wxWindow *m_catchwin;
int m_polling;
void *Entry(void);
}; };
#endif #endif
// __JOYSTICKH__ // __JOYSTICKH__

View File

@@ -57,6 +57,8 @@ bool MyApp::OnInit()
m_fire.Create(_T("gun.wav")); m_fire.Create(_T("gun.wav"));
#endif // wxUSE_SOUND #endif // wxUSE_SOUND
m_minX = stick.GetXMin();
m_minY = stick.GetYMin();
m_maxX = stick.GetXMax(); m_maxX = stick.GetXMax();
m_maxY = stick.GetYMax(); m_maxY = stick.GetYMax();
@@ -103,14 +105,14 @@ END_EVENT_TABLE()
MyCanvas::MyCanvas(wxWindow *parent, const wxPoint& pos, const wxSize& size): MyCanvas::MyCanvas(wxWindow *parent, const wxPoint& pos, const wxSize& size):
wxScrolledWindow(parent, -1, pos, size, wxSUNKEN_BORDER) wxScrolledWindow(parent, -1, pos, size, wxSUNKEN_BORDER)
{ {
wxJoystick joystick(wxJOYSTICK1); m_stick = new wxJoystick(wxJOYSTICK1);
joystick.SetCapture(this); m_stick->SetCapture(this, 10);
} }
MyCanvas::~MyCanvas() MyCanvas::~MyCanvas()
{ {
wxJoystick joystick(wxJOYSTICK1); m_stick->ReleaseCapture();
joystick.ReleaseCapture(); delete m_stick;
} }
void MyCanvas::OnJoystickEvent(wxJoystickEvent& event) void MyCanvas::OnJoystickEvent(wxJoystickEvent& event)
@@ -119,12 +121,28 @@ void MyCanvas::OnJoystickEvent(wxJoystickEvent& event)
wxPoint pt(event.GetPosition()); wxPoint pt(event.GetPosition());
// if negative positions are possible then shift everything up
int xmin = wxGetApp().m_minX;
int xmax = wxGetApp().m_maxX;
int ymin = wxGetApp().m_minY;
int ymax = wxGetApp().m_maxY;
if (xmin < 0) {
xmax += abs(xmin);
pt.x += abs(xmin);
xmin = 0;
}
if (ymin < 0) {
ymax += abs(ymin);
pt.y += abs(ymin);
ymin = 0;
}
// Scale to canvas size // Scale to canvas size
int cw, ch; int cw, ch;
GetSize(&cw, &ch); GetSize(&cw, &ch);
pt.x = (long) (((double)pt.x/(double)wxGetApp().m_maxX) * cw); pt.x = (long) (((double)pt.x/(double)xmax) * cw);
pt.y = (long) (((double)pt.y/(double)wxGetApp().m_maxY) * ch); pt.y = (long) (((double)pt.y/(double)ymax) * ch);
if (xpos > -1 && ypos > -1 && event.IsMove() && event.ButtonIsDown()) if (xpos > -1 && ypos > -1 && event.IsMove() && event.ButtonIsDown())
{ {

View File

@@ -16,6 +16,8 @@ public:
bool OnInit(); bool OnInit();
// Joystick max values // Joystick max values
int m_minX;
int m_minY;
int m_maxX; int m_maxX;
int m_maxY; int m_maxY;
@@ -33,6 +35,7 @@ public:
~MyCanvas(); ~MyCanvas();
void OnJoystickEvent(wxJoystickEvent& event); void OnJoystickEvent(wxJoystickEvent& event);
wxJoystick* m_stick;
DECLARE_EVENT_TABLE() DECLARE_EVENT_TABLE()
}; };

View File

@@ -33,139 +33,238 @@
#include "wx/event.h" #include "wx/event.h"
#include "wx/window.h" #include "wx/window.h"
#define JOYSTICK_AXE_MAX 32767 enum {
#define JOYSTICK_AXE_MIN -32767 wxJS_AXIS_X = 0,
wxJS_AXIS_Y,
wxJS_AXIS_Z,
wxJS_AXIS_RUDDER,
wxJS_AXIS_U,
wxJS_AXIS_V,
wxJS_AXIS_MAX = 32767,
wxJS_AXIS_MIN = -32767
};
IMPLEMENT_DYNAMIC_CLASS(wxJoystick, wxObject) IMPLEMENT_DYNAMIC_CLASS(wxJoystick, wxObject)
wxJoystick::wxJoystick(int joystick)
{
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); // FIXME Unicode?
m_joystick = open(dev_name.fn_str(), O_RDWR); ////////////////////////////////////////////////////////////////////////////
m_lastposition = wxPoint(-1, -1); // Background thread for reading the joystick device
for (int i=0;i<15;i++) ////////////////////////////////////////////////////////////////////////////
class wxJoystickThread : public wxThread
{
public:
wxJoystickThread(int device, int joystick);
void* Entry();
private:
int m_device;
int m_joystick;
wxPoint m_lastposition;
int m_axe[15];
int m_buttons;
wxWindow* m_catchwin;
int m_polling;
friend class wxJoystick;
};
wxJoystickThread::wxJoystickThread(int device, int joystick)
: m_device(device),
m_joystick(joystick),
m_lastposition(wxDefaultPosition),
m_buttons(0),
m_catchwin(NULL),
m_polling(0)
{
for (int i=0; i<15; i++)
m_axe[i] = 0; m_axe[i] = 0;
if (m_joystick != -1)
Create();
} }
////////////////////////////////////////////////////////////////////////////
// Background thread void* wxJoystickThread::Entry()
////////////////////////////////////////////////////////////////////////////
void *wxJoystick::Entry(void)
{ {
struct js_event j_evt; struct js_event j_evt;
wxJoystickEvent jwx_event;
fd_set read_fds; fd_set read_fds;
struct timeval time_out = {0, 0}; struct timeval time_out = {0, 0};
FD_ZERO(&read_fds); FD_ZERO(&read_fds);
while (1) { while (true) {
TestDestroy(); if (TestDestroy())
break;
if (m_polling) { // We use select when either polling or 'blocking' as even in the
FD_SET(m_joystick, &read_fds); // blocking case we need to check TestDestroy periodically
select(m_joystick+1, &read_fds, NULL, NULL, &time_out); if (m_polling)
if (FD_ISSET(m_joystick, &read_fds)) time_out.tv_usec = m_polling * 1000;
read(m_joystick, &j_evt, sizeof(j_evt));
else else
j_evt.type = 0; time_out.tv_usec = 10 * 1000; // check at least every 10 msec in blocking case
} else {
read(m_joystick, &j_evt, sizeof(j_evt)); FD_SET(m_device, &read_fds);
} select(m_device+1, &read_fds, NULL, NULL, &time_out);
if (FD_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)
{
wxJoystickEvent jwx_event;
if ((j_evt.type & JS_EVENT_AXIS) == JS_EVENT_AXIS) { if ((j_evt.type & JS_EVENT_AXIS) == JS_EVENT_AXIS) {
m_axe[j_evt.number] = j_evt.value;
switch (j_evt.number) { switch (j_evt.number) {
case 1: case wxJS_AXIS_X:
m_lastposition.x = j_evt.value; m_lastposition.x = j_evt.value;
jwx_event.SetEventType(wxEVT_JOY_MOVE); jwx_event.SetEventType(wxEVT_JOY_MOVE);
break; break;
case 2: case wxJS_AXIS_Y:
m_lastposition.y = j_evt.value; m_lastposition.y = j_evt.value;
jwx_event.SetEventType(wxEVT_JOY_MOVE); jwx_event.SetEventType(wxEVT_JOY_MOVE);
break; break;
case 3: case wxJS_AXIS_Z:
m_axe[3] = j_evt.value;
jwx_event.SetEventType(wxEVT_JOY_ZMOVE); jwx_event.SetEventType(wxEVT_JOY_ZMOVE);
break; break;
default: default:
m_axe[j_evt.number] = j_evt.value;
jwx_event.SetEventType(wxEVT_JOY_MOVE); jwx_event.SetEventType(wxEVT_JOY_MOVE);
// TODO: There should be a way to indicate that the event
// is for some other axes.
break; break;
} }
jwx_event.SetPosition(m_lastposition);
jwx_event.SetZPosition(m_axe[3]);
} }
if ((j_evt.type & JS_EVENT_BUTTON) == JS_EVENT_BUTTON) { if ((j_evt.type & JS_EVENT_BUTTON) == JS_EVENT_BUTTON) {
register int mask = 1 << j_evt.number; if (j_evt.value)
char button = m_buttons & mask; {
m_buttons |= (1 << j_evt.number);
m_buttons &= ~mask;
if (button) {
jwx_event.SetEventType(wxEVT_JOY_BUTTON_UP);
} else {
jwx_event.SetEventType(wxEVT_JOY_BUTTON_DOWN); jwx_event.SetEventType(wxEVT_JOY_BUTTON_DOWN);
m_buttons |= mask; }
else
{
m_buttons &= ~(1 << j_evt.number);
jwx_event.SetEventType(wxEVT_JOY_BUTTON_UP);
} }
jwx_event.SetButtonState(m_buttons);
jwx_event.SetButtonChange(j_evt.number); 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 (m_catchwin)
m_catchwin->ProcessEvent(jwx_event); // if (m_polling)
if (m_polling) // wxThread::Sleep(m_polling);
usleep(m_polling*1000); }
}
close(m_device);
return NULL;
} }
////////////////////////////////////////////////////////////////////////////
wxJoystick::wxJoystick(int joystick)
: m_device(-1),
m_joystick(joystick),
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);
m_device = open(dev_name.fn_str(), O_RDONLY);
if (m_device != -1)
{
m_thread = new wxJoystickThread(m_device, m_joystick);
m_thread->Create();
m_thread->Run();
}
}
wxJoystick::~wxJoystick()
{
ReleaseCapture();
if (m_thread)
m_thread->Delete(); // It's detached so it will delete itself
m_device = -1;
}
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// State // State
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
wxPoint wxJoystick::GetPosition(void) const wxPoint wxJoystick::GetPosition() const
{ {
return m_lastposition; wxPoint pos(wxDefaultPosition);
if (m_thread) pos = m_thread->m_lastposition;
return pos;
} }
int wxJoystick::GetZPosition(void) const int wxJoystick::GetZPosition() const
{ {
return m_axe[3]; if (m_thread)
return m_thread->m_axe[wxJS_AXIS_Z];
return 0;
} }
int wxJoystick::GetButtonState(void) const int wxJoystick::GetButtonState() const
{ {
return m_buttons; if (m_thread)
return m_thread->m_buttons;
return 0;
} }
int wxJoystick::GetPOVPosition(void) const int wxJoystick::GetPOVPosition() const
{ {
return -1; return -1;
} }
int wxJoystick::GetPOVCTSPosition(void) const int wxJoystick::GetPOVCTSPosition() const
{ {
return -1; return -1;
} }
int wxJoystick::GetRudderPosition(void) const int wxJoystick::GetRudderPosition() const
{ {
return m_axe[4]; if (m_thread)
return m_thread->m_axe[wxJS_AXIS_RUDDER];
return 0;
} }
int wxJoystick::GetUPosition(void) const int wxJoystick::GetUPosition() const
{ {
return m_axe[5]; if (m_thread)
return m_thread->m_axe[wxJS_AXIS_U];
return 0;
} }
int wxJoystick::GetVPosition(void) const int wxJoystick::GetVPosition() const
{ {
return m_axe[6]; if (m_thread)
return m_thread->m_axe[wxJS_AXIS_V];
return 0;
} }
int wxJoystick::GetMovementThreshold(void) const int wxJoystick::GetMovementThreshold() const
{ {
return 0; return 0;
} }
@@ -178,17 +277,17 @@ void wxJoystick::SetMovementThreshold(int threshold)
// Capabilities // Capabilities
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
bool wxJoystick::IsOk(void) const bool wxJoystick::IsOk() const
{ {
return (m_joystick != -1); return (m_device != -1);
} }
int wxJoystick::GetNumberJoysticks(void) const int wxJoystick::GetNumberJoysticks() const
{ {
wxString dev_name; wxString dev_name;
int fd, j; int fd, j;
for (j=0;j<2;j++) { for (j=0; j<4; j++) {
dev_name.Printf(wxT("/dev/js%d"), j); dev_name.Printf(wxT("/dev/js%d"), j);
fd = open(dev_name.fn_str(), O_RDONLY); fd = open(dev_name.fn_str(), O_RDONLY);
if (fd == -1) if (fd == -1)
@@ -198,156 +297,158 @@ int wxJoystick::GetNumberJoysticks(void) const
return j; return j;
} }
int wxJoystick::GetManufacturerId(void) const int wxJoystick::GetManufacturerId() const
{ {
return 0; return 0;
} }
int wxJoystick::GetProductId(void) const int wxJoystick::GetProductId() const
{ {
return 0; return 0;
} }
wxString wxJoystick::GetProductName(void) const wxString wxJoystick::GetProductName() const
{ {
wxString dev_name; char name[128];
// 2002-08-20 johan@linkdata.se
// Return the device name in lieu of a better one if (ioctl(m_device, JSIOCGNAME(sizeof(name)), name) < 0)
dev_name.Printf( wxT("/dev/js%d"), (m_joystick == wxJOYSTICK1) ? 0 : 1); // FIXME Unicode? strcpy(name, "Unknown");
return dev_name; return wxString(name, wxConvLibc);
} }
int wxJoystick::GetXMin(void) const int wxJoystick::GetXMin() const
{ {
return JOYSTICK_AXE_MAX; return wxJS_AXIS_MIN;
} }
int wxJoystick::GetYMin(void) const int wxJoystick::GetYMin() const
{ {
return JOYSTICK_AXE_MAX; return wxJS_AXIS_MIN;
} }
int wxJoystick::GetZMin(void) const int wxJoystick::GetZMin() const
{ {
return JOYSTICK_AXE_MAX; return wxJS_AXIS_MIN;
} }
int wxJoystick::GetXMax(void) const int wxJoystick::GetXMax() const
{ {
return JOYSTICK_AXE_MAX; return wxJS_AXIS_MAX;
} }
int wxJoystick::GetYMax(void) const int wxJoystick::GetYMax() const
{ {
return JOYSTICK_AXE_MAX; return wxJS_AXIS_MAX;
} }
int wxJoystick::GetZMax(void) const int wxJoystick::GetZMax() const
{ {
return JOYSTICK_AXE_MAX; return wxJS_AXIS_MAX;
} }
int wxJoystick::GetNumberButtons(void) const int wxJoystick::GetNumberButtons() const
{ {
int nb; char nb=0;
ioctl(m_joystick, JSIOCGBUTTONS, &nb); if (m_device != -1)
ioctl(m_device, JSIOCGBUTTONS, &nb);
return nb; return nb;
} }
int wxJoystick::GetNumberAxes(void) const int wxJoystick::GetNumberAxes() const
{ {
int nb; char nb=0;
ioctl(m_joystick, JSIOCGAXES, &nb); if (m_device != -1)
ioctl(m_device, JSIOCGAXES, &nb);
return nb; return nb;
} }
int wxJoystick::GetMaxButtons(void) const int wxJoystick::GetMaxButtons() const
{ {
return 15; // internal return 15; // internal
} }
int wxJoystick::GetMaxAxes(void) const int wxJoystick::GetMaxAxes() const
{ {
return 15; // internal return 15; // internal
} }
int wxJoystick::GetPollingMin(void) const int wxJoystick::GetPollingMin() const
{ {
return -1; return 10;
} }
int wxJoystick::GetPollingMax(void) const int wxJoystick::GetPollingMax() const
{ {
return -1; return 1000;
} }
int wxJoystick::GetRudderMin(void) const int wxJoystick::GetRudderMin() const
{ {
return JOYSTICK_AXE_MIN; return wxJS_AXIS_MIN;
} }
int wxJoystick::GetRudderMax(void) const int wxJoystick::GetRudderMax() const
{ {
return JOYSTICK_AXE_MAX; return wxJS_AXIS_MAX;
} }
int wxJoystick::GetUMin(void) const int wxJoystick::GetUMin() const
{ {
return JOYSTICK_AXE_MIN; return wxJS_AXIS_MIN;
} }
int wxJoystick::GetUMax(void) const int wxJoystick::GetUMax() const
{ {
return JOYSTICK_AXE_MAX; return wxJS_AXIS_MAX;
} }
int wxJoystick::GetVMin(void) const int wxJoystick::GetVMin() const
{ {
return JOYSTICK_AXE_MIN; return wxJS_AXIS_MIN;
} }
int wxJoystick::GetVMax(void) const int wxJoystick::GetVMax() const
{ {
return JOYSTICK_AXE_MAX; return wxJS_AXIS_MAX;
} }
bool wxJoystick::HasRudder(void) const bool wxJoystick::HasRudder() const
{ {
return GetNumberAxes() >= 4; return GetNumberAxes() >= wxJS_AXIS_RUDDER;
} }
bool wxJoystick::HasZ(void) const bool wxJoystick::HasZ() const
{ {
return GetNumberAxes() >= 3; return GetNumberAxes() >= wxJS_AXIS_Z;
} }
bool wxJoystick::HasU(void) const bool wxJoystick::HasU() const
{ {
return GetNumberAxes() >= 5; return GetNumberAxes() >= wxJS_AXIS_U;
} }
bool wxJoystick::HasV(void) const bool wxJoystick::HasV() const
{ {
return GetNumberAxes() >= 6; return GetNumberAxes() >= wxJS_AXIS_V;
} }
bool wxJoystick::HasPOV(void) const bool wxJoystick::HasPOV() const
{ {
return FALSE; return false;
} }
bool wxJoystick::HasPOV4Dir(void) const bool wxJoystick::HasPOV4Dir() const
{ {
return FALSE; return false;
} }
bool wxJoystick::HasPOVCTS(void) const bool wxJoystick::HasPOVCTS() const
{ {
return FALSE; return false;
} }
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
@@ -356,16 +457,24 @@ bool wxJoystick::HasPOVCTS(void) const
bool wxJoystick::SetCapture(wxWindow* win, int pollingFreq) bool wxJoystick::SetCapture(wxWindow* win, int pollingFreq)
{ {
m_catchwin = win; if (m_thread)
m_polling = pollingFreq; {
return TRUE; m_thread->m_catchwin = win;
m_thread->m_polling = pollingFreq;
return true;
}
return false;
} }
bool wxJoystick::ReleaseCapture(void) bool wxJoystick::ReleaseCapture()
{ {
m_catchwin = NULL; if (m_thread)
m_polling = 0; {
return TRUE; m_thread->m_catchwin = NULL;
m_thread->m_polling = 0;
return true;
}
return false;
} }
#endif // wxUSE_JOYSTICK #endif // wxUSE_JOYSTICK