Blender V2.61 - r43446

GHOST_SystemWin32.cpp

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00019  * All rights reserved.
00020  *
00021  * The Original Code is: all of this file.
00022  *
00023  * Contributor(s): none yet.
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00040 #ifdef BF_GHOST_DEBUG
00041 #include <iostream>
00042 #endif
00043 
00044 #include <stdio.h> // [mce] temporary debug, remove soon!
00045 
00046 #include "GHOST_SystemWin32.h"
00047 #include "GHOST_EventDragnDrop.h"
00048 
00049 #ifndef _WIN32_IE
00050 #define _WIN32_IE 0x0501 /* shipped before XP, so doesn't impose additional requirements */
00051 #endif
00052 #include <shlobj.h>
00053 #include <tlhelp32.h>
00054 
00055 // win64 doesn't define GWL_USERDATA
00056 #ifdef WIN32
00057 #ifndef GWL_USERDATA
00058 #define GWL_USERDATA GWLP_USERDATA
00059 #define GWL_WNDPROC GWLP_WNDPROC 
00060 #endif
00061 #endif
00062 
00063 #include "GHOST_DisplayManagerWin32.h"
00064 #include "GHOST_EventButton.h"
00065 #include "GHOST_EventCursor.h"
00066 #include "GHOST_EventKey.h"
00067 #include "GHOST_EventWheel.h"
00068 #include "GHOST_TimerTask.h"
00069 #include "GHOST_TimerManager.h"
00070 #include "GHOST_WindowManager.h"
00071 #include "GHOST_WindowWin32.h"
00072 
00073 #ifdef WITH_INPUT_NDOF
00074 #include "GHOST_NDOFManagerWin32.h"
00075 #endif
00076 
00077 // Key code values not found in winuser.h
00078 #ifndef VK_MINUS
00079 #define VK_MINUS 0xBD
00080 #endif // VK_MINUS
00081 #ifndef VK_SEMICOLON
00082 #define VK_SEMICOLON 0xBA
00083 #endif // VK_SEMICOLON
00084 #ifndef VK_PERIOD
00085 #define VK_PERIOD 0xBE
00086 #endif // VK_PERIOD
00087 #ifndef VK_COMMA
00088 #define VK_COMMA 0xBC
00089 #endif // VK_COMMA
00090 #ifndef VK_QUOTE
00091 #define VK_QUOTE 0xDE
00092 #endif // VK_QUOTE
00093 #ifndef VK_BACK_QUOTE
00094 #define VK_BACK_QUOTE 0xC0
00095 #endif // VK_BACK_QUOTE
00096 #ifndef VK_SLASH
00097 #define VK_SLASH 0xBF
00098 #endif // VK_SLASH
00099 #ifndef VK_BACK_SLASH
00100 #define VK_BACK_SLASH 0xDC
00101 #endif // VK_BACK_SLASH
00102 #ifndef VK_EQUALS
00103 #define VK_EQUALS 0xBB
00104 #endif // VK_EQUALS
00105 #ifndef VK_OPEN_BRACKET
00106 #define VK_OPEN_BRACKET 0xDB
00107 #endif // VK_OPEN_BRACKET
00108 #ifndef VK_CLOSE_BRACKET
00109 #define VK_CLOSE_BRACKET 0xDD
00110 #endif // VK_CLOSE_BRACKET
00111 #ifndef VK_GR_LESS
00112 #define VK_GR_LESS 0xE2
00113 #endif // VK_GR_LESS
00114 
00115 #ifndef VK_MEDIA_NEXT_TRACK
00116 #define VK_MEDIA_NEXT_TRACK 0xB0
00117 #endif // VK_MEDIA_NEXT_TRACK
00118 #ifndef VK_MEDIA_PREV_TRACK
00119 #define VK_MEDIA_PREV_TRACK 0xB1
00120 #endif // VK_MEDIA_PREV_TRACK
00121 #ifndef VK_MEDIA_STOP
00122 #define VK_MEDIA_STOP   0xB2
00123 #endif // VK_MEDIA_STOP
00124 #ifndef VK_MEDIA_PLAY_PAUSE
00125 #define VK_MEDIA_PLAY_PAUSE 0xB3
00126 #endif // VK_MEDIA_PLAY_PAUSE
00127 
00128 static void initRawInput()
00129 {
00130 #ifdef WITH_INPUT_NDOF
00131 #define DEVICE_COUNT 2
00132 #else
00133 #define DEVICE_COUNT 1
00134 #endif
00135 
00136     RAWINPUTDEVICE devices[DEVICE_COUNT];
00137     memset(devices, 0, DEVICE_COUNT * sizeof(RAWINPUTDEVICE));
00138 
00139     // Initiates WM_INPUT messages from keyboard
00140     // That way GHOST can retrieve true keys
00141     devices[0].usUsagePage = 0x01;
00142     devices[0].usUsage = 0x06; /* http://msdn.microsoft.com/en-us/windows/hardware/gg487473.aspx */
00143 
00144 #ifdef WITH_INPUT_NDOF
00145     // multi-axis mouse (SpaceNavigator, etc.)
00146     devices[1].usUsagePage = 0x01;
00147     devices[1].usUsage = 0x08;
00148 #endif
00149 
00150     if (RegisterRawInputDevices(devices, DEVICE_COUNT, sizeof(RAWINPUTDEVICE)))
00151         ; // yay!
00152     else
00153         printf("could not register for RawInput: %d\n", (int)GetLastError());
00154 
00155 #undef DEVICE_COUNT
00156 }
00157 
00158 GHOST_SystemWin32::GHOST_SystemWin32()
00159 : m_hasPerformanceCounter(false), m_freq(0), m_start(0)
00160 {
00161     m_displayManager = new GHOST_DisplayManagerWin32 ();
00162     GHOST_ASSERT(m_displayManager, "GHOST_SystemWin32::GHOST_SystemWin32(): m_displayManager==0\n");
00163     m_displayManager->initialize();
00164 
00165     m_consoleStatus = 1;
00166 
00167     // Check if current keyboard layout uses AltGr and save keylayout ID for
00168     // specialized handling if keys like VK_OEM_*. I.e. french keylayout
00169     // generates VK_OEM_8 for their exclamation key (key left of right shift)
00170     this->handleKeyboardChange();
00171     // Require COM for GHOST_DropTargetWin32 created in GHOST_WindowWin32.
00172     OleInitialize(0);
00173 
00174 #ifdef WITH_INPUT_NDOF
00175     m_ndofManager = new GHOST_NDOFManagerWin32(*this);
00176 #endif
00177 }
00178 
00179 GHOST_SystemWin32::~GHOST_SystemWin32()
00180 {
00181     // Shutdown COM
00182     OleUninitialize();
00183     toggleConsole(1);
00184 }
00185 
00186 
00187 GHOST_TUns64 GHOST_SystemWin32::getMilliSeconds() const
00188 {
00189     // Hardware does not support high resolution timers. We will use GetTickCount instead then.
00190     if (!m_hasPerformanceCounter) {
00191         return ::GetTickCount();
00192     }
00193 
00194     // Retrieve current count
00195     __int64 count = 0;
00196     ::QueryPerformanceCounter((LARGE_INTEGER*)&count);
00197 
00198     // Calculate the time passed since system initialization.
00199     __int64 delta = 1000*(count-m_start);
00200 
00201     GHOST_TUns64 t = (GHOST_TUns64)(delta/m_freq);
00202     return t; 
00203 }
00204 
00205 
00206 GHOST_TUns8 GHOST_SystemWin32::getNumDisplays() const
00207 {
00208     GHOST_ASSERT(m_displayManager, "GHOST_SystemWin32::getNumDisplays(): m_displayManager==0\n");
00209     GHOST_TUns8 numDisplays;
00210     m_displayManager->getNumDisplays(numDisplays);
00211     return numDisplays;
00212 }
00213 
00214 
00215 void GHOST_SystemWin32::getMainDisplayDimensions(GHOST_TUns32& width, GHOST_TUns32& height) const
00216 {
00217     width = ::GetSystemMetrics(SM_CXSCREEN);
00218     height= ::GetSystemMetrics(SM_CYSCREEN);
00219 }
00220 
00221 
00222 GHOST_IWindow* GHOST_SystemWin32::createWindow(
00223     const STR_String& title, 
00224     GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, GHOST_TUns32 height,
00225     GHOST_TWindowState state, GHOST_TDrawingContextType type,
00226     bool stereoVisual, const GHOST_TUns16 numOfAASamples, const GHOST_TEmbedderWindowID parentWindow )
00227 {
00228     GHOST_Window* window = 0;
00229     window = new GHOST_WindowWin32 (this, title, left, top, width, height, state, type, stereoVisual, numOfAASamples, parentWindow);
00230     if (window) {
00231         if (window->getValid()) {
00232             // Store the pointer to the window
00233 //          if (state != GHOST_kWindowStateFullScreen) {
00234                 m_windowManager->addWindow(window);
00235                 m_windowManager->setActiveWindow(window);
00236 //          }
00237         }
00238         else {
00239 
00240             // Invalid parent window hwnd
00241             if (((GHOST_WindowWin32*)window)->getNextWindow() == NULL) {
00242                 delete window;
00243                 window = 0;
00244                 return window;
00245             }
00246 
00247             // An invalid window could be one that was used to test for AA
00248             window = ((GHOST_WindowWin32*)window)->getNextWindow();
00249             
00250             // If another window is found, let the wm know about that one, but not the old one
00251             if (window->getValid()) {
00252                 m_windowManager->addWindow(window);
00253             }
00254             else {
00255                 delete window;
00256                 window = 0;
00257             }
00258 
00259         }
00260     }
00261     return window;
00262 }
00263 
00264 
00265 bool GHOST_SystemWin32::processEvents(bool waitForEvent)
00266 {
00267     MSG msg;
00268     bool anyProcessed = false;
00269 
00270     do {
00271         GHOST_TimerManager* timerMgr = getTimerManager();
00272 
00273         if (waitForEvent && !::PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE)) {
00274 #if 1
00275 			::Sleep(1);
00276 #else
00277             GHOST_TUns64 next = timerMgr->nextFireTime();
00278             GHOST_TInt64 maxSleep = next - getMilliSeconds();
00279             
00280             if (next == GHOST_kFireTimeNever) {
00281                 ::WaitMessage();
00282             } else if(maxSleep >= 0.0) {
00283                 ::SetTimer(NULL, 0, maxSleep, NULL);
00284                 ::WaitMessage();
00285                 ::KillTimer(NULL, 0);
00286             }
00287 #endif
00288         }
00289 
00290         if (timerMgr->fireTimers(getMilliSeconds())) {
00291             anyProcessed = true;
00292         }
00293 
00294         // Process all the events waiting for us
00295         while (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE) != 0) {
00296             ::DispatchMessage(&msg);
00297             anyProcessed = true;
00298         }
00299     } while (waitForEvent && !anyProcessed);
00300 
00301     return anyProcessed;
00302 }
00303 
00304 
00305 GHOST_TSuccess GHOST_SystemWin32::getCursorPosition(GHOST_TInt32& x, GHOST_TInt32& y) const
00306 {
00307     POINT point;
00308     if(::GetCursorPos(&point)){
00309         x = point.x;
00310         y = point.y;
00311         return GHOST_kSuccess;
00312     }
00313     return GHOST_kFailure;
00314 }
00315 
00316 
00317 GHOST_TSuccess GHOST_SystemWin32::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y)
00318 {
00319     if (!GetActiveWindow())
00320         return GHOST_kFailure;
00321     return ::SetCursorPos(x, y) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
00322 }
00323 
00324 
00325 GHOST_TSuccess GHOST_SystemWin32::getModifierKeys(GHOST_ModifierKeys& keys) const
00326 {
00327     bool down = HIBYTE(::GetKeyState(VK_LSHIFT)) != 0;
00328     keys.set(GHOST_kModifierKeyLeftShift, down);
00329     down = HIBYTE(::GetKeyState(VK_RSHIFT)) != 0;
00330     keys.set(GHOST_kModifierKeyRightShift, down);
00331     
00332     down = HIBYTE(::GetKeyState(VK_LMENU)) != 0;
00333     keys.set(GHOST_kModifierKeyLeftAlt, down);
00334     down = HIBYTE(::GetKeyState(VK_RMENU)) != 0;
00335     keys.set(GHOST_kModifierKeyRightAlt, down);
00336     
00337     down = HIBYTE(::GetKeyState(VK_LCONTROL)) != 0;
00338     keys.set(GHOST_kModifierKeyLeftControl, down);
00339     down = HIBYTE(::GetKeyState(VK_RCONTROL)) != 0;
00340     keys.set(GHOST_kModifierKeyRightControl, down);
00341     
00342     bool lwindown = HIBYTE(::GetKeyState(VK_LWIN)) != 0;
00343     bool rwindown = HIBYTE(::GetKeyState(VK_RWIN)) != 0;
00344     if(lwindown || rwindown)
00345         keys.set(GHOST_kModifierKeyOS, true);
00346     else
00347         keys.set(GHOST_kModifierKeyOS, false);
00348     return GHOST_kSuccess;
00349 }
00350 
00351 
00352 GHOST_TSuccess GHOST_SystemWin32::getButtons(GHOST_Buttons& buttons) const
00353 {
00354     /* Check for swapped buttons (left-handed mouse buttons)
00355      * GetAsyncKeyState() will give back the state of the physical mouse buttons.
00356      */
00357     bool swapped = ::GetSystemMetrics(SM_SWAPBUTTON) == TRUE;
00358 
00359     bool down = HIBYTE(::GetKeyState(VK_LBUTTON)) != 0;
00360     buttons.set(swapped ? GHOST_kButtonMaskRight : GHOST_kButtonMaskLeft, down);
00361 
00362     down = HIBYTE(::GetKeyState(VK_MBUTTON)) != 0;
00363     buttons.set(GHOST_kButtonMaskMiddle, down);
00364 
00365     down = HIBYTE(::GetKeyState(VK_RBUTTON)) != 0;
00366     buttons.set(swapped ? GHOST_kButtonMaskLeft : GHOST_kButtonMaskRight, down);
00367     return GHOST_kSuccess;
00368 }
00369 
00370 
00371 GHOST_TSuccess GHOST_SystemWin32::init()
00372 {
00373     GHOST_TSuccess success = GHOST_System::init();
00374     
00375     /* Disable scaling on high DPI displays on Vista */
00376     HMODULE
00377     user32 = ::LoadLibraryA("user32.dll");
00378     typedef BOOL (WINAPI * LPFNSETPROCESSDPIAWARE)();
00379     LPFNSETPROCESSDPIAWARE SetProcessDPIAware =
00380         (LPFNSETPROCESSDPIAWARE)GetProcAddress(user32, "SetProcessDPIAware");
00381     if (SetProcessDPIAware)
00382         SetProcessDPIAware();
00383     FreeLibrary(user32);
00384     initRawInput();
00385 
00386     // Determine whether this system has a high frequency performance counter. */
00387     m_hasPerformanceCounter = ::QueryPerformanceFrequency((LARGE_INTEGER*)&m_freq) == TRUE;
00388     if (m_hasPerformanceCounter) {
00389         GHOST_PRINT("GHOST_SystemWin32::init: High Frequency Performance Timer available\n")
00390         ::QueryPerformanceCounter((LARGE_INTEGER*)&m_start);
00391     }
00392     else {
00393         GHOST_PRINT("GHOST_SystemWin32::init: High Frequency Performance Timer not available\n")
00394     }
00395 
00396     if (success) {
00397         WNDCLASS wc;
00398         wc.style= CS_HREDRAW | CS_VREDRAW;
00399         wc.lpfnWndProc= s_wndProc;
00400         wc.cbClsExtra= 0;
00401         wc.cbWndExtra= 0;
00402         wc.hInstance= ::GetModuleHandle(0);
00403         wc.hIcon = ::LoadIcon(wc.hInstance, "APPICON");
00404         
00405         if (!wc.hIcon) {
00406             ::LoadIcon(NULL, IDI_APPLICATION);
00407         }
00408         wc.hCursor = ::LoadCursor(0, IDC_ARROW);
00409         wc.hbrBackground= (HBRUSH)::GetStockObject(BLACK_BRUSH);
00410         wc.lpszMenuName = 0;
00411         wc.lpszClassName= GHOST_WindowWin32::getWindowClassName();
00412 
00413         // Use RegisterClassEx for setting small icon
00414         if (::RegisterClass(&wc) == 0) {
00415             success = GHOST_kFailure;
00416         }
00417     }
00418     
00419     return success;
00420 }
00421 
00422 
00423 GHOST_TSuccess GHOST_SystemWin32::exit()
00424 {
00425     return GHOST_System::exit();
00426 }
00427 
00428 GHOST_TKey GHOST_SystemWin32::hardKey(GHOST_IWindow *window, RAWINPUT const& raw, int * keyDown, char * vk)
00429 {
00430     GHOST_TKey key = GHOST_kKeyUnknown;
00431 
00432 
00433     if(!keyDown)
00434         return GHOST_kKeyUnknown;
00435 
00436 
00437     GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem();
00438 
00439     GHOST_ModifierKeys modifiers;
00440     system->retrieveModifierKeys(modifiers);
00441 
00442     // RI_KEY_BREAK doesn't work for sticky keys release, so we also
00443     // check for the up message
00444     unsigned int msg = raw.data.keyboard.Message;
00445     *keyDown = !(raw.data.keyboard.Flags & RI_KEY_BREAK) && msg != WM_KEYUP && msg != WM_SYSKEYUP;
00446 
00447     key = this->convertKey(window, raw.data.keyboard.VKey, raw.data.keyboard.MakeCode, (raw.data.keyboard.Flags&(RI_KEY_E1|RI_KEY_E0)));
00448     
00449     // extra handling of modifier keys: don't send repeats out from GHOST
00450     if(key >= GHOST_kKeyLeftShift && key <= GHOST_kKeyRightAlt)
00451     {
00452         bool changed = false;
00453         GHOST_TModifierKeyMask modifier;
00454         switch(key) {
00455             case GHOST_kKeyLeftShift:
00456                 {
00457                     changed = (modifiers.get(GHOST_kModifierKeyLeftShift) != (bool)*keyDown);
00458                     modifier = GHOST_kModifierKeyLeftShift;
00459                 }
00460                 break;
00461             case GHOST_kKeyRightShift:
00462                 {
00463                     changed = (modifiers.get(GHOST_kModifierKeyRightShift) != (bool)*keyDown);
00464                     modifier = GHOST_kModifierKeyRightShift;
00465                 }
00466                 break;
00467             case GHOST_kKeyLeftControl:
00468                 {
00469                     changed = (modifiers.get(GHOST_kModifierKeyLeftControl) != (bool)*keyDown);
00470                     modifier = GHOST_kModifierKeyLeftControl;
00471                 }
00472                 break;
00473             case GHOST_kKeyRightControl:
00474                 {
00475                     changed = (modifiers.get(GHOST_kModifierKeyRightControl) != (bool)*keyDown);
00476                     modifier = GHOST_kModifierKeyRightControl;
00477                 }
00478                 break;
00479             case GHOST_kKeyLeftAlt:
00480                 {
00481                     changed = (modifiers.get(GHOST_kModifierKeyLeftAlt) != (bool)*keyDown);
00482                     modifier = GHOST_kModifierKeyLeftAlt;
00483                 }
00484                 break;
00485             case GHOST_kKeyRightAlt:
00486                 {
00487                     changed = (modifiers.get(GHOST_kModifierKeyRightAlt) != (bool)*keyDown);
00488                     modifier = GHOST_kModifierKeyRightAlt;
00489                 }
00490                 break;
00491             default: break;
00492         }
00493         
00494         if(changed)
00495         {
00496             modifiers.set(modifier, (bool)*keyDown);
00497             system->storeModifierKeys(modifiers);
00498         }
00499         else
00500         {
00501             key = GHOST_kKeyUnknown;
00502         }
00503     }
00504     
00505 
00506     if(vk) *vk = raw.data.keyboard.VKey;
00507 
00508     return key;
00509 }
00510 
00512 // This function was added in response to bug [#25715]
00513 GHOST_TKey GHOST_SystemWin32::processSpecialKey(GHOST_IWindow *window, short vKey, short scanCode) const
00514 {
00515     GHOST_TKey key = GHOST_kKeyUnknown;
00516     switch(PRIMARYLANGID(m_langId)) {
00517         case LANG_FRENCH:
00518             if(vKey==VK_OEM_8) key = GHOST_kKeyF13; // oem key; used purely for shortcuts .
00519             break;
00520     }
00521 
00522     return key;
00523 }
00524 
00525 GHOST_TKey GHOST_SystemWin32::convertKey(GHOST_IWindow *window, short vKey, short scanCode, short extend) const
00526 {
00527     GHOST_TKey key;
00528 
00529     if ((vKey >= '0') && (vKey <= '9')) {
00530         // VK_0 thru VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39)
00531         key = (GHOST_TKey)(vKey - '0' + GHOST_kKey0);
00532     }
00533     else if ((vKey >= 'A') && (vKey <= 'Z')) {
00534         // VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A)
00535         key = (GHOST_TKey)(vKey - 'A' + GHOST_kKeyA);
00536     }
00537     else if ((vKey >= VK_F1) && (vKey <= VK_F24)) {
00538         key = (GHOST_TKey)(vKey - VK_F1 + GHOST_kKeyF1);
00539     }
00540     else {
00541         switch (vKey) {
00542         case VK_RETURN:
00543                 key = (extend)?GHOST_kKeyNumpadEnter : GHOST_kKeyEnter; break;
00544             
00545         case VK_BACK:     key = GHOST_kKeyBackSpace;        break;
00546         case VK_TAB:      key = GHOST_kKeyTab;              break;
00547         case VK_ESCAPE:   key = GHOST_kKeyEsc;              break;
00548         case VK_SPACE:    key = GHOST_kKeySpace;            break;
00549         
00550         case VK_INSERT:
00551         case VK_NUMPAD0:
00552             key = (extend) ? GHOST_kKeyInsert : GHOST_kKeyNumpad0;  break;
00553         case VK_END:
00554         case VK_NUMPAD1:        
00555             key = (extend) ? GHOST_kKeyEnd : GHOST_kKeyNumpad1; break;
00556         case VK_DOWN:
00557         case VK_NUMPAD2:
00558             key = (extend) ? GHOST_kKeyDownArrow : GHOST_kKeyNumpad2;   break;
00559         case VK_NEXT:
00560         case VK_NUMPAD3:
00561             key = (extend) ?  GHOST_kKeyDownPage : GHOST_kKeyNumpad3;   break;
00562         case VK_LEFT:
00563         case VK_NUMPAD4:
00564             key = (extend) ? GHOST_kKeyLeftArrow : GHOST_kKeyNumpad4;   break;
00565         case VK_CLEAR:
00566         case VK_NUMPAD5:
00567             key = (extend) ? GHOST_kKeyUnknown: GHOST_kKeyNumpad5;  break;
00568         case VK_RIGHT:
00569         case VK_NUMPAD6:
00570             key = (extend) ? GHOST_kKeyRightArrow : GHOST_kKeyNumpad6;  break;
00571         case VK_HOME:
00572         case VK_NUMPAD7:
00573             key = (extend) ? GHOST_kKeyHome : GHOST_kKeyNumpad7;    break;
00574         case VK_UP:
00575         case VK_NUMPAD8:
00576             key = (extend) ? GHOST_kKeyUpArrow : GHOST_kKeyNumpad8; break;
00577         case VK_PRIOR:
00578         case VK_NUMPAD9:
00579             key = (extend) ? GHOST_kKeyUpPage : GHOST_kKeyNumpad9;  break;
00580         case VK_DECIMAL:
00581         case VK_DELETE:
00582             key = (extend) ? GHOST_kKeyDelete : GHOST_kKeyNumpadPeriod; break;
00583 
00584         case VK_SNAPSHOT: key = GHOST_kKeyPrintScreen;      break;
00585         case VK_PAUSE:    key = GHOST_kKeyPause;            break;
00586         case VK_MULTIPLY: key = GHOST_kKeyNumpadAsterisk;   break;
00587         case VK_SUBTRACT: key = GHOST_kKeyNumpadMinus;      break;
00588         case VK_DIVIDE:   key = GHOST_kKeyNumpadSlash;      break;
00589         case VK_ADD:      key = GHOST_kKeyNumpadPlus;       break;
00590 
00591         case VK_SEMICOLON:      key = GHOST_kKeySemicolon;      break;
00592         case VK_EQUALS:         key = GHOST_kKeyEqual;          break;
00593         case VK_COMMA:          key = GHOST_kKeyComma;          break;
00594         case VK_MINUS:          key = GHOST_kKeyMinus;          break;
00595         case VK_PERIOD:         key = GHOST_kKeyPeriod;         break;
00596         case VK_SLASH:          key = GHOST_kKeySlash;          break;
00597         case VK_BACK_QUOTE:     key = GHOST_kKeyAccentGrave;    break;
00598         case VK_OPEN_BRACKET:   key = GHOST_kKeyLeftBracket;    break;
00599         case VK_BACK_SLASH:     key = GHOST_kKeyBackslash;      break;
00600         case VK_CLOSE_BRACKET:  key = GHOST_kKeyRightBracket;   break;
00601         case VK_QUOTE:          key = GHOST_kKeyQuote;          break;
00602         case VK_GR_LESS:        key = GHOST_kKeyGrLess;         break;
00603 
00604         case VK_SHIFT:
00605             key = (scanCode == 0x36)? GHOST_kKeyRightShift : GHOST_kKeyLeftShift;
00606             break;
00607         case VK_CONTROL:
00608             key = (extend)? GHOST_kKeyRightControl : GHOST_kKeyLeftControl;
00609             break;
00610         case VK_MENU:
00611             key = (extend)? GHOST_kKeyRightAlt : GHOST_kKeyLeftAlt;
00612             break;
00613         case VK_LWIN:
00614         case VK_RWIN:
00615             key = GHOST_kKeyOS;
00616             break;
00617         case VK_NUMLOCK: key = GHOST_kKeyNumLock; break;
00618         case VK_SCROLL: key = GHOST_kKeyScrollLock; break;
00619         case VK_CAPITAL: key = GHOST_kKeyCapsLock; break;
00620         case VK_OEM_8:
00621             key = ((GHOST_SystemWin32*)getSystem())->processSpecialKey(window, vKey, scanCode);
00622             break;
00623         case VK_MEDIA_PLAY_PAUSE: key = GHOST_kKeyMediaPlay; break;
00624         case VK_MEDIA_STOP: key = GHOST_kKeyMediaStop; break;
00625         case VK_MEDIA_PREV_TRACK: key = GHOST_kKeyMediaFirst; break;
00626         case VK_MEDIA_NEXT_TRACK: key = GHOST_kKeyMediaLast; break;
00627         default:
00628             key = GHOST_kKeyUnknown;
00629             break;
00630         }
00631     }
00632     
00633     return key;
00634 }
00635 
00636 GHOST_EventButton* GHOST_SystemWin32::processButtonEvent(GHOST_TEventType type, GHOST_IWindow *window, GHOST_TButtonMask mask)
00637 {
00638     return new GHOST_EventButton (getSystem()->getMilliSeconds(), type, window, mask);
00639 }
00640 
00641 
00642 GHOST_EventCursor* GHOST_SystemWin32::processCursorEvent(GHOST_TEventType type, GHOST_IWindow *Iwindow)
00643 {
00644     GHOST_TInt32 x_screen, y_screen;
00645     GHOST_SystemWin32 * system = ((GHOST_SystemWin32 * ) getSystem());
00646     GHOST_WindowWin32 * window = ( GHOST_WindowWin32 * ) Iwindow;
00647     
00648     system->getCursorPosition(x_screen, y_screen);
00649 
00650     if(window->getCursorGrabMode() != GHOST_kGrabDisable && window->getCursorGrabMode() != GHOST_kGrabNormal)
00651     {
00652         GHOST_TInt32 x_new= x_screen;
00653         GHOST_TInt32 y_new= y_screen;
00654         GHOST_TInt32 x_accum, y_accum;
00655         GHOST_Rect bounds;
00656 
00657         /* fallback to window bounds */
00658         if(window->getCursorGrabBounds(bounds)==GHOST_kFailure){
00659             window->getClientBounds(bounds);
00660         }
00661 
00662         /* could also clamp to screen bounds
00663          * wrap with a window outside the view will fail atm  */
00664 
00665         bounds.wrapPoint(x_new, y_new, 2); /* offset of one incase blender is at screen bounds */
00666 
00667         window->getCursorGrabAccum(x_accum, y_accum);
00668         if(x_new != x_screen|| y_new != y_screen) {
00669             /* when wrapping we don't need to add an event because the
00670              * setCursorPosition call will cause a new event after */
00671             system->setCursorPosition(x_new, y_new); /* wrap */
00672             window->setCursorGrabAccum(x_accum + (x_screen - x_new), y_accum + (y_screen - y_new));
00673         }else{
00674             return new GHOST_EventCursor(system->getMilliSeconds(),
00675                                          GHOST_kEventCursorMove,
00676                                          window,
00677                                          x_screen + x_accum,
00678                                          y_screen + y_accum
00679             );
00680         }
00681 
00682     }
00683     else {
00684         return new GHOST_EventCursor(system->getMilliSeconds(),
00685                                      GHOST_kEventCursorMove,
00686                                      window,
00687                                      x_screen,
00688                                      y_screen
00689         );
00690     }
00691     return NULL;
00692 }
00693 
00694 
00695 GHOST_EventWheel* GHOST_SystemWin32::processWheelEvent(GHOST_IWindow *window, WPARAM wParam, LPARAM lParam)
00696 {
00697     // short fwKeys = LOWORD(wParam);           // key flags
00698     int zDelta = (short) HIWORD(wParam);    // wheel rotation
00699     
00700     // zDelta /= WHEEL_DELTA;
00701     // temporary fix below: microsoft now has added more precision, making the above division not work
00702     if (zDelta <= 0 ) zDelta= -1; else zDelta= 1;   
00703     
00704     // short xPos = (short) LOWORD(lParam); // horizontal position of pointer
00705     // short yPos = (short) HIWORD(lParam); // vertical position of pointer
00706     return new GHOST_EventWheel (getSystem()->getMilliSeconds(), window, zDelta);
00707 }
00708 
00709 
00710 GHOST_EventKey* GHOST_SystemWin32::processKeyEvent(GHOST_IWindow *window, RAWINPUT const& raw)
00711 {
00712     int keyDown=0;
00713     char vk;
00714     GHOST_SystemWin32 * system = (GHOST_SystemWin32 *)getSystem();
00715     GHOST_TKey key = system->hardKey(window, raw, &keyDown, &vk);
00716     GHOST_EventKey* event;
00717 
00718     if (key != GHOST_kKeyUnknown) {
00719         char utf8_char[6] = {0} ;
00720 
00721         wchar_t utf16[2]={0};
00722         BYTE state[256];
00723         GetKeyboardState((PBYTE)state);  
00724 
00725         if(ToUnicodeEx(vk, 0, state, utf16, 2, 0, system->m_keylayout))
00726             WideCharToMultiByte(CP_UTF8, 0, 
00727                                     (wchar_t*)utf16, 1,
00728                                     (LPSTR) utf8_char, 5,
00729                                     NULL,NULL); else *utf8_char = 0;
00730 
00731         if(!keyDown) utf8_char[0] = '\0';
00732         
00733         event = new GHOST_EventKey(system->getMilliSeconds(), keyDown ? GHOST_kEventKeyDown: GHOST_kEventKeyUp, window, key, (*utf8_char & 0x80)?'?':*utf8_char, utf8_char);
00734         
00735 #ifdef GHOST_DEBUG
00736         std::cout << ascii << std::endl;
00737 #endif
00738     }
00739     else {
00740         event = 0;
00741     }
00742     return event;
00743 }
00744 
00745 
00746 GHOST_Event* GHOST_SystemWin32::processWindowEvent(GHOST_TEventType type, GHOST_IWindow* window)
00747 {
00748     GHOST_System* system = (GHOST_System*)getSystem();
00749 
00750     if (type == GHOST_kEventWindowActivate) {
00751         system->getWindowManager()->setActiveWindow(window);
00752     }
00753 
00754     return new GHOST_Event(system->getMilliSeconds(), type, window);
00755 }
00756 
00757 GHOST_TSuccess GHOST_SystemWin32::pushDragDropEvent(GHOST_TEventType eventType, 
00758                                                     GHOST_TDragnDropTypes draggedObjectType,
00759                                                     GHOST_IWindow* window,
00760                                                     int mouseX, int mouseY,
00761                                                     void* data)
00762 {
00763     GHOST_SystemWin32* system = ((GHOST_SystemWin32*)getSystem());
00764     return system->pushEvent(new GHOST_EventDragnDrop(system->getMilliSeconds(),
00765                                                       eventType,
00766                                                       draggedObjectType,
00767                                                       window,mouseX,mouseY,data)
00768             );
00769 }
00770 
00771 void GHOST_SystemWin32::processMinMaxInfo(MINMAXINFO * minmax)
00772 {
00773     minmax->ptMinTrackSize.x=320;
00774     minmax->ptMinTrackSize.y=240;
00775 }
00776 
00777 #ifdef WITH_INPUT_NDOF
00778 bool GHOST_SystemWin32::processNDOF(RAWINPUT const& raw)
00779 {
00780     bool eventSent = false;
00781     GHOST_TUns64 now = getMilliSeconds();
00782 
00783     static bool firstEvent = true;
00784     if (firstEvent) { // determine exactly which device is plugged in
00785         RID_DEVICE_INFO info;
00786         unsigned infoSize = sizeof(RID_DEVICE_INFO);
00787         info.cbSize = infoSize;
00788 
00789         GetRawInputDeviceInfo(raw.header.hDevice, RIDI_DEVICEINFO, &info, &infoSize);
00790         if (info.dwType == RIM_TYPEHID)
00791             m_ndofManager->setDevice(info.hid.dwVendorId, info.hid.dwProductId);
00792         else
00793             puts("<!> not a HID device... mouse/kb perhaps?");
00794 
00795         firstEvent = false;
00796     }
00797 
00798     // The NDOF manager sends button changes immediately, and *pretends* to
00799     // send motion. Mark as 'sent' so motion will always get dispatched.
00800     eventSent = true;
00801 
00802 #ifdef _MSC_VER
00803     // using Microsoft compiler & header files
00804     // they invented the RawInput API, so this version is (probably) correct
00805     BYTE const* data = raw.data.hid.bRawData;
00806     // struct RAWHID {
00807     // DWORD dwSizeHid;
00808     // DWORD dwCount;
00809     // BYTE  bRawData[1];
00810     // };
00811 #else
00812     // MinGW's definition (below) doesn't agree, so we need a slight
00813     // workaround until it's fixed
00814     BYTE const* data = &raw.data.hid.bRawData;
00815     // struct RAWHID {
00816     // DWORD dwSizeHid;
00817     // DWORD dwCount;
00818     // BYTE bRawData; // <== isn't this s'posed to be a BYTE*?
00819     // };
00820 #endif
00821 
00822     BYTE packetType = data[0];
00823     switch (packetType)
00824     {
00825         case 1: // translation
00826         {
00827             short* axis = (short*)(data + 1);
00828             // massage into blender view coords (same goes for rotation)
00829             short t[3] = {axis[0], -axis[2], axis[1]};
00830             m_ndofManager->updateTranslation(t, now);
00831 
00832             if (raw.data.hid.dwSizeHid == 13)
00833             { // this report also includes rotation
00834                 short r[3] = {-axis[3], axis[5], -axis[4]};
00835                 m_ndofManager->updateRotation(r, now);
00836 
00837                 // I've never gotten one of these, has anyone else?
00838                 puts("ndof: combined T + R");
00839             }
00840             break;
00841         }
00842         case 2: // rotation
00843         {
00844             short* axis = (short*)(data + 1);
00845             short r[3] = {-axis[0], axis[2], -axis[1]};
00846             m_ndofManager->updateRotation(r, now);
00847             break;
00848         }
00849         case 3: // buttons
00850         {
00851             int button_bits;
00852             memcpy(&button_bits, data + 1, sizeof(button_bits));
00853             m_ndofManager->updateButtons(button_bits, now);
00854             break;
00855         }
00856     }
00857     return eventSent;
00858 }
00859 #endif // WITH_INPUT_NDOF
00860 
00861 LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
00862 {
00863     GHOST_Event* event = 0;
00864     bool eventHandled = false;
00865 
00866     LRESULT lResult = 0;
00867     GHOST_SystemWin32* system = ((GHOST_SystemWin32*)getSystem());
00868     GHOST_ASSERT(system, "GHOST_SystemWin32::s_wndProc(): system not initialized")
00869 
00870     if (hwnd) {
00871         GHOST_WindowWin32* window = (GHOST_WindowWin32*)::GetWindowLong(hwnd, GWL_USERDATA);
00872         if (window) {
00873             switch (msg) {
00874                 // we need to check if new key layout has AltGr
00875                 case WM_INPUTLANGCHANGE:
00876                     system->handleKeyboardChange();
00877                     break;
00879                 // Keyboard events, processed
00881                 case WM_INPUT:
00882                 {
00883                     // check WM_INPUT from input sink when ghost window is not in the foreground
00884                     if (wParam == RIM_INPUTSINK) {
00885                         if (GetFocus() != hwnd) // WM_INPUT message not for this window
00886                             return 0;
00887                     } //else wParam == RIM_INPUT
00888 
00889                     RAWINPUT raw;
00890                     RAWINPUT* raw_ptr = &raw;
00891                     UINT rawSize = sizeof(RAWINPUT);
00892 
00893                     GetRawInputData((HRAWINPUT)lParam, RID_INPUT, raw_ptr, &rawSize, sizeof(RAWINPUTHEADER));
00894 
00895                     switch (raw.header.dwType)
00896                     {
00897                     case RIM_TYPEKEYBOARD:
00898                         event = processKeyEvent(window, raw);
00899                         if (!event) {
00900                             GHOST_PRINT("GHOST_SystemWin32::wndProc: key event ")
00901                             GHOST_PRINT(msg)
00902                             GHOST_PRINT(" key ignored\n")
00903                         }
00904                         break;
00905 #ifdef WITH_INPUT_NDOF
00906                     case RIM_TYPEHID:
00907                         if (system->processNDOF(raw))
00908                             eventHandled = true;
00909                         break;
00910 #endif
00911                     }
00912                 break;
00913                 }
00915                 // Keyboard events, ignored
00917                 case WM_KEYDOWN:
00918                 case WM_SYSKEYDOWN:
00919                 case WM_KEYUP:
00920                 case WM_SYSKEYUP:
00921                     /* These functions were replaced by WM_INPUT*/
00922                 case WM_CHAR:
00923                     /* The WM_CHAR message is posted to the window with the keyboard focus when
00924                      * a WM_KEYDOWN message is translated by the TranslateMessage function. WM_CHAR
00925                      * contains the character code of the key that was pressed.
00926                      */
00927                 case WM_DEADCHAR:
00928                     /* The WM_DEADCHAR message is posted to the window with the keyboard focus when a
00929                      * WM_KEYUP message is translated by the TranslateMessage function. WM_DEADCHAR 
00930                      * specifies a character code generated by a dead key. A dead key is a key that 
00931                      * generates a character, such as the umlaut (double-dot), that is combined with 
00932                      * another character to form a composite character. For example, the umlaut-O 
00933                      * character (Ö) is generated by typing the dead key for the umlaut character, and
00934                      * then typing the O key.
00935                      */
00936                     break;
00937                 case WM_SYSDEADCHAR:
00938                     /* The WM_SYSDEADCHAR message is sent to the window with the keyboard focus when 
00939                      * a WM_SYSKEYDOWN message is translated by the TranslateMessage function. 
00940                      * WM_SYSDEADCHAR specifies the character code of a system dead key - that is, 
00941                      * a dead key that is pressed while holding down the alt key. 
00942                      */
00943                 case WM_SYSCHAR:
00944                     /* The WM_SYSCHAR message is sent to the window with the keyboard focus when 
00945                      * a WM_SYSCHAR message is translated by the TranslateMessage function. 
00946                      * WM_SYSCHAR specifies the character code of a dead key - that is, 
00947                      * a dead key that is pressed while holding down the alt key.
00948                      * To prevent the sound, DefWindowProc must be avoided by return
00949                      */
00950                     break;
00951                 case WM_SYSCOMMAND:
00952                     /* The WM_SYSCHAR message is sent to the window when system commands such as 
00953                      * maximize, minimize  or close the window are triggered. Also it is sent when ALT 
00954                      * button is press for menu. To prevent this we must return preventing DefWindowProc.
00955                      */
00956                     if(wParam==SC_KEYMENU) return 0;
00957                     break;
00959                 // Tablet events, processed
00961                 case WT_PACKET:
00962                     ((GHOST_WindowWin32*)window)->processWin32TabletEvent(wParam, lParam);
00963                     break;
00964                 case WT_CSRCHANGE:
00965                 case WT_PROXIMITY:
00966                     ((GHOST_WindowWin32*)window)->processWin32TabletInitEvent();
00967                     break;
00969                 // Mouse events, processed
00971                 case WM_LBUTTONDOWN:
00972                     window->registerMouseClickEvent(0);
00973                     event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskLeft);
00974                     break;
00975                 case WM_MBUTTONDOWN:
00976                     window->registerMouseClickEvent(0);
00977                     event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskMiddle);
00978                     break;
00979                 case WM_RBUTTONDOWN:
00980                     window->registerMouseClickEvent(0);
00981                     event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskRight);
00982                     break;
00983                 case WM_XBUTTONDOWN:
00984                     window->registerMouseClickEvent(0);
00985                     if ((short) HIWORD(wParam) == XBUTTON1){
00986                         event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskButton4);
00987                     }else if((short) HIWORD(wParam) == XBUTTON2){
00988                         event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskButton5);
00989                     }
00990                     break;
00991                 case WM_LBUTTONUP:
00992                     window->registerMouseClickEvent(1);
00993                     event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskLeft);
00994                     break;
00995                 case WM_MBUTTONUP:
00996                     window->registerMouseClickEvent(1);
00997                     event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskMiddle);
00998                     break;
00999                 case WM_RBUTTONUP:
01000                     window->registerMouseClickEvent(1);
01001                     event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskRight);
01002                     break;
01003                 case WM_XBUTTONUP:
01004                     window->registerMouseClickEvent(1);
01005                     if ((short) HIWORD(wParam) == XBUTTON1){
01006                         event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskButton4);
01007                     }else if((short) HIWORD(wParam) == XBUTTON2){
01008                         event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskButton5);
01009                     }
01010                     break;
01011                 case WM_MOUSEMOVE:
01012                     event = processCursorEvent(GHOST_kEventCursorMove, window);
01013                     break;
01014                 case WM_MOUSEWHEEL:
01015                     /* The WM_MOUSEWHEEL message is sent to the focus window 
01016                      * when the mouse wheel is rotated. The DefWindowProc 
01017                      * function propagates the message to the window's parent.
01018                      * There should be no internal forwarding of the message, 
01019                      * since DefWindowProc propagates it up the parent chain 
01020                      * until it finds a window that processes it.
01021                      */
01022                     event = processWheelEvent(window, wParam, lParam);
01023                     break;
01024                 case WM_SETCURSOR:
01025                     /* The WM_SETCURSOR message is sent to a window if the mouse causes the cursor
01026                      * to move within a window and mouse input is not captured.
01027                      * This means we have to set the cursor shape every time the mouse moves!
01028                      * The DefWindowProc function uses this message to set the cursor to an 
01029                      * arrow if it is not in the client area.
01030                      */
01031                     if (LOWORD(lParam) == HTCLIENT) {
01032                         // Load the current cursor
01033                         window->loadCursor(window->getCursorVisibility(), window->getCursorShape());
01034                         // Bypass call to DefWindowProc
01035                         return 0;
01036                     } 
01037                     else {
01038                         // Outside of client area show standard cursor
01039                         window->loadCursor(true, GHOST_kStandardCursorDefault);
01040                     }
01041                     break;
01042 
01044                 // Mouse events, ignored
01046                 case WM_NCMOUSEMOVE:
01047                     /* The WM_NCMOUSEMOVE message is posted to a window when the cursor is moved 
01048                      * within the nonclient area of the window. This message is posted to the window 
01049                      * that contains the cursor. If a window has captured the mouse, this message is not posted.
01050                      */
01051                 case WM_NCHITTEST:
01052                     /* The WM_NCHITTEST message is sent to a window when the cursor moves, or 
01053                      * when a mouse button is pressed or released. If the mouse is not captured, 
01054                      * the message is sent to the window beneath the cursor. Otherwise, the message 
01055                      * is sent to the window that has captured the mouse. 
01056                      */
01057                     break;
01058 
01060                 // Window events, processed
01062                 case WM_CLOSE:
01063                     /* The WM_CLOSE message is sent as a signal that a window or an application should terminate. */
01064                     event = processWindowEvent(GHOST_kEventWindowClose, window);
01065                     break;
01066                 case WM_ACTIVATE:
01067                     /* The WM_ACTIVATE message is sent to both the window being activated and the window being 
01068                      * deactivated. If the windows use the same input queue, the message is sent synchronously, 
01069                      * first to the window procedure of the top-level window being deactivated, then to the window
01070                      * procedure of the top-level window being activated. If the windows use different input queues,
01071                      * the message is sent asynchronously, so the window is activated immediately. 
01072                      */
01073                     {
01074                     GHOST_ModifierKeys modifiers;
01075                     modifiers.clear();
01076                     system->storeModifierKeys(modifiers);
01077                     event = processWindowEvent(LOWORD(wParam) ? GHOST_kEventWindowActivate : GHOST_kEventWindowDeactivate, window);
01078                     /* WARNING: Let DefWindowProc handle WM_ACTIVATE, otherwise WM_MOUSEWHEEL
01079                     will not be dispatched to OUR active window if we minimize one of OUR windows. */
01080                     lResult = ::DefWindowProc(hwnd, msg, wParam, lParam);
01081                     break;
01082                     }
01083                 case WM_PAINT:
01084                     /* An application sends the WM_PAINT message when the system or another application 
01085                      * makes a request to paint a portion of an application's window. The message is sent
01086                      * when the UpdateWindow or RedrawWindow function is called, or by the DispatchMessage 
01087                      * function when the application obtains a WM_PAINT message by using the GetMessage or 
01088                      * PeekMessage function. 
01089                      */
01090                     event = processWindowEvent(GHOST_kEventWindowUpdate, window);
01091                     ::ValidateRect(hwnd, NULL);
01092                     break;
01093                 case WM_GETMINMAXINFO:
01094                     /* The WM_GETMINMAXINFO message is sent to a window when the size or 
01095                      * position of the window is about to change. An application can use 
01096                      * this message to override the window's default maximized size and 
01097                      * position, or its default minimum or maximum tracking size. 
01098                      */
01099                     processMinMaxInfo((MINMAXINFO *) lParam);
01100                     /* Let DefWindowProc handle it. */
01101                     break;
01102                 case WM_SIZE:
01103                     /* The WM_SIZE message is sent to a window after its size has changed.
01104                      * The WM_SIZE and WM_MOVE messages are not sent if an application handles the 
01105                      * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient
01106                      * to perform any move or size change processing during the WM_WINDOWPOSCHANGED 
01107                      * message without calling DefWindowProc.
01108                      */
01109                     event = processWindowEvent(GHOST_kEventWindowSize, window);
01110                     break;
01111                 case WM_CAPTURECHANGED:
01112                     window->lostMouseCapture();
01113                     break;
01114                 case WM_MOVING:
01115                     /* The WM_MOVING message is sent to a window that the user is moving. By processing 
01116                      * this message, an application can monitor the size and position of the drag rectangle
01117                      * and, if needed, change its size or position.
01118                      */
01119                 case WM_MOVE:
01120                     /* The WM_SIZE and WM_MOVE messages are not sent if an application handles the 
01121                      * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient
01122                      * to perform any move or size change processing during the WM_WINDOWPOSCHANGED 
01123                      * message without calling DefWindowProc. 
01124                      */
01125                     event = processWindowEvent(GHOST_kEventWindowMove, window);
01126                     break;
01128                 // Window events, ignored
01130                 case WM_WINDOWPOSCHANGED:
01131                     /* The WM_WINDOWPOSCHANGED message is sent to a window whose size, position, or place
01132                      * in the Z order has changed as a result of a call to the SetWindowPos function or 
01133                      * another window-management function.
01134                      * The WM_SIZE and WM_MOVE messages are not sent if an application handles the 
01135                      * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient
01136                      * to perform any move or size change processing during the WM_WINDOWPOSCHANGED 
01137                      * message without calling DefWindowProc.
01138                      */
01139                 case WM_ERASEBKGND:
01140                     /* An application sends the WM_ERASEBKGND message when the window background must be 
01141                      * erased (for example, when a window is resized). The message is sent to prepare an 
01142                      * invalidated portion of a window for painting. 
01143                      */
01144                 case WM_NCPAINT:
01145                     /* An application sends the WM_NCPAINT message to a window when its frame must be painted. */
01146                 case WM_NCACTIVATE:
01147                     /* The WM_NCACTIVATE message is sent to a window when its nonclient area needs to be changed 
01148                      * to indicate an active or inactive state. 
01149                      */
01150                 case WM_DESTROY:
01151                     /* The WM_DESTROY message is sent when a window is being destroyed. It is sent to the window 
01152                      * procedure of the window being destroyed after the window is removed from the screen. 
01153                      * This message is sent first to the window being destroyed and then to the child windows 
01154                      * (if any) as they are destroyed. During the processing of the message, it can be assumed 
01155                      * that all child windows still exist. 
01156                      */
01157                 case WM_NCDESTROY:
01158                     /* The WM_NCDESTROY message informs a window that its nonclient area is being destroyed. The 
01159                      * DestroyWindow function sends the WM_NCDESTROY message to the window following the WM_DESTROY
01160                      * message. WM_DESTROY is used to free the allocated memory object associated with the window. 
01161                      */
01162                     break;
01163                 case WM_KILLFOCUS:
01164                     /* The WM_KILLFOCUS message is sent to a window immediately before it loses the keyboard focus. 
01165                      * We want to prevent this if a window is still active and it loses focus to nowhere*/
01166                     if(!wParam && hwnd==GetActiveWindow())
01167                         SetFocus(hwnd);
01168                 case WM_SHOWWINDOW:
01169                     /* The WM_SHOWWINDOW message is sent to a window when the window is about to be hidden or shown. */
01170                 case WM_WINDOWPOSCHANGING:
01171                     /* The WM_WINDOWPOSCHANGING message is sent to a window whose size, position, or place in 
01172                      * the Z order is about to change as a result of a call to the SetWindowPos function or 
01173                      * another window-management function. 
01174                      */
01175                 case WM_SETFOCUS:
01176                     /* The WM_SETFOCUS message is sent to a window after it has gained the keyboard focus. */
01177                 case WM_ENTERSIZEMOVE:
01178                     /* The WM_ENTERSIZEMOVE message is sent one time to a window after it enters the moving 
01179                      * or sizing modal loop. The window enters the moving or sizing modal loop when the user 
01180                      * clicks the window's title bar or sizing border, or when the window passes the 
01181                      * WM_SYSCOMMAND message to the DefWindowProc function and the wParam parameter of the 
01182                      * message specifies the SC_MOVE or SC_SIZE value. The operation is complete when 
01183                      * DefWindowProc returns. 
01184                      */
01185                     break;
01186                     
01188                 // Other events
01190                 case WM_GETTEXT:
01191                     /* An application sends a WM_GETTEXT message to copy the text that 
01192                      * corresponds to a window into a buffer provided by the caller. 
01193                      */
01194                 case WM_ACTIVATEAPP:
01195                     /* The WM_ACTIVATEAPP message is sent when a window belonging to a 
01196                      * different application than the active window is about to be activated.
01197                      * The message is sent to the application whose window is being activated
01198                      * and to the application whose window is being deactivated. 
01199                      */
01200                 case WM_TIMER:
01201                     /* The WIN32 docs say:
01202                      * The WM_TIMER message is posted to the installing thread's message queue
01203                      * when a timer expires. You can process the message by providing a WM_TIMER
01204                      * case in the window procedure. Otherwise, the default window procedure will
01205                      * call the TimerProc callback function specified in the call to the SetTimer
01206                      * function used to install the timer. 
01207                      *
01208                      * In GHOST, we let DefWindowProc call the timer callback.
01209                      */
01210                     break;
01211             }
01212         }
01213         else {
01214             // Event found for a window before the pointer to the class has been set.
01215             GHOST_PRINT("GHOST_SystemWin32::wndProc: GHOST window event before creation\n")
01216             /* These are events we typically miss at this point:
01217                WM_GETMINMAXINFO 0x24
01218                WM_NCCREATE          0x81
01219                WM_NCCALCSIZE        0x83
01220                WM_CREATE            0x01
01221                We let DefWindowProc do the work.
01222             */
01223         }
01224     }
01225     else {
01226         // Events without valid hwnd
01227         GHOST_PRINT("GHOST_SystemWin32::wndProc: event without window\n")
01228     }
01229 
01230     if (event) {
01231         system->pushEvent(event);
01232         eventHandled = true;
01233     }
01234 
01235     if (!eventHandled)
01236         lResult = ::DefWindowProc(hwnd, msg, wParam, lParam);
01237 
01238     return lResult;
01239 }
01240 
01241 GHOST_TUns8* GHOST_SystemWin32::getClipboard(bool selection) const 
01242 {
01243     wchar_t *buffer;
01244     char *temp_buff;
01245     
01246     if ( IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(NULL) ) {
01247         size_t len = 0;
01248         HANDLE hData = GetClipboardData( CF_UNICODETEXT );
01249         if (hData == NULL) {
01250             CloseClipboard();
01251             return NULL;
01252         }
01253         buffer = (wchar_t*)GlobalLock( hData );
01254         if (!buffer) {
01255             CloseClipboard();
01256             return NULL;
01257         }
01258         
01259         len = WideCharToMultiByte(CP_UTF8, 0, buffer, -1, NULL, 0, NULL, NULL);
01260         temp_buff = (char*) malloc(len);
01261         WideCharToMultiByte(CP_UTF8, 0, buffer, -1, temp_buff, len, NULL, NULL);
01262         
01263         /* Buffer mustn't be accessed after CloseClipboard
01264            it would like accessing free-d memory */
01265         GlobalUnlock( hData );
01266         CloseClipboard();
01267         
01268         return (GHOST_TUns8*)temp_buff;
01269     } else {
01270         return NULL;
01271     }
01272 }
01273 
01274 void GHOST_SystemWin32::putClipboard(GHOST_TInt8 *buffer, bool selection) const
01275 {
01276     if(selection) {return;} // for copying the selection, used on X11
01277 
01278     if (OpenClipboard(NULL)) {
01279         HLOCAL clipbuffer;
01280         wchar_t *data;
01281         
01282         if (buffer) {
01283             EmptyClipboard();
01284             
01285             int wlen = MultiByteToWideChar(CP_UTF8, 0, buffer, -1, NULL, 0);
01286             
01287             clipbuffer = LocalAlloc(LMEM_FIXED, wlen * sizeof(wchar_t));
01288             data = (wchar_t*)GlobalLock(clipbuffer);
01289             
01290             MultiByteToWideChar(CP_UTF8, 0, buffer, -1, data, wlen);
01291             
01292             LocalUnlock(clipbuffer);
01293             SetClipboardData(CF_UNICODETEXT,clipbuffer);
01294         }
01295         CloseClipboard();
01296     } else {
01297         return;
01298     }
01299 }
01300 
01301 int GHOST_SystemWin32::toggleConsole(int action)
01302 {
01303     switch(action)
01304     {
01305         case 3: //hide if no console
01306             {
01307                 DWORD sp = GetCurrentProcessId();
01308                 HANDLE ptree = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
01309                 PROCESSENTRY32 e = {0}; e.dwSize = sizeof(PROCESSENTRY32);
01310                 
01311                 if( Process32First(ptree, &e)) {
01312                     do { //Searches for Blender's PROCESSENTRY32
01313                             if (e.th32ProcessID == sp) {
01314                                 sp = e.th32ParentProcessID;
01315                                 Process32First(ptree, &e);
01316                                     do { //Got parent id, searches for its PROCESSENTRY32
01317                                         if (e.th32ProcessID == sp) {
01318                                             if(strcmp("explorer.exe",e.szExeFile)==0)
01319                                             { //If explorer, hide cmd
01320                                                 ShowWindow(GetConsoleWindow(),SW_HIDE);
01321                                                 m_consoleStatus = 0;
01322                                             }
01323                                             break;
01324                                         }
01325 
01326                                     } while( Process32Next(ptree, &e));
01327                                 break;
01328                             }
01329                     } while( Process32Next(ptree, &e));
01330                 }
01331 
01332                 CloseHandle(ptree);
01333                 break;
01334             }
01335         case 0: //hide
01336             ShowWindow(GetConsoleWindow(),SW_HIDE);
01337             m_consoleStatus = 0;
01338             break;
01339         case 1: //show
01340             ShowWindow(GetConsoleWindow(),SW_SHOW);
01341             m_consoleStatus = 1;
01342             break;
01343         case 2: //toggle
01344             ShowWindow(GetConsoleWindow(),m_consoleStatus?SW_HIDE:SW_SHOW);
01345             m_consoleStatus=!m_consoleStatus;
01346             break;
01347 
01348     };
01349 
01350 
01351     return m_consoleStatus;
01352 }