-void *wxJoystick::Entry(void)
-{
-  struct js_event j_evt;
-  wxJoystickEvent jwx_event;
-  fd_set read_fds;
-  struct timeval time_out = {0, 0};
-
-  FD_ZERO(&read_fds);
-  while (1) {
-    TestDestroy();
-
-    if (m_polling) {
-      FD_SET(m_joystick, &read_fds);
-      select(m_joystick+1, &read_fds, NULL, NULL, &time_out);
-      if (FD_ISSET(m_joystick, &read_fds))
-        read(m_joystick, &j_evt, sizeof(j_evt));
-      else
-        j_evt.type = 0;
-    } else {
-      read(m_joystick, &j_evt, sizeof(j_evt));
+
+class wxJoystickThread : public wxThread
+{
+public:
+    wxJoystickThread(int device, int joystick);
+    void* Entry();
+
+private:
+    void      SendEvent(wxEventType type, long ts, int change = 0);
+    int       m_device;
+    int       m_joystick;
+    wxPoint   m_lastposition;
+    int       m_axe[wxJS_MAX_AXES];
+    int       m_buttons;
+    wxWindow* m_catchwin;
+    int       m_polling;
+    int       m_threshold;
+
+    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),
+      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->GetEventHandler()->AddPendingEvent(jwx_event);
+}
+
+void* wxJoystickThread::Entry()
+{
+    struct js_event j_evt;
+    fd_set read_fds;
+    struct timeval time_out = {0, 0};
+
+    wxFD_ZERO(&read_fds);
+    while (true)
+    {
+        if (TestDestroy())
+            break;
+
+        // We use select when either polling or 'blocking' as even in the
+        // blocking case we need to check TestDestroy periodically
+        if (m_polling)
+            time_out.tv_usec = m_polling * 1000;
+        else
+            time_out.tv_usec = 10 * 1000; // check at least every 10 msec in blocking case
+
+        wxFD_SET(m_device, &read_fds);
+        select(m_device+1, &read_fds, NULL, NULL, &time_out);
+        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 ((j_evt.type & JS_EVENT_AXIS) && (j_evt.number < wxJS_MAX_AXES))
+            {
+                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)
+                {
+                    case wxJS_AXIS_X:
+                        m_lastposition.x = j_evt.value;
+                        SendEvent(wxEVT_JOY_MOVE, j_evt.time);
+                        break;
+                    case wxJS_AXIS_Y:
+                        m_lastposition.y = j_evt.value;
+                        SendEvent(wxEVT_JOY_MOVE, j_evt.time);
+                        break;
+                    case wxJS_AXIS_Z:
+                        SendEvent(wxEVT_JOY_ZMOVE, j_evt.time);
+                        break;
+                    default:
+                        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) && (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);
+                }
+            }
+        }