ndof device detection on Windows, safer button handling
authorMike Erwin <significant.bit@gmail.com>
Sat, 18 Jun 2011 16:50:54 +0000 (16:50 +0000)
committerMike Erwin <significant.bit@gmail.com>
Sat, 18 Jun 2011 16:50:54 +0000 (16:50 +0000)
intern/ghost/intern/GHOST_NDOFManager.cpp
intern/ghost/intern/GHOST_NDOFManager.h
intern/ghost/intern/GHOST_SystemWin32.cpp
intern/ghost/intern/GHOST_SystemWin32.h

index 8cd5728601d0c2e6a8f1027b777ac81197d0a4c7..3bb1d990f28eab053c9cbc784d5c1ec77c7aa783 100644 (file)
@@ -134,7 +134,9 @@ static const NDOF_ButtonT SpacePilotPro_HID_map[] =
 
 GHOST_NDOFManager::GHOST_NDOFManager(GHOST_System& sys)
        : m_system(sys)
-       , m_deviceType(NDOF_UnknownDevice) // each platform needs its own device detection code
+       , m_deviceType(NDOF_UnknownDevice) // each platform has its own device detection code
+       , m_buttonCount(0)
+       , m_buttonMask(0)
        , m_buttons(0)
        , m_motionTime(1000) // one full second (operators should filter out such large time deltas)
        , m_prevMotionTime(0)
@@ -154,10 +156,26 @@ void GHOST_NDOFManager::setDevice(unsigned short vendor_id, unsigned short produ
                        switch (product_id)
                                {
                                // -- current devices --
-                               case 0xC626: m_deviceType = NDOF_SpaceNavigator; break;
-                               case 0xC628: m_deviceType = NDOF_SpaceNavigator; /* for Notebooks */ break;
-                               case 0xC627: m_deviceType = NDOF_SpaceExplorer; break;
-                               case 0xC629: m_deviceType = NDOF_SpacePilotPro; break;
+                               case 0xC626:
+                                       m_deviceType = NDOF_SpaceNavigator;
+                                       m_buttonCount = 2;
+//                                     m_buttonMask = 0x3; // 2 buttons
+                                       break;
+                               case 0xC628:
+                                       m_deviceType = NDOF_SpaceNavigator; // for Notebooks
+                                       m_buttonCount = 2;
+//                                     m_buttonMask = 0x3; // 2 buttons
+                                       break;
+                               case 0xC627:
+                                       m_deviceType = NDOF_SpaceExplorer;
+                                       m_buttonCount = 15;
+//                                     m_buttonMask = 0x7FFF; // 15 buttons
+                                       break;
+                               case 0xC629:
+                                       m_deviceType = NDOF_SpacePilotPro;
+                                       m_buttonCount = 29;
+//                                     m_buttonMask = 0x1FFFFFFF; // 29 buttons
+                                       break;
 
                                // -- older devices --
                                case 0xC623: puts("ndof: SpaceTraveler not supported, please file a bug report"); break;
@@ -169,6 +187,9 @@ void GHOST_NDOFManager::setDevice(unsigned short vendor_id, unsigned short produ
                default:
                        printf("ndof: unknown vendor %04hx\n", vendor_id);
                }
+
+       m_buttonMask = ~(-1 << m_buttonCount);
+       printf("ndof: %d buttons -> %X\n", m_buttonCount, m_buttonMask);
        }
 
 void GHOST_NDOFManager::updateTranslation(short t[3], GHOST_TUns64 time)
@@ -217,7 +238,8 @@ void GHOST_NDOFManager::updateButton(int button_number, bool press, GHOST_TUns64
        GHOST_IWindow* window = m_system.getWindowManager()->getActiveWindow();
 
        #ifdef DEBUG_NDOF_BUTTONS
-       printf("ndof: button %d -> ", button_number);
+       if (m_deviceType != NDOF_UnknownDevice)
+               printf("ndof: button %d -> ", button_number);
        #endif
 
        switch (m_deviceType)
@@ -258,6 +280,8 @@ void GHOST_NDOFManager::updateButton(int button_number, bool press, GHOST_TUns64
 
 void GHOST_NDOFManager::updateButtons(int button_bits, GHOST_TUns64 time)
        {
+       button_bits &= m_buttonMask; // discard any "garbage" bits
+
        int diff = m_buttons ^ button_bits;
 
        for (int button_number = 0; button_number <= 31; ++button_number)
index 9e4ceab2d55aaeef0f2a74f02e7e2ecde9188b82..1a25c60f45692e6f0d80aa8d778804e3da7376e7 100644 (file)
@@ -115,6 +115,8 @@ private:
 
 
        NDOF_DeviceT m_deviceType;
+       int m_buttonCount;
+       int m_buttonMask;
 
        short m_translation[3];
        short m_rotation[3];
index 4548d6b34ebef818a22b0e2dce7b5b5fe648fa2a..76508158a143ce08783f50f32ba8a90c3b7530a3 100644 (file)
@@ -818,9 +818,28 @@ void GHOST_SystemWin32::processMinMaxInfo(MINMAXINFO * minmax)
        minmax->ptMinTrackSize.y=240;
 }
 
-bool GHOST_SystemWin32::processNDOF(/*GHOST_WindowWin32* window,*/ RAWINPUT const& raw)
+bool GHOST_SystemWin32::processNDOF(RAWINPUT const& raw)
 {
        bool eventSent = false;
+       GHOST_TUns64 now = getMilliSeconds();
+
+       static bool firstEvent = true;
+       if (firstEvent)
+               { // determine exactly which device is plugged in
+               RID_DEVICE_INFO info;
+               unsigned infoSize = sizeof(RID_DEVICE_INFO);
+               info.cbSize = infoSize;
+
+               GetRawInputDeviceInfo(raw.header.hDevice, RIDI_DEVICEINFO, &info, &infoSize);
+               if (info.dwType == RIM_TYPEHID)
+                       {
+                       printf("hardware ID = %08X:%08X\n", info.hid.dwVendorId, info.hid.dwProductId);
+                       m_ndofManager->setDevice(info.hid.dwVendorId, info.hid.dwProductId);
+                       }
+               else puts("<!> not a HID device... mouse/kb perhaps?");
+
+               firstEvent = false;
+               }
 
        // The NDOF manager sends button changes immediately, and *pretends* to
        // send motion. Mark as 'sent' so motion will always get dispatched.
@@ -839,26 +858,39 @@ bool GHOST_SystemWin32::processNDOF(/*GHOST_WindowWin32* window,*/ RAWINPUT cons
                {
                case 1: // translation
                        {
-                       short t[3];
-                       memcpy(t, data + 1, sizeof(t));
-                       m_ndofManager->updateTranslation(t, getMilliSeconds());
+                       short axis_data[3];
+                       memcpy(axis_data, data + 1, sizeof(axis_data));
+                       m_ndofManager->updateTranslation(axis_data, now);
                        // wariness of alignment issues prevents me from saying it this way:
                        // m_ndofManager->updateTranslation((short*)(data + 1), getMilliSeconds());
                        // though it probably (94.7%) would work fine
+
+                       if (raw.data.hid.dwSizeHid == 13)
+                               { // this report also includes rotation
+                               puts("ndof: combined T + R");
+                               memcpy(axis_data, data + 7, sizeof(axis_data));
+                               m_ndofManager->updateRotation(axis_data, now);
+                               }
                        break;
                        }
                case 2: // rotation
                        {
-                       short r[3];
-                       memcpy(r, data + 1, sizeof(r));
-                       m_ndofManager->updateRotation(r, getMilliSeconds());
+                       short axis_data[3];
+                       memcpy(axis_data, data + 1, sizeof(axis_data));
+                       m_ndofManager->updateRotation(axis_data, now);
                        break;
                        }
                case 3: // buttons
                        {
+                       // I'm getting garbage bits -- examine whole report:
+                       printf("ndof: HID report for buttons [");
+                       for (int i = 0; i < raw.data.hid.dwSizeHid; ++i)
+                               printf(" %02X", data[i]);
+                       printf(" ]\n");
+
                        int button_bits;
                        memcpy(&button_bits, data + 1, sizeof(button_bits));
-                       m_ndofManager->updateButtons(button_bits, getMilliSeconds());
+                       m_ndofManager->updateButtons(button_bits, now);
                        break;
                        }
                }
@@ -910,7 +942,7 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
                                                }
                                                break;
                                        case RIM_TYPEHID:
-                                               if (system->processNDOF(/*window,*/ raw))
+                                               if (system->processNDOF(raw))
                                                        eventHandled = true;
                                                break;
                                        }
index cfb88bace1069afcb50ffb0eb026fced186f1c51..dae8bf9a31a56750fbae39c80ef837a46563e4fb 100644 (file)
@@ -397,11 +397,10 @@ protected:
         * Handles Motion and Button events from a SpaceNavigator or related device.
         * Instead of returning an event object, this function communicates directly
         * with the GHOST_NDOFManager.
-        * @param window        The window receiving the event (the active window).
         * @param raw           RawInput structure with detailed info about the NDOF event
         * @return Whether an event was generated and sent.
         */
-       bool processNDOF(/*GHOST_IWindow *window,*/ RAWINPUT const& raw);
+       bool processNDOF(RAWINPUT const& raw);
 
        /**
         * Returns the local state of the modifier keys (from the message queue).