3 * ***** BEGIN GPL LICENSE BLOCK *****
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
20 * All rights reserved.
22 * The Original Code is: all of this file.
24 * Contributor(s): none yet.
26 * ***** END GPL LICENSE BLOCK *****
32 * Copyright (C) 2001 NaN Technologies B.V.
33 * @author Maarten Gribnau
39 #include "GHOST_SystemWin32.h"
40 #include "GHOST_EventDragnDrop.h"
42 #define WIN32_LEAN_AND_MEAN
46 #define _WIN32_IE 0x0501
50 // win64 doesn't define GWL_USERDATA
53 #define GWL_USERDATA GWLP_USERDATA
54 #define GWL_WNDPROC GWLP_WNDPROC
59 * According to the docs the mouse wheel message is supported from windows 98
60 * upwards. Leaving WINVER at default value, the WM_MOUSEWHEEL message and the
61 * wheel detent value are undefined.
64 #define WM_MOUSEWHEEL 0x020A
65 #endif // WM_MOUSEWHEEL
67 #define WHEEL_DELTA 120 /* Value for rolling one detent, (old convention! MS changed it) */
71 * Defines for mouse buttons 4 and 5 aka xbutton1 and xbutton2.
72 * MSDN: Declared in Winuser.h, include Windows.h
73 * This does not seem to work with MinGW so we define our own here.
76 #define XBUTTON1 0x0001
79 #define XBUTTON2 0x0002
82 #define WM_XBUTTONUP 524
83 #endif // WM_XBUTTONUP
84 #ifndef WM_XBUTTONDOWN
85 #define WM_XBUTTONDOWN 523
86 #endif // WM_XBUTTONDOWN
88 #include "GHOST_Debug.h"
89 #include "GHOST_DisplayManagerWin32.h"
90 #include "GHOST_EventButton.h"
91 #include "GHOST_EventCursor.h"
92 #include "GHOST_EventKey.h"
93 #include "GHOST_EventWheel.h"
94 #include "GHOST_EventNDOF.h"
95 #include "GHOST_TimerTask.h"
96 #include "GHOST_TimerManager.h"
97 #include "GHOST_WindowManager.h"
98 #include "GHOST_WindowWin32.h"
99 #include "GHOST_NDOFManager.h"
101 // Key code values not found in winuser.h
103 #define VK_MINUS 0xBD
106 #define VK_SEMICOLON 0xBA
107 #endif // VK_SEMICOLON
109 #define VK_PERIOD 0xBE
112 #define VK_COMMA 0xBC
115 #define VK_QUOTE 0xDE
117 #ifndef VK_BACK_QUOTE
118 #define VK_BACK_QUOTE 0xC0
119 #endif // VK_BACK_QUOTE
121 #define VK_SLASH 0xBF
123 #ifndef VK_BACK_SLASH
124 #define VK_BACK_SLASH 0xDC
125 #endif // VK_BACK_SLASH
127 #define VK_EQUALS 0xBB
129 #ifndef VK_OPEN_BRACKET
130 #define VK_OPEN_BRACKET 0xDB
131 #endif // VK_OPEN_BRACKET
132 #ifndef VK_CLOSE_BRACKET
133 #define VK_CLOSE_BRACKET 0xDD
134 #endif // VK_CLOSE_BRACKET
136 #define VK_GR_LESS 0xE2
140 GHOST_SystemWin32::GHOST_SystemWin32()
141 : m_hasPerformanceCounter(false), m_freq(0), m_start(0)
143 m_displayManager = new GHOST_DisplayManagerWin32 ();
144 GHOST_ASSERT(m_displayManager, "GHOST_SystemWin32::GHOST_SystemWin32(): m_displayManager==0\n");
145 m_displayManager->initialize();
147 // Check if current keyboard layout uses AltGr
148 this->keyboardAltGr();
150 // Require COM for GHOST_DropTargetWin32 created in GHOST_WindowWin32.
154 GHOST_SystemWin32::~GHOST_SystemWin32()
161 GHOST_TUns64 GHOST_SystemWin32::getMilliSeconds() const
163 // Hardware does not support high resolution timers. We will use GetTickCount instead then.
164 if (!m_hasPerformanceCounter) {
165 return ::GetTickCount();
168 // Retrieve current count
170 ::QueryPerformanceCounter((LARGE_INTEGER*)&count);
172 // Calculate the time passed since system initialization.
173 __int64 delta = 1000*(count-m_start);
175 GHOST_TUns64 t = (GHOST_TUns64)(delta/m_freq);
180 GHOST_TUns8 GHOST_SystemWin32::getNumDisplays() const
182 GHOST_ASSERT(m_displayManager, "GHOST_SystemWin32::getNumDisplays(): m_displayManager==0\n");
183 GHOST_TUns8 numDisplays;
184 m_displayManager->getNumDisplays(numDisplays);
189 void GHOST_SystemWin32::getMainDisplayDimensions(GHOST_TUns32& width, GHOST_TUns32& height) const
191 width = ::GetSystemMetrics(SM_CXSCREEN);
192 height= ::GetSystemMetrics(SM_CYSCREEN);
196 GHOST_IWindow* GHOST_SystemWin32::createWindow(
197 const STR_String& title,
198 GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, GHOST_TUns32 height,
199 GHOST_TWindowState state, GHOST_TDrawingContextType type,
200 bool stereoVisual, const GHOST_TUns16 numOfAASamples, const GHOST_TEmbedderWindowID parentWindow )
202 GHOST_Window* window = 0;
203 window = new GHOST_WindowWin32 (this, title, left, top, width, height, state, type, stereoVisual, numOfAASamples);
205 if (window->getValid()) {
206 // Store the pointer to the window
207 // if (state != GHOST_kWindowStateFullScreen) {
208 m_windowManager->addWindow(window);
212 // An invalid window could be one that was used to test for AA
213 window = ((GHOST_WindowWin32*)window)->getNextWindow();
215 // If another window is found, let the wm know about that one, but not the old one
216 if (window->getValid()) {
217 m_windowManager->addWindow(window);
230 bool GHOST_SystemWin32::processEvents(bool waitForEvent)
233 bool anyProcessed = false;
236 GHOST_TimerManager* timerMgr = getTimerManager();
238 if (waitForEvent && !::PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE)) {
242 GHOST_TUns64 next = timerMgr->nextFireTime();
243 GHOST_TInt64 maxSleep = next - getMilliSeconds();
245 if (next == GHOST_kFireTimeNever) {
247 } else if(maxSleep >= 0.0) {
248 ::SetTimer(NULL, 0, maxSleep, NULL);
250 ::KillTimer(NULL, 0);
255 if (timerMgr->fireTimers(getMilliSeconds())) {
259 // Process all the events waiting for us
260 while (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE) != 0) {
261 ::TranslateMessage(&msg);
262 ::DispatchMessage(&msg);
265 } while (waitForEvent && !anyProcessed);
271 GHOST_TSuccess GHOST_SystemWin32::getCursorPosition(GHOST_TInt32& x, GHOST_TInt32& y) const
274 if(::GetCursorPos(&point)){
277 return GHOST_kSuccess;
279 return GHOST_kFailure;
283 GHOST_TSuccess GHOST_SystemWin32::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y)
285 if (!GetActiveWindow())
286 return GHOST_kFailure;
287 return ::SetCursorPos(x, y) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
291 GHOST_TSuccess GHOST_SystemWin32::getModifierKeys(GHOST_ModifierKeys& keys) const
293 bool down = HIBYTE(::GetKeyState(VK_SHIFT)) != 0;
294 keys.set(GHOST_kModifierKeyLeftShift, down);
295 keys.set(GHOST_kModifierKeyRightShift, down);
297 down = HIBYTE(::GetKeyState(VK_MENU)) != 0;
298 keys.set(GHOST_kModifierKeyLeftAlt, down);
299 keys.set(GHOST_kModifierKeyRightAlt, down);
301 down = HIBYTE(::GetKeyState(VK_CONTROL)) != 0;
302 keys.set(GHOST_kModifierKeyLeftControl, down);
303 keys.set(GHOST_kModifierKeyRightControl, down);
305 bool lwindown = HIBYTE(::GetKeyState(VK_LWIN)) != 0;
306 bool rwindown = HIBYTE(::GetKeyState(VK_RWIN)) != 0;
307 if(lwindown || rwindown)
308 keys.set(GHOST_kModifierKeyOS, true);
310 keys.set(GHOST_kModifierKeyOS, false);
311 return GHOST_kSuccess;
315 GHOST_TSuccess GHOST_SystemWin32::getButtons(GHOST_Buttons& buttons) const
317 /* Check for swapped buttons (left-handed mouse buttons)
318 * GetAsyncKeyState() will give back the state of the physical mouse buttons.
320 bool swapped = ::GetSystemMetrics(SM_SWAPBUTTON) == TRUE;
322 bool down = HIBYTE(::GetKeyState(VK_LBUTTON)) != 0;
323 buttons.set(swapped ? GHOST_kButtonMaskRight : GHOST_kButtonMaskLeft, down);
325 down = HIBYTE(::GetKeyState(VK_MBUTTON)) != 0;
326 buttons.set(GHOST_kButtonMaskMiddle, down);
328 down = HIBYTE(::GetKeyState(VK_RBUTTON)) != 0;
329 buttons.set(swapped ? GHOST_kButtonMaskLeft : GHOST_kButtonMaskRight, down);
330 return GHOST_kSuccess;
334 GHOST_TSuccess GHOST_SystemWin32::init()
336 GHOST_TSuccess success = GHOST_System::init();
338 /* Disable scaling on high DPI displays on Vista */
339 HMODULE user32 = ::LoadLibraryA("user32.dll");
340 typedef BOOL (WINAPI * LPFNSETPROCESSDPIAWARE)();
341 LPFNSETPROCESSDPIAWARE SetProcessDPIAware =
342 (LPFNSETPROCESSDPIAWARE)GetProcAddress(user32, "SetProcessDPIAware");
343 if (SetProcessDPIAware)
344 SetProcessDPIAware();
347 // Determine whether this system has a high frequency performance counter. */
348 m_hasPerformanceCounter = ::QueryPerformanceFrequency((LARGE_INTEGER*)&m_freq) == TRUE;
349 if (m_hasPerformanceCounter) {
350 GHOST_PRINT("GHOST_SystemWin32::init: High Frequency Performance Timer available\n")
351 ::QueryPerformanceCounter((LARGE_INTEGER*)&m_start);
354 GHOST_PRINT("GHOST_SystemWin32::init: High Frequency Performance Timer not available\n")
359 wc.style= CS_HREDRAW | CS_VREDRAW;
360 wc.lpfnWndProc= s_wndProc;
363 wc.hInstance= ::GetModuleHandle(0);
364 wc.hIcon = ::LoadIcon(wc.hInstance, "APPICON");
367 ::LoadIcon(NULL, IDI_APPLICATION);
369 wc.hCursor = ::LoadCursor(0, IDC_ARROW);
370 wc.hbrBackground= (HBRUSH)::GetStockObject(BLACK_BRUSH);
372 wc.lpszClassName= GHOST_WindowWin32::getWindowClassName();
374 // Use RegisterClassEx for setting small icon
375 if (::RegisterClass(&wc) == 0) {
376 success = GHOST_kFailure;
383 GHOST_TSuccess GHOST_SystemWin32::exit()
385 return GHOST_System::exit();
389 GHOST_TKey GHOST_SystemWin32::convertKey(GHOST_IWindow *window, WPARAM wParam, LPARAM lParam) const
391 bool isExtended = (lParam&(1<<24))?true:false;
394 GHOST_ModifierKeys oldModifiers, newModifiers;
395 ((GHOST_SystemWin32*)getSystem())->retrieveModifierKeys(oldModifiers);
396 ((GHOST_SystemWin32*)getSystem())->getModifierKeys(newModifiers);
398 if ((wParam >= '0') && (wParam <= '9')) {
399 // VK_0 thru VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39)
400 key = (GHOST_TKey)(wParam - '0' + GHOST_kKey0);
402 else if ((wParam >= 'A') && (wParam <= 'Z')) {
403 // VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A)
404 key = (GHOST_TKey)(wParam - 'A' + GHOST_kKeyA);
406 else if ((wParam >= VK_F1) && (wParam <= VK_F24)) {
407 key = (GHOST_TKey)(wParam - VK_F1 + GHOST_kKeyF1);
412 key = isExtended?GHOST_kKeyNumpadEnter:GHOST_kKeyEnter;
415 case VK_BACK: key = GHOST_kKeyBackSpace; break;
416 case VK_TAB: key = GHOST_kKeyTab; break;
417 case VK_ESCAPE: key = GHOST_kKeyEsc; break;
418 case VK_SPACE: key = GHOST_kKeySpace; break;
419 case VK_PRIOR: key = GHOST_kKeyUpPage; break;
420 case VK_NEXT: key = GHOST_kKeyDownPage; break;
421 case VK_END: key = GHOST_kKeyEnd; break;
422 case VK_HOME: key = GHOST_kKeyHome; break;
423 case VK_INSERT: key = GHOST_kKeyInsert; break;
424 case VK_DELETE: key = GHOST_kKeyDelete; break;
425 case VK_LEFT: key = GHOST_kKeyLeftArrow; break;
426 case VK_RIGHT: key = GHOST_kKeyRightArrow; break;
427 case VK_UP: key = GHOST_kKeyUpArrow; break;
428 case VK_DOWN: key = GHOST_kKeyDownArrow; break;
429 case VK_NUMPAD0: key = GHOST_kKeyNumpad0; break;
430 case VK_NUMPAD1: key = GHOST_kKeyNumpad1; break;
431 case VK_NUMPAD2: key = GHOST_kKeyNumpad2; break;
432 case VK_NUMPAD3: key = GHOST_kKeyNumpad3; break;
433 case VK_NUMPAD4: key = GHOST_kKeyNumpad4; break;
434 case VK_NUMPAD5: key = GHOST_kKeyNumpad5; break;
435 case VK_NUMPAD6: key = GHOST_kKeyNumpad6; break;
436 case VK_NUMPAD7: key = GHOST_kKeyNumpad7; break;
437 case VK_NUMPAD8: key = GHOST_kKeyNumpad8; break;
438 case VK_NUMPAD9: key = GHOST_kKeyNumpad9; break;
439 case VK_SNAPSHOT: key = GHOST_kKeyPrintScreen; break;
440 case VK_PAUSE: key = GHOST_kKeyPause; break;
441 case VK_MULTIPLY: key = GHOST_kKeyNumpadAsterisk; break;
442 case VK_SUBTRACT: key = GHOST_kKeyNumpadMinus; break;
443 case VK_DECIMAL: key = GHOST_kKeyNumpadPeriod; break;
444 case VK_DIVIDE: key = GHOST_kKeyNumpadSlash; break;
445 case VK_ADD: key = GHOST_kKeyNumpadPlus; break;
447 case VK_SEMICOLON: key = GHOST_kKeySemicolon; break;
448 case VK_EQUALS: key = GHOST_kKeyEqual; break;
449 case VK_COMMA: key = GHOST_kKeyComma; break;
450 case VK_MINUS: key = GHOST_kKeyMinus; break;
451 case VK_PERIOD: key = GHOST_kKeyPeriod; break;
452 case VK_SLASH: key = GHOST_kKeySlash; break;
453 case VK_BACK_QUOTE: key = GHOST_kKeyAccentGrave; break;
454 case VK_OPEN_BRACKET: key = GHOST_kKeyLeftBracket; break;
455 case VK_BACK_SLASH: key = GHOST_kKeyBackslash; break;
456 case VK_CLOSE_BRACKET: key = GHOST_kKeyRightBracket; break;
457 case VK_QUOTE: key = GHOST_kKeyQuote; break;
458 case VK_GR_LESS: key = GHOST_kKeyGrLess; break;
462 bool lchanged = oldModifiers.get(GHOST_kModifierKeyLeftShift) != newModifiers.get(GHOST_kModifierKeyLeftShift);
464 key = GHOST_kKeyLeftShift;
466 key = GHOST_kKeyRightShift;
472 bool lchanged = oldModifiers.get(GHOST_kModifierKeyLeftControl) != newModifiers.get(GHOST_kModifierKeyLeftControl);
474 key = GHOST_kKeyLeftControl;
476 key = GHOST_kKeyRightControl;
482 if(m_hasAltGr && isExtended) {
483 // We have here an extended RAlt, which is AltGr. The keyboard driver on Windows sends before this a LControl, so
484 // to be able to input characters created with AltGr (normal on German, French, Finnish and other keyboards) we
485 // push an extra LControl up event. This ensures we don't have a 'hanging' ctrl event in Blender windowmanager
486 // when typing in Text editor or Console.
487 GHOST_Event *extra = new GHOST_EventKey(getSystem()->getMilliSeconds(), GHOST_kEventKeyUp, window, GHOST_kKeyLeftControl, '\0');
488 ((GHOST_SystemWin32*)getSystem())->pushEvent(extra);
489 newModifiers.set(GHOST_kModifierKeyRightControl, false);
490 newModifiers.set(GHOST_kModifierKeyLeftControl, false);
492 bool lchanged = oldModifiers.get(GHOST_kModifierKeyLeftAlt) != newModifiers.get(GHOST_kModifierKeyLeftAlt);
494 key = GHOST_kKeyLeftAlt;
496 key = GHOST_kKeyRightAlt;
504 case VK_NUMLOCK: key = GHOST_kKeyNumLock; break;
505 case VK_SCROLL: key = GHOST_kKeyScrollLock; break;
506 case VK_CAPITAL: key = GHOST_kKeyCapsLock; break;
508 key = GHOST_kKeyUnknown;
512 ((GHOST_SystemWin32*)getSystem())->storeModifierKeys(newModifiers);
516 GHOST_EventButton* GHOST_SystemWin32::processButtonEvent(GHOST_TEventType type, GHOST_IWindow *window, GHOST_TButtonMask mask)
518 return new GHOST_EventButton (getSystem()->getMilliSeconds(), type, window, mask);
522 GHOST_EventCursor* GHOST_SystemWin32::processCursorEvent(GHOST_TEventType type, GHOST_IWindow *Iwindow)
524 GHOST_TInt32 x_screen, y_screen;
525 GHOST_SystemWin32 * system = ((GHOST_SystemWin32 * ) getSystem());
526 GHOST_WindowWin32 * window = ( GHOST_WindowWin32 * ) Iwindow;
528 system->getCursorPosition(x_screen, y_screen);
530 if(window->getCursorGrabMode() != GHOST_kGrabDisable && window->getCursorGrabMode() != GHOST_kGrabNormal)
532 GHOST_TInt32 x_new= x_screen;
533 GHOST_TInt32 y_new= y_screen;
534 GHOST_TInt32 x_accum, y_accum;
537 /* fallback to window bounds */
538 if(window->getCursorGrabBounds(bounds)==GHOST_kFailure){
539 window->getClientBounds(bounds);
542 /* could also clamp to screen bounds
543 * wrap with a window outside the view will fail atm */
545 bounds.wrapPoint(x_new, y_new, 2); /* offset of one incase blender is at screen bounds */
547 window->getCursorGrabAccum(x_accum, y_accum);
548 if(x_new != x_screen|| y_new != y_screen) {
549 /* when wrapping we don't need to add an event because the
550 * setCursorPosition call will cause a new event after */
551 system->setCursorPosition(x_new, y_new); /* wrap */
552 window->setCursorGrabAccum(x_accum + (x_screen - x_new), y_accum + (y_screen - y_new));
554 return new GHOST_EventCursor(system->getMilliSeconds(),
555 GHOST_kEventCursorMove,
564 return new GHOST_EventCursor(system->getMilliSeconds(),
565 GHOST_kEventCursorMove,
575 GHOST_EventWheel* GHOST_SystemWin32::processWheelEvent(GHOST_IWindow *window, WPARAM wParam, LPARAM lParam)
577 // short fwKeys = LOWORD(wParam); // key flags
578 int zDelta = (short) HIWORD(wParam); // wheel rotation
580 // zDelta /= WHEEL_DELTA;
581 // temporary fix below: microsoft now has added more precision, making the above division not work
582 if (zDelta <= 0 ) zDelta= -1; else zDelta= 1;
584 // short xPos = (short) LOWORD(lParam); // horizontal position of pointer
585 // short yPos = (short) HIWORD(lParam); // vertical position of pointer
586 return new GHOST_EventWheel (getSystem()->getMilliSeconds(), window, zDelta);
590 GHOST_EventKey* GHOST_SystemWin32::processKeyEvent(GHOST_IWindow *window, bool keyDown, WPARAM wParam, LPARAM lParam)
592 GHOST_TKey key = ((GHOST_SystemWin32*)getSystem())->convertKey(window, wParam, lParam);
593 GHOST_EventKey* event;
594 if (key != GHOST_kKeyUnknown) {
598 /* Eat any character related messages */
599 if (::PeekMessage(&keyMsg, NULL, WM_CHAR, WM_SYSDEADCHAR, PM_REMOVE)) {
600 ascii = (char) keyMsg.wParam;
604 event = new GHOST_EventKey(getSystem()->getMilliSeconds(), keyDown ? GHOST_kEventKeyDown: GHOST_kEventKeyUp, window, key, ascii);
613 GHOST_Event* GHOST_SystemWin32::processWindowEvent(GHOST_TEventType type, GHOST_IWindow* window)
615 return new GHOST_Event(getSystem()->getMilliSeconds(), type, window);
618 GHOST_TSuccess GHOST_SystemWin32::pushDragDropEvent(GHOST_TEventType eventType,
619 GHOST_TDragnDropTypes draggedObjectType,
620 GHOST_IWindow* window,
621 int mouseX, int mouseY,
624 GHOST_SystemWin32* system = ((GHOST_SystemWin32*)getSystem());
625 return system->pushEvent(new GHOST_EventDragnDrop(system->getMilliSeconds(),
628 window,mouseX,mouseY,data)
632 void GHOST_SystemWin32::processMinMaxInfo(MINMAXINFO * minmax)
634 minmax->ptMinTrackSize.x=320;
635 minmax->ptMinTrackSize.y=240;
639 LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
641 GHOST_Event* event = 0;
643 GHOST_SystemWin32* system = ((GHOST_SystemWin32*)getSystem());
644 GHOST_ASSERT(system, "GHOST_SystemWin32::s_wndProc(): system not initialized")
647 GHOST_WindowWin32* window = (GHOST_WindowWin32*)::GetWindowLong(hwnd, GWL_USERDATA);
650 // we need to check if new key layout has AltGr
651 case WM_INPUTLANGCHANGE:
652 system->keyboardAltGr();
654 ////////////////////////////////////////////////////////////////////////
655 // Keyboard events, processed
656 ////////////////////////////////////////////////////////////////////////
659 event = processKeyEvent(window, true, wParam, lParam);
661 GHOST_PRINT("GHOST_SystemWin32::wndProc: key event ")
663 GHOST_PRINT(" key ignored\n")
669 event = processKeyEvent(window, false, wParam, lParam);
671 GHOST_PRINT("GHOST_SystemWin32::wndProc: key event ")
673 GHOST_PRINT(" key ignored\n")
677 ////////////////////////////////////////////////////////////////////////
678 // Keyboard events, ignored
679 ////////////////////////////////////////////////////////////////////////
681 /* The WM_CHAR message is posted to the window with the keyboard focus when
682 * a WM_KEYDOWN message is translated by the TranslateMessage function. WM_CHAR
683 * contains the character code of the key that was pressed.
686 /* The WM_DEADCHAR message is posted to the window with the keyboard focus when a
687 * WM_KEYUP message is translated by the TranslateMessage function. WM_DEADCHAR
688 * specifies a character code generated by a dead key. A dead key is a key that
689 * generates a character, such as the umlaut (double-dot), that is combined with
690 * another character to form a composite character. For example, the umlaut-O
691 * character (Ù) is generated by typing the dead key for the umlaut character, and
692 * then typing the O key.
695 /* The WM_SYSDEADCHAR message is sent to the window with the keyboard focus when
696 * a WM_SYSKEYDOWN message is translated by the TranslateMessage function.
697 * WM_SYSDEADCHAR specifies the character code of a system dead key - that is,
698 * a dead key that is pressed while holding down the alt key.
701 ////////////////////////////////////////////////////////////////////////
702 // Tablet events, processed
703 ////////////////////////////////////////////////////////////////////////
705 ((GHOST_WindowWin32*)window)->processWin32TabletEvent(wParam, lParam);
709 ((GHOST_WindowWin32*)window)->processWin32TabletInitEvent();
711 ////////////////////////////////////////////////////////////////////////
712 // Mouse events, processed
713 ////////////////////////////////////////////////////////////////////////
715 window->registerMouseClickEvent(true);
716 event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskLeft);
719 window->registerMouseClickEvent(true);
720 event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskMiddle);
723 window->registerMouseClickEvent(true);
724 event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskRight);
727 window->registerMouseClickEvent(true);
728 if ((short) HIWORD(wParam) == XBUTTON1){
729 event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskButton4);
730 }else if((short) HIWORD(wParam) == XBUTTON2){
731 event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskButton5);
735 window->registerMouseClickEvent(false);
736 event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskLeft);
739 window->registerMouseClickEvent(false);
740 event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskMiddle);
743 window->registerMouseClickEvent(false);
744 event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskRight);
747 window->registerMouseClickEvent(false);
748 if ((short) HIWORD(wParam) == XBUTTON1){
749 event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskButton4);
750 }else if((short) HIWORD(wParam) == XBUTTON2){
751 event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskButton5);
755 event = processCursorEvent(GHOST_kEventCursorMove, window);
758 /* The WM_MOUSEWHEEL message is sent to the focus window
759 * when the mouse wheel is rotated. The DefWindowProc
760 * function propagates the message to the window's parent.
761 * There should be no internal forwarding of the message,
762 * since DefWindowProc propagates it up the parent chain
763 * until it finds a window that processes it.
765 event = processWheelEvent(window, wParam, lParam);
768 /* The WM_SETCURSOR message is sent to a window if the mouse causes the cursor
769 * to move within a window and mouse input is not captured.
770 * This means we have to set the cursor shape every time the mouse moves!
771 * The DefWindowProc function uses this message to set the cursor to an
772 * arrow if it is not in the client area.
774 if (LOWORD(lParam) == HTCLIENT) {
775 // Load the current cursor
776 window->loadCursor(window->getCursorVisibility(), window->getCursorShape());
777 // Bypass call to DefWindowProc
781 // Outside of client area show standard cursor
782 window->loadCursor(true, GHOST_kStandardCursorDefault);
786 ////////////////////////////////////////////////////////////////////////
787 // Mouse events, ignored
788 ////////////////////////////////////////////////////////////////////////
790 /* The WM_NCMOUSEMOVE message is posted to a window when the cursor is moved
791 * within the nonclient area of the window. This message is posted to the window
792 * that contains the cursor. If a window has captured the mouse, this message is not posted.
795 /* The WM_NCHITTEST message is sent to a window when the cursor moves, or
796 * when a mouse button is pressed or released. If the mouse is not captured,
797 * the message is sent to the window beneath the cursor. Otherwise, the message
798 * is sent to the window that has captured the mouse.
802 ////////////////////////////////////////////////////////////////////////
803 // Window events, processed
804 ////////////////////////////////////////////////////////////////////////
806 /* The WM_CLOSE message is sent as a signal that a window or an application should terminate. */
807 event = processWindowEvent(GHOST_kEventWindowClose, window);
810 /* The WM_ACTIVATE message is sent to both the window being activated and the window being
811 * deactivated. If the windows use the same input queue, the message is sent synchronously,
812 * first to the window procedure of the top-level window being deactivated, then to the window
813 * procedure of the top-level window being activated. If the windows use different input queues,
814 * the message is sent asynchronously, so the window is activated immediately.
816 event = processWindowEvent(LOWORD(wParam) ? GHOST_kEventWindowActivate : GHOST_kEventWindowDeactivate, window);
817 /* WARNING: Let DefWindowProc handle WM_ACTIVATE, otherwise WM_MOUSEWHEEL
818 will not be dispatched to OUR active window if we minimize one of OUR windows. */
819 lResult = ::DefWindowProc(hwnd, msg, wParam, lParam);
822 /* An application sends the WM_PAINT message when the system or another application
823 * makes a request to paint a portion of an application's window. The message is sent
824 * when the UpdateWindow or RedrawWindow function is called, or by the DispatchMessage
825 * function when the application obtains a WM_PAINT message by using the GetMessage or
826 * PeekMessage function.
828 event = processWindowEvent(GHOST_kEventWindowUpdate, window);
829 ::ValidateRect(hwnd, NULL);
831 case WM_GETMINMAXINFO:
832 /* The WM_GETMINMAXINFO message is sent to a window when the size or
833 * position of the window is about to change. An application can use
834 * this message to override the window's default maximized size and
835 * position, or its default minimum or maximum tracking size.
837 processMinMaxInfo((MINMAXINFO *) lParam);
838 /* Let DefWindowProc handle it. */
841 /* The WM_SIZE message is sent to a window after its size has changed.
842 * The WM_SIZE and WM_MOVE messages are not sent if an application handles the
843 * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient
844 * to perform any move or size change processing during the WM_WINDOWPOSCHANGED
845 * message without calling DefWindowProc.
847 event = processWindowEvent(GHOST_kEventWindowSize, window);
849 case WM_CAPTURECHANGED:
850 window->lostMouseCapture();
853 /* The WM_MOVING message is sent to a window that the user is moving. By processing
854 * this message, an application can monitor the size and position of the drag rectangle
855 * and, if needed, change its size or position.
858 /* The WM_SIZE and WM_MOVE messages are not sent if an application handles the
859 * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient
860 * to perform any move or size change processing during the WM_WINDOWPOSCHANGED
861 * message without calling DefWindowProc.
863 event = processWindowEvent(GHOST_kEventWindowMove, window);
865 ////////////////////////////////////////////////////////////////////////
866 // Window events, ignored
867 ////////////////////////////////////////////////////////////////////////
868 case WM_WINDOWPOSCHANGED:
869 /* The WM_WINDOWPOSCHANGED message is sent to a window whose size, position, or place
870 * in the Z order has changed as a result of a call to the SetWindowPos function or
871 * another window-management function.
872 * The WM_SIZE and WM_MOVE messages are not sent if an application handles the
873 * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient
874 * to perform any move or size change processing during the WM_WINDOWPOSCHANGED
875 * message without calling DefWindowProc.
878 /* An application sends the WM_ERASEBKGND message when the window background must be
879 * erased (for example, when a window is resized). The message is sent to prepare an
880 * invalidated portion of a window for painting.
883 /* An application sends the WM_NCPAINT message to a window when its frame must be painted. */
885 /* The WM_NCACTIVATE message is sent to a window when its nonclient area needs to be changed
886 * to indicate an active or inactive state.
889 /* The WM_DESTROY message is sent when a window is being destroyed. It is sent to the window
890 * procedure of the window being destroyed after the window is removed from the screen.
891 * This message is sent first to the window being destroyed and then to the child windows
892 * (if any) as they are destroyed. During the processing of the message, it can be assumed
893 * that all child windows still exist.
896 /* The WM_NCDESTROY message informs a window that its nonclient area is being destroyed. The
897 * DestroyWindow function sends the WM_NCDESTROY message to the window following the WM_DESTROY
898 * message. WM_DESTROY is used to free the allocated memory object associated with the window.
901 /* The WM_KILLFOCUS message is sent to a window immediately before it loses the keyboard focus. */
903 /* The WM_SHOWWINDOW message is sent to a window when the window is about to be hidden or shown. */
904 case WM_WINDOWPOSCHANGING:
905 /* The WM_WINDOWPOSCHANGING message is sent to a window whose size, position, or place in
906 * the Z order is about to change as a result of a call to the SetWindowPos function or
907 * another window-management function.
910 /* The WM_SETFOCUS message is sent to a window after it has gained the keyboard focus. */
911 case WM_ENTERSIZEMOVE:
912 /* The WM_ENTERSIZEMOVE message is sent one time to a window after it enters the moving
913 * or sizing modal loop. The window enters the moving or sizing modal loop when the user
914 * clicks the window's title bar or sizing border, or when the window passes the
915 * WM_SYSCOMMAND message to the DefWindowProc function and the wParam parameter of the
916 * message specifies the SC_MOVE or SC_SIZE value. The operation is complete when
917 * DefWindowProc returns.
921 ////////////////////////////////////////////////////////////////////////
923 ////////////////////////////////////////////////////////////////////////
925 /* An application sends a WM_GETTEXT message to copy the text that
926 * corresponds to a window into a buffer provided by the caller.
929 /* The WM_ACTIVATEAPP message is sent when a window belonging to a
930 * different application than the active window is about to be activated.
931 * The message is sent to the application whose window is being activated
932 * and to the application whose window is being deactivated.
935 /* The WIN32 docs say:
936 * The WM_TIMER message is posted to the installing thread's message queue
937 * when a timer expires. You can process the message by providing a WM_TIMER
938 * case in the window procedure. Otherwise, the default window procedure will
939 * call the TimerProc callback function specified in the call to the SetTimer
940 * function used to install the timer.
942 * In GHOST, we let DefWindowProc call the timer callback.
945 case WM_BLND_NDOF_AXIS:
947 GHOST_TEventNDOFData ndofdata;
948 system->m_ndofManager->GHOST_NDOFGetDatas(ndofdata);
949 system->m_eventManager->
950 pushEvent(new GHOST_EventNDOF(
951 system->getMilliSeconds(),
952 GHOST_kEventNDOFMotion,
956 case WM_BLND_NDOF_BTN:
958 GHOST_TEventNDOFData ndofdata;
959 system->m_ndofManager->GHOST_NDOFGetDatas(ndofdata);
960 system->m_eventManager->
961 pushEvent(new GHOST_EventNDOF(
962 system->getMilliSeconds(),
963 GHOST_kEventNDOFButton,
970 // Event found for a window before the pointer to the class has been set.
971 GHOST_PRINT("GHOST_SystemWin32::wndProc: GHOST window event before creation\n")
972 /* These are events we typically miss at this point:
973 WM_GETMINMAXINFO 0x24
977 We let DefWindowProc do the work.
982 // Events without valid hwnd
983 GHOST_PRINT("GHOST_SystemWin32::wndProc: event without window\n")
987 system->pushEvent(event);
990 lResult = ::DefWindowProc(hwnd, msg, wParam, lParam);
995 GHOST_TUns8* GHOST_SystemWin32::getClipboard(bool selection) const
1000 if ( IsClipboardFormatAvailable(CF_TEXT) && OpenClipboard(NULL) ) {
1001 HANDLE hData = GetClipboardData( CF_TEXT );
1002 if (hData == NULL) {
1006 buffer = (char*)GlobalLock( hData );
1008 temp_buff = (char*) malloc(strlen(buffer)+1);
1009 strcpy(temp_buff, buffer);
1011 GlobalUnlock( hData );
1014 temp_buff[strlen(buffer)] = '\0';
1016 return (GHOST_TUns8*)temp_buff;
1025 void GHOST_SystemWin32::putClipboard(GHOST_TInt8 *buffer, bool selection) const
1027 if(selection) {return;} // for copying the selection, used on X11
1029 if (OpenClipboard(NULL)) {
1036 clipbuffer = LocalAlloc(LMEM_FIXED,((strlen(buffer)+1)));
1037 data = (char*)GlobalLock(clipbuffer);
1039 strcpy(data, (char*)buffer);
1040 data[strlen(buffer)] = '\0';
1041 LocalUnlock(clipbuffer);
1042 SetClipboardData(CF_TEXT,clipbuffer);
1050 const GHOST_TUns8* GHOST_SystemWin32::getSystemDir() const
1052 static char knownpath[MAX_PATH];
1053 HRESULT hResult = SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, SHGFP_TYPE_CURRENT, knownpath);
1055 if (hResult == S_OK)
1057 return (GHOST_TUns8*)knownpath;
1063 const GHOST_TUns8* GHOST_SystemWin32::getUserDir() const
1065 static char knownpath[MAX_PATH];
1066 HRESULT hResult = SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, knownpath);
1068 if (hResult == S_OK)
1070 return (GHOST_TUns8*)knownpath;
1076 const GHOST_TUns8* GHOST_SystemWin32::getBinaryDir() const
1078 static char fullname[MAX_PATH];
1079 if(GetModuleFileName(0, fullname, MAX_PATH)) {
1080 return (GHOST_TUns8*)fullname;