Blender V2.61 - r43446
|
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 }