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