svn merge -r38814:38905 https://svn.blender.org/svnroot/bf-blender/trunk/blender .
[blender.git] / intern / ghost / intern / GHOST_SystemWin32.cpp
index 95b3456ce3bca4ad45e9a2f507209f2979353c84..1b43fa92bb26771d0d0d2567e5ec367c43da22c6 100644 (file)
  * @date       May 7, 2001
  */
 
+#ifdef BF_GHOST_DEBUG
 #include <iostream>
-
-#ifdef FREE_WINDOWS
-#  define WINVER 0x0501 /* GetConsoleWindow() for MinGW */
 #endif
 
+#include <stdio.h> // [mce] temporary debug, remove soon!
+
 #include "GHOST_SystemWin32.h"
 #include "GHOST_EventDragnDrop.h"
 
-#define WIN32_LEAN_AND_MEAN
-#ifdef _WIN32_IE
-#undef _WIN32_IE
+#ifndef _WIN32_IE
+#define _WIN32_IE 0x0501 /* shipped before XP, so doesn't impose additional requirements */
 #endif
-#define _WIN32_IE 0x0501
-#include <windows.h>
 #include <shlobj.h>
 #include <tlhelp32.h>
 
 #endif
 #endif
 
-/*
- * According to the docs the mouse wheel message is supported from windows 98 
- * upwards. Leaving WINVER at default value, the WM_MOUSEWHEEL message and the 
- * wheel detent value are undefined.
- */
-#ifndef WM_MOUSEWHEEL
-#define WM_MOUSEWHEEL 0x020A
-#endif // WM_MOUSEWHEEL
-#ifndef WHEEL_DELTA
-#define WHEEL_DELTA 120        /* Value for rolling one detent, (old convention! MS changed it) */
-#endif // WHEEL_DELTA
-
-/* 
- * Defines for mouse buttons 4 and 5 aka xbutton1 and xbutton2.
- * MSDN: Declared in Winuser.h, include Windows.h 
- * This does not seem to work with MinGW so we define our own here.
- */
-#ifndef XBUTTON1
-#define XBUTTON1 0x0001
-#endif // XBUTTON1
-#ifndef XBUTTON2
-#define XBUTTON2 0x0002
-#endif // XBUTTON2
-#ifndef WM_XBUTTONUP
-#define WM_XBUTTONUP 524
-#endif // WM_XBUTTONUP
-#ifndef WM_XBUTTONDOWN
-#define WM_XBUTTONDOWN 523
-#endif // WM_XBUTTONDOWN
-
 #include "GHOST_Debug.h"
 #include "GHOST_DisplayManagerWin32.h"
 #include "GHOST_EventButton.h"
 #include "GHOST_EventCursor.h"
 #include "GHOST_EventKey.h"
 #include "GHOST_EventWheel.h"
-#include "GHOST_EventNDOF.h"
 #include "GHOST_TimerTask.h"
 #include "GHOST_TimerManager.h"
 #include "GHOST_WindowManager.h"
 #include "GHOST_WindowWin32.h"
-#include "GHOST_NDOFManager.h"
+#include "GHOST_NDOFManagerWin32.h"
 
 // Key code values not found in winuser.h
 #ifndef VK_MINUS
 #define VK_MEDIA_PLAY_PAUSE    0xB3
 #endif // VK_MEDIA_PLAY_PAUSE
 
-/*
-       Initiates WM_INPUT messages from keyboard
-       That way GHOST can retrieve true keys
-*/
-GHOST_TInt32 GHOST_SystemWin32::initKeyboardRawInput(void)
+static void initRawInput()
 {
-       RAWINPUTDEVICE device = {0};
-       device.usUsagePage      = 0x01; /* usUsagePage & usUsage for keyboard*/
-       device.usUsage          = 0x06; /* http://msdn.microsoft.com/en-us/windows/hardware/gg487473.aspx */
+       RAWINPUTDEVICE devices[2];
+       memset(devices, 0, 2 * sizeof(RAWINPUTDEVICE));
 
-       return RegisterRawInputDevices(&device, 1, sizeof(device));
-};
+       // multi-axis mouse (SpaceNavigator, etc.)
+       devices[0].usUsagePage = 0x01;
+       devices[0].usUsage = 0x08;
+
+       // Initiates WM_INPUT messages from keyboard
+       // That way GHOST can retrieve true keys
+       devices[1].usUsagePage = 0x01;
+       devices[1].usUsage = 0x06; /* http://msdn.microsoft.com/en-us/windows/hardware/gg487473.aspx */
+
+       if (RegisterRawInputDevices(devices, 2, sizeof(RAWINPUTDEVICE)))
+               puts("registered for RawInput (spacenav & keyboard)");
+       else
+               printf("could not register for RawInput: %d\n", (int)GetLastError());
+}
 
 GHOST_SystemWin32::GHOST_SystemWin32()
 : m_hasPerformanceCounter(false), m_freq(0), m_start(0)
@@ -187,6 +160,8 @@ GHOST_SystemWin32::GHOST_SystemWin32()
        this->handleKeyboardChange();
        // Require COM for GHOST_DropTargetWin32 created in GHOST_WindowWin32.
        OleInitialize(0);
+
+       m_ndofManager = new GHOST_NDOFManagerWin32(*this);
 }
 
 GHOST_SystemWin32::~GHOST_SystemWin32()
@@ -245,6 +220,7 @@ GHOST_IWindow* GHOST_SystemWin32::createWindow(
                        // Store the pointer to the window
 //                     if (state != GHOST_kWindowStateFullScreen) {
                                m_windowManager->addWindow(window);
+                               m_windowManager->setActiveWindow(window);
 //                     }
                }
                else {
@@ -385,22 +361,15 @@ GHOST_TSuccess GHOST_SystemWin32::init()
        GHOST_TSuccess success = GHOST_System::init();
        
        /* Disable scaling on high DPI displays on Vista */
+       HMODULE
        user32 = ::LoadLibraryA("user32.dll");
        typedef BOOL (WINAPI * LPFNSETPROCESSDPIAWARE)();
        LPFNSETPROCESSDPIAWARE SetProcessDPIAware =
                (LPFNSETPROCESSDPIAWARE)GetProcAddress(user32, "SetProcessDPIAware");
        if (SetProcessDPIAware)
                SetProcessDPIAware();
-       #ifdef NEED_RAW_PROC
-               pRegisterRawInputDevices = (LPFNDLLRRID)GetProcAddress(user32, "RegisterRawInputDevices");
-               pGetRawInputData = (LPFNDLLGRID)GetProcAddress(user32, "GetRawInputData");
-       #else
-               FreeLibrary(user32);
-       #endif
-
-       /*      Initiates WM_INPUT messages from keyboard */
-       initKeyboardRawInput();
-
+       FreeLibrary(user32);
+       initRawInput();
 
        // Determine whether this system has a high frequency performance counter. */
        m_hasPerformanceCounter = ::QueryPerformanceFrequency((LARGE_INTEGER*)&m_freq) == TRUE;
@@ -441,104 +410,84 @@ GHOST_TSuccess GHOST_SystemWin32::init()
 
 GHOST_TSuccess GHOST_SystemWin32::exit()
 {
-       #ifdef NEED_RAW_PROC
-       FreeLibrary(user32);
-       #endif
-
        return GHOST_System::exit();
 }
 
-GHOST_TKey GHOST_SystemWin32::hardKey(GHOST_IWindow *window, WPARAM wParam, LPARAM lParam, int * keyDown, char * vk)
+GHOST_TKey GHOST_SystemWin32::hardKey(GHOST_IWindow *window, RAWINPUT const& raw, int * keyDown, char * vk)
 {
-       unsigned int size = 0;
-       char * data;
        GHOST_TKey key = GHOST_kKeyUnknown;
 
 
        if(!keyDown)
                return GHOST_kKeyUnknown;
 
-       GetRawInputData((HRAWINPUT)lParam, RID_INPUT, 0, &size, sizeof(RAWINPUTHEADER));
 
+       GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem();
 
-       if((data = (char*)malloc(size)) &&
-               GetRawInputData((HRAWINPUT)lParam, RID_INPUT, data, &size, sizeof(RAWINPUTHEADER)))
+       GHOST_ModifierKeys modifiers;
+       system->retrieveModifierKeys(modifiers);
+       
+       *keyDown = !(raw.data.keyboard.Flags & RI_KEY_BREAK);
+       key = this->convertKey(window, raw.data.keyboard.VKey, raw.data.keyboard.MakeCode, (raw.data.keyboard.Flags&(RI_KEY_E1|RI_KEY_E0)));
+       
+       // extra handling of modifier keys: don't send repeats out from GHOST
+       if(key >= GHOST_kKeyLeftShift && key <= GHOST_kKeyRightAlt)
        {
-               RAWINPUT ri;
-               memcpy(&ri,data,(size < sizeof(ri)) ? size : sizeof(ri));
-
-               if (ri.header.dwType == RIM_TYPEKEYBOARD)
-               {
-                       GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem();
-                       
-                       GHOST_ModifierKeys modifiers;
-                       system->retrieveModifierKeys(modifiers);
-                       
-                       *keyDown = !(ri.data.keyboard.Flags & RI_KEY_BREAK);
-                       key = this->convertKey(window, ri.data.keyboard.VKey, ri.data.keyboard.MakeCode, (ri.data.keyboard.Flags&(RI_KEY_E1|RI_KEY_E0)));
-                       
-                       // extra handling of modifier keys: don't send repeats out from GHOST
-                       if(key >= GHOST_kKeyLeftShift && key <= GHOST_kKeyRightAlt)
-                       {
-                               bool changed = false;
-                               GHOST_TModifierKeyMask modifier;
-                               switch(key) {
-                                       case GHOST_kKeyLeftShift:
-                                               {
-                                                       changed = (modifiers.get(GHOST_kModifierKeyLeftShift) != (bool)*keyDown);
-                                                       modifier = GHOST_kModifierKeyLeftShift;
-                                               }
-                                               break;
-                                       case GHOST_kKeyRightShift:
-                                               {
-                                                       changed = (modifiers.get(GHOST_kModifierKeyRightShift) != (bool)*keyDown);
-                                                       modifier = GHOST_kModifierKeyRightShift;
-                                               }
-                                               break;
-                                       case GHOST_kKeyLeftControl:
-                                               {
-                                                       changed = (modifiers.get(GHOST_kModifierKeyLeftControl) != (bool)*keyDown);
-                                                       modifier = GHOST_kModifierKeyLeftControl;
-                                               }
-                                               break;
-                                       case GHOST_kKeyRightControl:
-                                               {
-                                                       changed = (modifiers.get(GHOST_kModifierKeyRightControl) != (bool)*keyDown);
-                                                       modifier = GHOST_kModifierKeyRightControl;
-                                               }
-                                               break;
-                                       case GHOST_kKeyLeftAlt:
-                                               {
-                                                       changed = (modifiers.get(GHOST_kModifierKeyLeftAlt) != (bool)*keyDown);
-                                                       modifier = GHOST_kModifierKeyLeftAlt;
-                                               }
-                                               break;
-                                       case GHOST_kKeyRightAlt:
-                                               {
-                                                       changed = (modifiers.get(GHOST_kModifierKeyRightAlt) != (bool)*keyDown);
-                                                       modifier = GHOST_kModifierKeyRightAlt;
-                                               }
-                                               break;
-                                       default: break;
+               bool changed = false;
+               GHOST_TModifierKeyMask modifier;
+               switch(key) {
+                       case GHOST_kKeyLeftShift:
+                               {
+                                       changed = (modifiers.get(GHOST_kModifierKeyLeftShift) != (bool)*keyDown);
+                                       modifier = GHOST_kModifierKeyLeftShift;
                                }
-                               
-                               if(changed)
+                               break;
+                       case GHOST_kKeyRightShift:
                                {
-                                       modifiers.set(modifier, (bool)*keyDown);
-                                       system->storeModifierKeys(modifiers);
+                                       changed = (modifiers.get(GHOST_kModifierKeyRightShift) != (bool)*keyDown);
+                                       modifier = GHOST_kModifierKeyRightShift;
+                               }
+                               break;
+                       case GHOST_kKeyLeftControl:
+                               {
+                                       changed = (modifiers.get(GHOST_kModifierKeyLeftControl) != (bool)*keyDown);
+                                       modifier = GHOST_kModifierKeyLeftControl;
                                }
-                               else
+                               break;
+                       case GHOST_kKeyRightControl:
                                {
-                                       key = GHOST_kKeyUnknown;
+                                       changed = (modifiers.get(GHOST_kModifierKeyRightControl) != (bool)*keyDown);
+                                       modifier = GHOST_kModifierKeyRightControl;
                                }
-                       }
-                       
+                               break;
+                       case GHOST_kKeyLeftAlt:
+                               {
+                                       changed = (modifiers.get(GHOST_kModifierKeyLeftAlt) != (bool)*keyDown);
+                                       modifier = GHOST_kModifierKeyLeftAlt;
+                               }
+                               break;
+                       case GHOST_kKeyRightAlt:
+                               {
+                                       changed = (modifiers.get(GHOST_kModifierKeyRightAlt) != (bool)*keyDown);
+                                       modifier = GHOST_kModifierKeyRightAlt;
+                               }
+                               break;
+                       default: break;
+               }
+               
+               if(changed)
+               {
+                       modifiers.set(modifier, (bool)*keyDown);
+                       system->storeModifierKeys(modifiers);
+               }
+               else
+               {
+                       key = GHOST_kKeyUnknown;
+               }
+       }
        
-                       if(vk) *vk = ri.data.keyboard.VKey;
-               };
 
-       };
-       free(data);
+       if(vk) *vk = raw.data.keyboard.VKey;
 
        return key;
 }
@@ -742,12 +691,12 @@ GHOST_EventWheel* GHOST_SystemWin32::processWheelEvent(GHOST_IWindow *window, WP
 }
 
 
-GHOST_EventKey* GHOST_SystemWin32::processKeyEvent(GHOST_IWindow *window, WPARAM wParam, LPARAM lParam)
+GHOST_EventKey* GHOST_SystemWin32::processKeyEvent(GHOST_IWindow *window, RAWINPUT const& raw)
 {
        int keyDown=0;
        char vk;
        GHOST_SystemWin32 * system = (GHOST_SystemWin32 *)getSystem();
-       GHOST_TKey key = system->hardKey(window, wParam, lParam, &keyDown, &vk);
+       GHOST_TKey key = system->hardKey(window, raw, &keyDown, &vk);
        GHOST_EventKey* event;
        if (key != GHOST_kKeyUnknown) {
                char ascii = '\0';
@@ -777,7 +726,15 @@ GHOST_EventKey* GHOST_SystemWin32::processKeyEvent(GHOST_IWindow *window, WPARAM
 
 GHOST_Event* GHOST_SystemWin32::processWindowEvent(GHOST_TEventType type, GHOST_IWindow* window)
 {
-       return new GHOST_Event(getSystem()->getMilliSeconds(), type, window);
+       GHOST_System* system = (GHOST_System*)getSystem();
+
+       if (type == GHOST_kEventWindowActivate)
+               {
+               puts("activating window");
+               system->getWindowManager()->setActiveWindow(window);
+               }
+
+       return new GHOST_Event(system->getMilliSeconds(), type, window);
 }
 
 GHOST_TSuccess GHOST_SystemWin32::pushDragDropEvent(GHOST_TEventType eventType, 
@@ -800,9 +757,101 @@ void GHOST_SystemWin32::processMinMaxInfo(MINMAXINFO * minmax)
        minmax->ptMinTrackSize.y=240;
 }
 
+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)
+                       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.
+       eventSent = true;
+
+#ifdef _MSC_VER
+    // using Microsoft compiler & header files
+    // they invented the RawInput API, so this version is (probably) correct
+       BYTE const* data = raw.data.hid.bRawData;
+       // struct RAWHID {
+       // DWORD dwSizeHid;
+       // DWORD dwCount;
+       // BYTE  bRawData[1];
+       // };
+#else
+       // MinGW's definition (below) doesn't agree, so we need a slight
+       // workaround until it's fixed
+       BYTE const* data = &raw.data.hid.bRawData;
+       // struct RAWHID {
+       // DWORD dwSizeHid;
+       // DWORD dwCount;
+       // BYTE bRawData; // <== isn't this s'posed to be a BYTE*?
+       // };
+#endif
+
+       BYTE packetType = data[0];
+       switch (packetType)
+               {
+               case 1: // translation
+                       {
+                       short* axis = (short*)(data + 1);
+                       short t[3] = {axis[0], -axis[2], axis[1]};
+                       m_ndofManager->updateTranslation(t, now);
+
+                       if (raw.data.hid.dwSizeHid == 13)
+                               { // this report also includes rotation
+                               short r[3] = {-axis[3], axis[5], -axis[4]};
+                               m_ndofManager->updateRotation(r, now);
+
+                               // I've never gotten one of these, has anyone else?
+                               puts("ndof: combined T + R");
+                               }
+                       break;
+                       }
+               case 2: // rotation
+                       {
+                       short* axis = (short*)(data + 1);
+                       short r[3] = {-axis[0], axis[2], -axis[1]};
+                       m_ndofManager->updateRotation(r, now);
+                       break;
+                       }
+               case 3: // buttons
+                       {
+                       #if 0
+                       // 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");
+                       #endif
+
+                       int button_bits;
+                       memcpy(&button_bits, data + 1, sizeof(button_bits));
+                       m_ndofManager->updateButtons(button_bits, now);
+                       break;
+                       }
+               }
+       return eventSent;
+}
+
 LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
        GHOST_Event* event = 0;
+       bool eventHandled = false;
+
        LRESULT lResult = 0;
        GHOST_SystemWin32* system = ((GHOST_SystemWin32*)getSystem());
        GHOST_ASSERT(system, "GHOST_SystemWin32::s_wndProc(): system not initialized")
@@ -819,18 +868,36 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
                                // Keyboard events, processed
                                ////////////////////////////////////////////////////////////////////////
                                case WM_INPUT:
+                               {
                                        // check WM_INPUT from input sink when ghost window is not in the foreground
                                        if (wParam == RIM_INPUTSINK) {
                                                if (GetFocus() != hwnd) // WM_INPUT message not for this window
                                                        return 0;
-                                       } //else wPAram == RIM_INPUT
-                                       event = processKeyEvent(window, wParam, lParam);
-                                       if (!event) {
-                                               GHOST_PRINT("GHOST_SystemWin32::wndProc: key event ")
-                                               GHOST_PRINT(msg)
-                                               GHOST_PRINT(" key ignored\n")
+                                       } //else wParam == RIM_INPUT
+
+                                       RAWINPUT raw;
+                                       RAWINPUT* raw_ptr = &raw;
+                                       UINT rawSize = sizeof(RAWINPUT);
+
+                                       GetRawInputData((HRAWINPUT)lParam, RID_INPUT, raw_ptr, &rawSize, sizeof(RAWINPUTHEADER));
+
+                                       switch (raw.header.dwType)
+                                       {
+                                       case RIM_TYPEKEYBOARD:
+                                               event = processKeyEvent(window, raw);
+                                               if (!event) {
+                                                       GHOST_PRINT("GHOST_SystemWin32::wndProc: key event ")
+                                                       GHOST_PRINT(msg)
+                                                       GHOST_PRINT(" key ignored\n")
+                                               }
+                                               break;
+                                       case RIM_TYPEHID:
+                                               if (system->processNDOF(raw))
+                                                       eventHandled = true;
+                                               break;
                                        }
-                                       break;
+                               break;
+                               }
                                ////////////////////////////////////////////////////////////////////////
                                // Keyboard events, ignored
                                ////////////////////////////////////////////////////////////////////////
@@ -840,9 +907,9 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
                                case WM_SYSKEYUP:
                                        /* These functions were replaced by WM_INPUT*/
                                case WM_CHAR:
-                                       /* The WM_CHAR message is posted to the window with the keyboard focus when 
-                                        * a WM_KEYDOWN message is translated by the TranslateMessage function. WM_CHAR 
-                                        * contains the character code of the key that was pressed. 
+                                       /* The WM_CHAR message is posted to the window with the keyboard focus when
+                                        * a WM_KEYDOWN message is translated by the TranslateMessage function. WM_CHAR
+                                        * contains the character code of the key that was pressed.
                                         */
                                case WM_DEADCHAR:
                                        /* The WM_DEADCHAR message is posted to the window with the keyboard focus when a
@@ -1128,28 +1195,6 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
                                         * In GHOST, we let DefWindowProc call the timer callback.
                                         */
                                        break;
-                               case WM_BLND_NDOF_AXIS:
-                                       {
-                                               GHOST_TEventNDOFData ndofdata;
-                                               system->m_ndofManager->GHOST_NDOFGetDatas(ndofdata);
-                                               system->m_eventManager->
-                                                       pushEvent(new GHOST_EventNDOF(
-                                                               system->getMilliSeconds(), 
-                                                               GHOST_kEventNDOFMotion, 
-                                                               window, ndofdata));
-                                       }
-                                       break;
-                               case WM_BLND_NDOF_BTN:
-                                       {
-                                               GHOST_TEventNDOFData ndofdata;
-                                               system->m_ndofManager->GHOST_NDOFGetDatas(ndofdata);
-                                               system->m_eventManager->
-                                                       pushEvent(new GHOST_EventNDOF(
-                                                               system->getMilliSeconds(), 
-                                                               GHOST_kEventNDOFButton, 
-                                                               window, ndofdata));
-                                       }
-                                       break;
                        }
                }
                else {
@@ -1171,10 +1216,12 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
 
        if (event) {
                system->pushEvent(event);
+               eventHandled = true;
        }
-       else {
+
+       if (!eventHandled)
                lResult = ::DefWindowProc(hwnd, msg, wParam, lParam);
-       }
+
        return lResult;
 }