]> git.saurik.com Git - wxWidgets.git/blobdiff - src/unix/joystick.cpp
Disable wxUSE_ENH_METAFILE for wxGTK builds.
[wxWidgets.git] / src / unix / joystick.cpp
index 0a32033ee32aad2cf472b190f297db1e44a2ef78..27b3b6cb74a8d67e254cc800c00ac3bc9c3134be 100644 (file)
@@ -1,5 +1,5 @@
 /////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////
-// Name:        joystick.cpp
+// Name:        src/unix/joystick.cpp
 // Purpose:     wxJoystick class
 // Author:      Ported to Linux by Guilhem Lavaux
 // Modified by:
 // Purpose:     wxJoystick class
 // Author:      Ported to Linux by Guilhem Lavaux
 // Modified by:
@@ -9,19 +9,21 @@
 // Licence:     wxWindows 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"
 
 // for compilers that support precompilation, includes "wx.h".
 #include "wx/wxprec.h"
 
-#include "wx/defs.h"
-
 #if wxUSE_JOYSTICK
 
 #include "wx/joystick.h"
 
 #if wxUSE_JOYSTICK
 
 #include "wx/joystick.h"
 
+#ifndef WX_PRECOMP
+    #include "wx/event.h"
+    #include "wx/window.h"
+    #include "wx/log.h"
+#endif //WX_PRECOMP
+
+#include "wx/thread.h"
+
 #include <linux/joystick.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <linux/joystick.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <unistd.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,
 
 enum {
     wxJS_AXIS_X = 0,
@@ -42,7 +47,9 @@ enum {
     wxJS_AXIS_V,
 
     wxJS_AXIS_MAX = 32767,
     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
 };
 
 
 };
 
 
@@ -60,13 +67,15 @@ public:
     void* Entry();
 
 private:
     void* Entry();
 
 private:
+    void      SendEvent(wxEventType type, long ts, int change = 0);
     int       m_device;
     int       m_joystick;
     wxPoint   m_lastposition;
     int       m_device;
     int       m_joystick;
     wxPoint   m_lastposition;
-    int       m_axe[15];
+    int       m_axe[wxJS_MAX_AXES];
     int       m_buttons;
     wxWindow* m_catchwin;
     int       m_polling;
     int       m_buttons;
     wxWindow* m_catchwin;
     int       m_polling;
+    int       m_threshold;
 
     friend class wxJoystick;
 };
 
     friend class wxJoystick;
 };
@@ -78,12 +87,24 @@ wxJoystickThread::wxJoystickThread(int device, int joystick)
       m_lastposition(wxDefaultPosition),
       m_buttons(0),
       m_catchwin(NULL),
       m_lastposition(wxDefaultPosition),
       m_buttons(0),
       m_catchwin(NULL),
-      m_polling(0)
+      m_polling(0),
+      m_threshold(0)
 {
 {
-    for (int i=0; i<15; i++)
-        m_axe[i] = 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->GetEventHandler()->AddPendingEvent(jwx_event);
+}
 
 void* wxJoystickThread::Entry()
 {
 
 void* wxJoystickThread::Entry()
 {
@@ -91,7 +112,7 @@ void* wxJoystickThread::Entry()
     fd_set read_fds;
     struct timeval time_out = {0, 0};
 
     fd_set read_fds;
     struct timeval time_out = {0, 0};
 
-    FD_ZERO(&read_fds);
+    wxFD_ZERO(&read_fds);
     while (true)
     {
         if (TestDestroy())
     while (true)
     {
         if (TestDestroy())
@@ -104,9 +125,9 @@ void* wxJoystickThread::Entry()
         else
             time_out.tv_usec = 10 * 1000; // check at least every 10 msec in blocking case
 
         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);
         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));
         {
             memset(&j_evt, 0, sizeof(j_evt));
             read(m_device, &j_evt, sizeof(j_evt));
@@ -114,9 +135,18 @@ void* wxJoystickThread::Entry()
             //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);
 
             //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);
 
-            wxJoystickEvent jwx_event;
+            if ((j_evt.type & JS_EVENT_AXIS) && (j_evt.number < wxJS_MAX_AXES))
+            {
+                // Ignore invalid axis.
+                if ( j_evt.number >= wxJS_MAX_AXES )
+                {
+                    wxLogDebug(wxS("Invalid axis index %d in joystick message."),
+                               j_evt.number);
+                    continue;
+                }
 
 
-            if (j_evt.type & JS_EVENT_AXIS)
+                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;
 
             {
                 m_axe[j_evt.number] = j_evt.value;
 
@@ -124,47 +154,36 @@ void* wxJoystickThread::Entry()
                 {
                     case wxJS_AXIS_X:
                         m_lastposition.x = j_evt.value;
                 {
                     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;
                         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:
                         break;
                     case wxJS_AXIS_Z:
-                        jwx_event.SetEventType(wxEVT_JOY_ZMOVE);
+                        SendEvent(wxEVT_JOY_ZMOVE, j_evt.time);
                         break;
                     default:
                         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;
                 }
             }
                         // TODO: There should be a way to indicate that the event
                         //       is for some other axes.
                         break;
                 }
             }
+            }
 
 
-            if (j_evt.type & JS_EVENT_BUTTON)
+            if ( (j_evt.type & JS_EVENT_BUTTON) && (j_evt.number < wxJS_MAX_BUTTONS) )
             {
                 if (j_evt.value)
                 {
                     m_buttons |= (1 << j_evt.number);
             {
                 if (j_evt.value)
                 {
                     m_buttons |= (1 << j_evt.number);
-                    jwx_event.SetEventType(wxEVT_JOY_BUTTON_DOWN);
+                    SendEvent(wxEVT_JOY_BUTTON_DOWN, j_evt.time, j_evt.number);
                 }
                 else
                 {
                     m_buttons &= ~(1 << j_evt.number);
                 }
                 else
                 {
                     m_buttons &= ~(1 << j_evt.number);
-                    jwx_event.SetEventType(wxEVT_JOY_BUTTON_UP);
+                    SendEvent(wxEVT_JOY_BUTTON_UP, j_evt.time, 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);
-
-                if (m_catchwin)
-                    m_catchwin->AddPendingEvent(jwx_event);
             }
         }
     }
             }
         }
     }
@@ -183,10 +202,17 @@ wxJoystick::wxJoystick(int joystick)
 {
     wxString dev_name;
 
 {
     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);
 
     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);
     if (m_device != -1)
     {
         m_thread = new wxJoystickThread(m_device, m_joystick);
@@ -216,6 +242,13 @@ wxPoint wxJoystick::GetPosition() const
     return pos;
 }
 
     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)
 int wxJoystick::GetZPosition() const
 {
     if (m_thread)
@@ -230,6 +263,13 @@ int wxJoystick::GetButtonState() const
     return 0;
 }
 
     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::GetPOVPosition() const
 {
     return -1;
@@ -263,11 +303,15 @@ int wxJoystick::GetVPosition() const
 
 int wxJoystick::GetMovementThreshold() const
 {
 
 int wxJoystick::GetMovementThreshold() const
 {
+    if (m_thread)
+        return m_thread->m_threshold;
     return 0;
 }
 
 void wxJoystick::SetMovementThreshold(int threshold)
 {
     return 0;
 }
 
 void wxJoystick::SetMovementThreshold(int threshold)
 {
+    if (m_thread)
+        m_thread->m_threshold = threshold;
 }
 
 ////////////////////////////////////////////////////////////////////////////
 }
 
 ////////////////////////////////////////////////////////////////////////////
@@ -279,7 +323,7 @@ bool wxJoystick::IsOk() const
     return (m_device != -1);
 }
 
     return (m_device != -1);
 }
 
-int wxJoystick::GetNumberJoysticks() const
+int wxJoystick::GetNumberJoysticks()
 {
     wxString dev_name;
     int fd, j;
 {
     wxString dev_name;
     int fd, j;
@@ -288,9 +332,20 @@ int wxJoystick::GetNumberJoysticks() const
         dev_name.Printf(wxT("/dev/js%d"), j);
         fd = open(dev_name.fn_str(), O_RDONLY);
         if (fd == -1)
         dev_name.Printf(wxT("/dev/js%d"), j);
         fd = open(dev_name.fn_str(), O_RDONLY);
         if (fd == -1)
-            return j;
+            break;
         close(fd);
     }
         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;
 }
 
     return j;
 }
 
@@ -350,6 +405,9 @@ int wxJoystick::GetNumberButtons() const
     if (m_device != -1)
         ioctl(m_device, JSIOCGBUTTONS, &nb);
 
     if (m_device != -1)
         ioctl(m_device, JSIOCGBUTTONS, &nb);
 
+    if ((int)nb > wxJS_MAX_BUTTONS)
+        nb = wxJS_MAX_BUTTONS;
+
     return nb;
 }
 
     return nb;
 }
 
@@ -360,17 +418,20 @@ int wxJoystick::GetNumberAxes() const
     if (m_device != -1)
         ioctl(m_device, JSIOCGAXES, &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 nb;
 }
 
 int wxJoystick::GetMaxButtons() const
 {
-    return 15; // internal
+    return wxJS_MAX_BUTTONS; // internal
 }
 
 int wxJoystick::GetMaxAxes() const
 {
 }
 
 int wxJoystick::GetMaxAxes() const
 {
-    return 15; // internal
+    return wxJS_MAX_AXES; // internal
 }
 
 int wxJoystick::GetPollingMin() const
 }
 
 int wxJoystick::GetPollingMin() const
@@ -474,4 +535,3 @@ bool wxJoystick::ReleaseCapture()
     return false;
 }
 #endif  // wxUSE_JOYSTICK
     return false;
 }
 #endif  // wxUSE_JOYSTICK
-