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
37 #include "GHOST_SystemWin32.h"
38 #include "GHOST_EventDragnDrop.h"
40 #define WIN32_LEAN_AND_MEAN
44 #define _WIN32_IE 0x0501
48 // win64 doesn't define GWL_USERDATA
51 #define GWL_USERDATA GWLP_USERDATA
52 #define GWL_WNDPROC GWLP_WNDPROC
57 * According to the docs the mouse wheel message is supported from windows 98
58 * upwards. Leaving WINVER at default value, the WM_MOUSEWHEEL message and the
59 * wheel detent value are undefined.
62 #define WM_MOUSEWHEEL 0x020A
63 #endif // WM_MOUSEWHEEL
65 #define WHEEL_DELTA 120 /* Value for rolling one detent, (old convention! MS changed it) */
69 * Defines for mouse buttons 4 and 5 aka xbutton1 and xbutton2.
70 * MSDN: Declared in Winuser.h, include Windows.h
71 * This does not seem to work with MinGW so we define our own here.
74 #define XBUTTON1 0x0001
77 #define XBUTTON2 0x0002
80 #define WM_XBUTTONUP 524
81 #endif // WM_XBUTTONUP
82 #ifndef WM_XBUTTONDOWN
83 #define WM_XBUTTONDOWN 523
84 #endif // WM_XBUTTONDOWN
86 #include "GHOST_Debug.h"
87 #include "GHOST_DisplayManagerWin32.h"
88 #include "GHOST_EventButton.h"
89 #include "GHOST_EventCursor.h"
90 #include "GHOST_EventKey.h"
91 #include "GHOST_EventWheel.h"
92 #include "GHOST_EventNDOF.h"
93 #include "GHOST_TimerTask.h"
94 #include "GHOST_TimerManager.h"
95 #include "GHOST_WindowManager.h"
96 #include "GHOST_WindowWin32.h"
97 #include "GHOST_NDOFManager.h"
99 // Key code values not found in winuser.h
101 #define VK_MINUS 0xBD
104 #define VK_SEMICOLON 0xBA
105 #endif // VK_SEMICOLON
107 #define VK_PERIOD 0xBE
110 #define VK_COMMA 0xBC
113 #define VK_QUOTE 0xDE
115 #ifndef VK_BACK_QUOTE
116 #define VK_BACK_QUOTE 0xC0
117 #endif // VK_BACK_QUOTE
119 #define VK_SLASH 0xBF
121 #ifndef VK_BACK_SLASH
122 #define VK_BACK_SLASH 0xDC
123 #endif // VK_BACK_SLASH
125 #define VK_EQUALS 0xBB
127 #ifndef VK_OPEN_BRACKET
128 #define VK_OPEN_BRACKET 0xDB
129 #endif // VK_OPEN_BRACKET
130 #ifndef VK_CLOSE_BRACKET
131 #define VK_CLOSE_BRACKET 0xDD
132 #endif // VK_CLOSE_BRACKET
134 #define VK_GR_LESS 0xE2
138 GHOST_SystemWin32::GHOST_SystemWin32()
139 : m_hasPerformanceCounter(false), m_freq(0), m_start(0)
141 m_displayManager = new GHOST_DisplayManagerWin32 ();
142 GHOST_ASSERT(m_displayManager, "GHOST_SystemWin32::GHOST_SystemWin32(): m_displayManager==0\n");
143 m_displayManager->initialize();
145 // Require COM for GHOST_DropTargetWin32 created in GHOST_WindowWin32.
149 GHOST_SystemWin32::~GHOST_SystemWin32()
156 GHOST_TUns64 GHOST_SystemWin32::getMilliSeconds() const
158 // Hardware does not support high resolution timers. We will use GetTickCount instead then.
159 if (!m_hasPerformanceCounter) {
160 return ::GetTickCount();
163 // Retrieve current count
165 ::QueryPerformanceCounter((LARGE_INTEGER*)&count);
167 // Calculate the time passed since system initialization.
168 __int64 delta = 1000*(count-m_start);
170 GHOST_TUns64 t = (GHOST_TUns64)(delta/m_freq);
175 GHOST_TUns8 GHOST_SystemWin32::getNumDisplays() const
177 GHOST_ASSERT(m_displayManager, "GHOST_SystemWin32::getNumDisplays(): m_displayManager==0\n");
178 GHOST_TUns8 numDisplays;
179 m_displayManager->getNumDisplays(numDisplays);
184 void GHOST_SystemWin32::getMainDisplayDimensions(GHOST_TUns32& width, GHOST_TUns32& height) const
186 width = ::GetSystemMetrics(SM_CXSCREEN);
187 height= ::GetSystemMetrics(SM_CYSCREEN);
191 GHOST_IWindow* GHOST_SystemWin32::createWindow(
192 const STR_String& title,
193 GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, GHOST_TUns32 height,
194 GHOST_TWindowState state, GHOST_TDrawingContextType type,
195 bool stereoVisual, const GHOST_TUns16 numOfAASamples, const GHOST_TEmbedderWindowID parentWindow )
197 GHOST_Window* window = 0;
198 window = new GHOST_WindowWin32 (this, title, left, top, width, height, state, type, stereoVisual, numOfAASamples);
200 if (window->getValid()) {
201 // Store the pointer to the window
202 // if (state != GHOST_kWindowStateFullScreen) {
203 m_windowManager->addWindow(window);
207 // An invalid window could be one that was used to test for AA
208 window = ((GHOST_WindowWin32*)window)->getNextWindow();
210 // If another window is found, let the wm know about that one, but not the old one
211 if (window->getValid()) {
212 m_windowManager->addWindow(window);
225 bool GHOST_SystemWin32::processEvents(bool waitForEvent)
228 bool anyProcessed = false;
231 GHOST_TimerManager* timerMgr = getTimerManager();
233 if (waitForEvent && !::PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE)) {
237 GHOST_TUns64 next = timerMgr->nextFireTime();
238 GHOST_TInt64 maxSleep = next - getMilliSeconds();
240 if (next == GHOST_kFireTimeNever) {
242 } else if(maxSleep >= 0.0) {
243 ::SetTimer(NULL, 0, maxSleep, NULL);
245 ::KillTimer(NULL, 0);
250 if (timerMgr->fireTimers(getMilliSeconds())) {
254 // Process all the events waiting for us
255 while (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE) != 0) {
256 ::TranslateMessage(&msg);
257 ::DispatchMessage(&msg);
260 } while (waitForEvent && !anyProcessed);
266 GHOST_TSuccess GHOST_SystemWin32::getCursorPosition(GHOST_TInt32& x, GHOST_TInt32& y) const
269 if(::GetCursorPos(&point)){
272 return GHOST_kSuccess;
274 return GHOST_kFailure;
278 GHOST_TSuccess GHOST_SystemWin32::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y)
280 if (!GetActiveWindow())
281 return GHOST_kFailure;
282 return ::SetCursorPos(x, y) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
286 GHOST_TSuccess GHOST_SystemWin32::getModifierKeys(GHOST_ModifierKeys& keys) const
288 bool down = HIBYTE(::GetKeyState(VK_LSHIFT)) != 0;
289 keys.set(GHOST_kModifierKeyLeftShift, down);
290 down = HIBYTE(::GetKeyState(VK_RSHIFT)) != 0;
291 keys.set(GHOST_kModifierKeyRightShift, down);
292 down = HIBYTE(::GetKeyState(VK_LMENU)) != 0;
293 keys.set(GHOST_kModifierKeyLeftAlt, down);
294 down = HIBYTE(::GetKeyState(VK_RMENU)) != 0;
295 keys.set(GHOST_kModifierKeyRightAlt, down);
296 down = HIBYTE(::GetKeyState(VK_LCONTROL)) != 0;
297 keys.set(GHOST_kModifierKeyLeftControl, down);
298 down = HIBYTE(::GetKeyState(VK_RCONTROL)) != 0;
299 keys.set(GHOST_kModifierKeyRightControl, down);
300 bool lwindown = HIBYTE(::GetKeyState(VK_LWIN)) != 0;
301 bool rwindown = HIBYTE(::GetKeyState(VK_RWIN)) != 0;
302 if(lwindown || rwindown)
303 keys.set(GHOST_kModifierKeyOS, true);
305 keys.set(GHOST_kModifierKeyOS, false);
306 return GHOST_kSuccess;
310 GHOST_TSuccess GHOST_SystemWin32::getButtons(GHOST_Buttons& buttons) const
312 /* Check for swapped buttons (left-handed mouse buttons)
313 * GetAsyncKeyState() will give back the state of the physical mouse buttons.
315 bool swapped = ::GetSystemMetrics(SM_SWAPBUTTON) == TRUE;
317 bool down = HIBYTE(::GetKeyState(VK_LBUTTON)) != 0;
318 buttons.set(swapped ? GHOST_kButtonMaskRight : GHOST_kButtonMaskLeft, down);
320 down = HIBYTE(::GetKeyState(VK_MBUTTON)) != 0;
321 buttons.set(GHOST_kButtonMaskMiddle, down);
323 down = HIBYTE(::GetKeyState(VK_RBUTTON)) != 0;
324 buttons.set(swapped ? GHOST_kButtonMaskLeft : GHOST_kButtonMaskRight, down);
325 return GHOST_kSuccess;
329 GHOST_TSuccess GHOST_SystemWin32::init()
331 GHOST_TSuccess success = GHOST_System::init();
333 /* Disable scaling on high DPI displays on Vista */
334 HMODULE user32 = ::LoadLibraryA("user32.dll");
335 typedef BOOL (WINAPI * LPFNSETPROCESSDPIAWARE)();
336 LPFNSETPROCESSDPIAWARE SetProcessDPIAware =
337 (LPFNSETPROCESSDPIAWARE)GetProcAddress(user32, "SetProcessDPIAware");
338 if (SetProcessDPIAware)
339 SetProcessDPIAware();
342 // Determine whether this system has a high frequency performance counter. */
343 m_hasPerformanceCounter = ::QueryPerformanceFrequency((LARGE_INTEGER*)&m_freq) == TRUE;
344 if (m_hasPerformanceCounter) {
345 GHOST_PRINT("GHOST_SystemWin32::init: High Frequency Performance Timer available\n")
346 ::QueryPerformanceCounter((LARGE_INTEGER*)&m_start);
349 GHOST_PRINT("GHOST_SystemWin32::init: High Frequency Performance Timer not available\n")
354 wc.style= CS_HREDRAW | CS_VREDRAW;
355 wc.lpfnWndProc= s_wndProc;
358 wc.hInstance= ::GetModuleHandle(0);
359 wc.hIcon = ::LoadIcon(wc.hInstance, "APPICON");
362 ::LoadIcon(NULL, IDI_APPLICATION);
364 wc.hCursor = ::LoadCursor(0, IDC_ARROW);
365 wc.hbrBackground= (HBRUSH)::GetStockObject(BLACK_BRUSH);
367 wc.lpszClassName= GHOST_WindowWin32::getWindowClassName();
369 // Use RegisterClassEx for setting small icon
370 if (::RegisterClass(&wc) == 0) {
371 success = GHOST_kFailure;
378 GHOST_TSuccess GHOST_SystemWin32::exit()
380 return GHOST_System::exit();
384 GHOST_TKey GHOST_SystemWin32::convertKey(WPARAM wParam, LPARAM lParam) const
387 GHOST_ModifierKeys oldModifiers, newModifiers;
388 ((GHOST_SystemWin32*)getSystem())->retrieveModifierKeys(oldModifiers);
389 ((GHOST_SystemWin32*)getSystem())->getModifierKeys(newModifiers);
391 bool isExtended = (lParam&(1<<24))?true:false;
393 if ((wParam >= '0') && (wParam <= '9')) {
394 // VK_0 thru VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39)
395 key = (GHOST_TKey)(wParam - '0' + GHOST_kKey0);
397 else if ((wParam >= 'A') && (wParam <= 'Z')) {
398 // VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A)
399 key = (GHOST_TKey)(wParam - 'A' + GHOST_kKeyA);
401 else if ((wParam >= VK_F1) && (wParam <= VK_F24)) {
402 key = (GHOST_TKey)(wParam - VK_F1 + GHOST_kKeyF1);
407 key = isExtended?GHOST_kKeyNumpadEnter:GHOST_kKeyEnter;
410 case VK_BACK: key = GHOST_kKeyBackSpace; break;
411 case VK_TAB: key = GHOST_kKeyTab; break;
412 case VK_ESCAPE: key = GHOST_kKeyEsc; break;
413 case VK_SPACE: key = GHOST_kKeySpace; break;
414 case VK_PRIOR: key = GHOST_kKeyUpPage; break;
415 case VK_NEXT: key = GHOST_kKeyDownPage; break;
416 case VK_END: key = GHOST_kKeyEnd; break;
417 case VK_HOME: key = GHOST_kKeyHome; break;
418 case VK_INSERT: key = GHOST_kKeyInsert; break;
419 case VK_DELETE: key = GHOST_kKeyDelete; break;
420 case VK_LEFT: key = GHOST_kKeyLeftArrow; break;
421 case VK_RIGHT: key = GHOST_kKeyRightArrow; break;
422 case VK_UP: key = GHOST_kKeyUpArrow; break;
423 case VK_DOWN: key = GHOST_kKeyDownArrow; break;
424 case VK_NUMPAD0: key = GHOST_kKeyNumpad0; break;
425 case VK_NUMPAD1: key = GHOST_kKeyNumpad1; break;
426 case VK_NUMPAD2: key = GHOST_kKeyNumpad2; break;
427 case VK_NUMPAD3: key = GHOST_kKeyNumpad3; break;
428 case VK_NUMPAD4: key = GHOST_kKeyNumpad4; break;
429 case VK_NUMPAD5: key = GHOST_kKeyNumpad5; break;
430 case VK_NUMPAD6: key = GHOST_kKeyNumpad6; break;
431 case VK_NUMPAD7: key = GHOST_kKeyNumpad7; break;
432 case VK_NUMPAD8: key = GHOST_kKeyNumpad8; break;
433 case VK_NUMPAD9: key = GHOST_kKeyNumpad9; break;
434 case VK_SNAPSHOT: key = GHOST_kKeyPrintScreen; break;
435 case VK_PAUSE: key = GHOST_kKeyPause; break;
436 case VK_MULTIPLY: key = GHOST_kKeyNumpadAsterisk; break;
437 case VK_SUBTRACT: key = GHOST_kKeyNumpadMinus; break;
438 case VK_DECIMAL: key = GHOST_kKeyNumpadPeriod; break;
439 case VK_DIVIDE: key = GHOST_kKeyNumpadSlash; break;
440 case VK_ADD: key = GHOST_kKeyNumpadPlus; break;
442 case VK_SEMICOLON: key = GHOST_kKeySemicolon; break;
443 case VK_EQUALS: key = GHOST_kKeyEqual; break;
444 case VK_COMMA: key = GHOST_kKeyComma; break;
445 case VK_MINUS: key = GHOST_kKeyMinus; break;
446 case VK_PERIOD: key = GHOST_kKeyPeriod; break;
447 case VK_SLASH: key = GHOST_kKeySlash; break;
448 case VK_BACK_QUOTE: key = GHOST_kKeyAccentGrave; break;
449 case VK_OPEN_BRACKET: key = GHOST_kKeyLeftBracket; break;
450 case VK_BACK_SLASH: key = GHOST_kKeyBackslash; break;
451 case VK_CLOSE_BRACKET: key = GHOST_kKeyRightBracket; break;
452 case VK_QUOTE: key = GHOST_kKeyQuote; break;
453 case VK_GR_LESS: key = GHOST_kKeyGrLess; break;
457 bool lchanged = oldModifiers.get(GHOST_kModifierKeyLeftShift) != newModifiers.get(GHOST_kModifierKeyLeftShift);
459 key = GHOST_kKeyLeftShift;
461 key = GHOST_kKeyRightShift;
467 bool lchanged = oldModifiers.get(GHOST_kModifierKeyLeftControl) != newModifiers.get(GHOST_kModifierKeyLeftControl);
469 key = GHOST_kKeyLeftControl;
471 key = GHOST_kKeyRightControl;
477 bool lchanged = oldModifiers.get(GHOST_kModifierKeyLeftAlt) != newModifiers.get(GHOST_kModifierKeyLeftAlt);
479 key = GHOST_kKeyLeftAlt;
481 key = GHOST_kKeyRightAlt;
489 case VK_NUMLOCK: key = GHOST_kKeyNumLock; break;
490 case VK_SCROLL: key = GHOST_kKeyScrollLock; break;
491 case VK_CAPITAL: key = GHOST_kKeyCapsLock; break;
493 key = GHOST_kKeyUnknown;
500 GHOST_EventButton* GHOST_SystemWin32::processButtonEvent(GHOST_TEventType type, GHOST_IWindow *window, GHOST_TButtonMask mask)
502 return new GHOST_EventButton (getSystem()->getMilliSeconds(), type, window, mask);
506 GHOST_EventCursor* GHOST_SystemWin32::processCursorEvent(GHOST_TEventType type, GHOST_IWindow *Iwindow)
508 GHOST_TInt32 x_screen, y_screen;
509 GHOST_SystemWin32 * system = ((GHOST_SystemWin32 * ) getSystem());
510 GHOST_WindowWin32 * window = ( GHOST_WindowWin32 * ) Iwindow;
512 system->getCursorPosition(x_screen, y_screen);
514 if(window->getCursorGrabMode() != GHOST_kGrabDisable && window->getCursorGrabMode() != GHOST_kGrabNormal)
516 GHOST_TInt32 x_new= x_screen;
517 GHOST_TInt32 y_new= y_screen;
518 GHOST_TInt32 x_accum, y_accum;
521 /* fallback to window bounds */
522 if(window->getCursorGrabBounds(bounds)==GHOST_kFailure){
523 window->getClientBounds(bounds);
526 /* could also clamp to screen bounds
527 * wrap with a window outside the view will fail atm */
529 bounds.wrapPoint(x_new, y_new, 2); /* offset of one incase blender is at screen bounds */
531 window->getCursorGrabAccum(x_accum, y_accum);
532 if(x_new != x_screen|| y_new != y_screen) {
533 /* when wrapping we don't need to add an event because the
534 * setCursorPosition call will cause a new event after */
535 system->setCursorPosition(x_new, y_new); /* wrap */
536 window->setCursorGrabAccum(x_accum + (x_screen - x_new), y_accum + (y_screen - y_new));
538 return new GHOST_EventCursor(system->getMilliSeconds(),
539 GHOST_kEventCursorMove,
548 return new GHOST_EventCursor(system->getMilliSeconds(),
549 GHOST_kEventCursorMove,
559 GHOST_EventWheel* GHOST_SystemWin32::processWheelEvent(GHOST_IWindow *window, WPARAM wParam, LPARAM lParam)
561 // short fwKeys = LOWORD(wParam); // key flags
562 int zDelta = (short) HIWORD(wParam); // wheel rotation
564 // zDelta /= WHEEL_DELTA;
565 // temporary fix below: microsoft now has added more precision, making the above division not work
566 if (zDelta <= 0 ) zDelta= -1; else zDelta= 1;
568 // short xPos = (short) LOWORD(lParam); // horizontal position of pointer
569 // short yPos = (short) HIWORD(lParam); // vertical position of pointer
570 return new GHOST_EventWheel (getSystem()->getMilliSeconds(), window, zDelta);
574 GHOST_EventKey* GHOST_SystemWin32::processKeyEvent(GHOST_IWindow *window, bool keyDown, WPARAM wParam, LPARAM lParam)
576 GHOST_TKey key = ((GHOST_SystemWin32*)getSystem())->convertKey(wParam, lParam);
577 GHOST_EventKey* event;
578 if (key != GHOST_kKeyUnknown) {
582 /* Eat any character related messages */
583 if (::PeekMessage(&keyMsg, NULL, WM_CHAR, WM_SYSDEADCHAR, PM_REMOVE)) {
584 ascii = (char) keyMsg.wParam;
587 event = new GHOST_EventKey(getSystem()->getMilliSeconds(), keyDown ? GHOST_kEventKeyDown: GHOST_kEventKeyUp, window, key, ascii);
596 GHOST_Event* GHOST_SystemWin32::processWindowEvent(GHOST_TEventType type, GHOST_IWindow* window)
598 return new GHOST_Event(getSystem()->getMilliSeconds(), type, window);
601 GHOST_TSuccess GHOST_SystemWin32::pushDragDropEvent(GHOST_TEventType eventType,
602 GHOST_TDragnDropTypes draggedObjectType,
603 GHOST_IWindow* window,
604 int mouseX, int mouseY,
607 GHOST_SystemWin32* system = ((GHOST_SystemWin32*)getSystem());
608 return system->pushEvent(new GHOST_EventDragnDrop(system->getMilliSeconds(),
611 window,mouseX,mouseY,data)
615 void GHOST_SystemWin32::processMinMaxInfo(MINMAXINFO * minmax)
617 minmax->ptMinTrackSize.x=320;
618 minmax->ptMinTrackSize.y=240;
622 LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
624 GHOST_Event* event = 0;
626 GHOST_SystemWin32* system = ((GHOST_SystemWin32*)getSystem());
627 GHOST_ASSERT(system, "GHOST_SystemWin32::s_wndProc(): system not initialized")
630 GHOST_WindowWin32* window = (GHOST_WindowWin32*)::GetWindowLong(hwnd, GWL_USERDATA);
633 ////////////////////////////////////////////////////////////////////////
634 // Keyboard events, processed
635 ////////////////////////////////////////////////////////////////////////
638 event = processKeyEvent(window, true, wParam, lParam);
640 GHOST_PRINT("GHOST_SystemWin32::wndProc: key event ")
642 GHOST_PRINT(" key ignored\n")
648 event = processKeyEvent(window, false, wParam, lParam);
650 GHOST_PRINT("GHOST_SystemWin32::wndProc: key event ")
652 GHOST_PRINT(" key ignored\n")
656 ////////////////////////////////////////////////////////////////////////
657 // Keyboard events, ignored
658 ////////////////////////////////////////////////////////////////////////
660 /* The WM_CHAR message is posted to the window with the keyboard focus when
661 * a WM_KEYDOWN message is translated by the TranslateMessage function. WM_CHAR
662 * contains the character code of the key that was pressed.
665 /* The WM_DEADCHAR message is posted to the window with the keyboard focus when a
666 * WM_KEYUP message is translated by the TranslateMessage function. WM_DEADCHAR
667 * specifies a character code generated by a dead key. A dead key is a key that
668 * generates a character, such as the umlaut (double-dot), that is combined with
669 * another character to form a composite character. For example, the umlaut-O
670 * character (Ù) is generated by typing the dead key for the umlaut character, and
671 * then typing the O key.
674 /* The WM_SYSDEADCHAR message is sent to the window with the keyboard focus when
675 * a WM_SYSKEYDOWN message is translated by the TranslateMessage function.
676 * WM_SYSDEADCHAR specifies the character code of a system dead key - that is,
677 * a dead key that is pressed while holding down the alt key.
680 ////////////////////////////////////////////////////////////////////////
681 // Tablet events, processed
682 ////////////////////////////////////////////////////////////////////////
684 ((GHOST_WindowWin32*)window)->processWin32TabletEvent(wParam, lParam);
688 ((GHOST_WindowWin32*)window)->processWin32TabletInitEvent();
690 ////////////////////////////////////////////////////////////////////////
691 // Mouse events, processed
692 ////////////////////////////////////////////////////////////////////////
694 window->registerMouseClickEvent(true);
695 event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskLeft);
698 window->registerMouseClickEvent(true);
699 event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskMiddle);
702 window->registerMouseClickEvent(true);
703 event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskRight);
706 window->registerMouseClickEvent(true);
707 if ((short) HIWORD(wParam) == XBUTTON1){
708 event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskButton4);
709 }else if((short) HIWORD(wParam) == XBUTTON2){
710 event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskButton5);
714 window->registerMouseClickEvent(false);
715 event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskLeft);
718 window->registerMouseClickEvent(false);
719 event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskMiddle);
722 window->registerMouseClickEvent(false);
723 event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskRight);
726 window->registerMouseClickEvent(false);
727 if ((short) HIWORD(wParam) == XBUTTON1){
728 event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskButton4);
729 }else if((short) HIWORD(wParam) == XBUTTON2){
730 event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskButton5);
734 event = processCursorEvent(GHOST_kEventCursorMove, window);
737 /* The WM_MOUSEWHEEL message is sent to the focus window
738 * when the mouse wheel is rotated. The DefWindowProc
739 * function propagates the message to the window's parent.
740 * There should be no internal forwarding of the message,
741 * since DefWindowProc propagates it up the parent chain
742 * until it finds a window that processes it.
744 event = processWheelEvent(window, wParam, lParam);
747 /* The WM_SETCURSOR message is sent to a window if the mouse causes the cursor
748 * to move within a window and mouse input is not captured.
749 * This means we have to set the cursor shape every time the mouse moves!
750 * The DefWindowProc function uses this message to set the cursor to an
751 * arrow if it is not in the client area.
753 if (LOWORD(lParam) == HTCLIENT) {
754 // Load the current cursor
755 window->loadCursor(window->getCursorVisibility(), window->getCursorShape());
756 // Bypass call to DefWindowProc
760 // Outside of client area show standard cursor
761 window->loadCursor(true, GHOST_kStandardCursorDefault);
765 ////////////////////////////////////////////////////////////////////////
766 // Mouse events, ignored
767 ////////////////////////////////////////////////////////////////////////
769 /* The WM_NCMOUSEMOVE message is posted to a window when the cursor is moved
770 * within the nonclient area of the window. This message is posted to the window
771 * that contains the cursor. If a window has captured the mouse, this message is not posted.
774 /* The WM_NCHITTEST message is sent to a window when the cursor moves, or
775 * when a mouse button is pressed or released. If the mouse is not captured,
776 * the message is sent to the window beneath the cursor. Otherwise, the message
777 * is sent to the window that has captured the mouse.
781 ////////////////////////////////////////////////////////////////////////
782 // Window events, processed
783 ////////////////////////////////////////////////////////////////////////
785 /* The WM_CLOSE message is sent as a signal that a window or an application should terminate. */
786 event = processWindowEvent(GHOST_kEventWindowClose, window);
789 /* The WM_ACTIVATE message is sent to both the window being activated and the window being
790 * deactivated. If the windows use the same input queue, the message is sent synchronously,
791 * first to the window procedure of the top-level window being deactivated, then to the window
792 * procedure of the top-level window being activated. If the windows use different input queues,
793 * the message is sent asynchronously, so the window is activated immediately.
795 event = processWindowEvent(LOWORD(wParam) ? GHOST_kEventWindowActivate : GHOST_kEventWindowDeactivate, window);
796 /* WARNING: Let DefWindowProc handle WM_ACTIVATE, otherwise WM_MOUSEWHEEL
797 will not be dispatched to OUR active window if we minimize one of OUR windows. */
798 lResult = ::DefWindowProc(hwnd, msg, wParam, lParam);
801 /* An application sends the WM_PAINT message when the system or another application
802 * makes a request to paint a portion of an application's window. The message is sent
803 * when the UpdateWindow or RedrawWindow function is called, or by the DispatchMessage
804 * function when the application obtains a WM_PAINT message by using the GetMessage or
805 * PeekMessage function.
807 event = processWindowEvent(GHOST_kEventWindowUpdate, window);
808 ::ValidateRect(hwnd, NULL);
810 case WM_GETMINMAXINFO:
811 /* The WM_GETMINMAXINFO message is sent to a window when the size or
812 * position of the window is about to change. An application can use
813 * this message to override the window's default maximized size and
814 * position, or its default minimum or maximum tracking size.
816 processMinMaxInfo((MINMAXINFO *) lParam);
817 /* Let DefWindowProc handle it. */
820 /* The WM_SIZE message is sent to a window after its size has changed.
821 * The WM_SIZE and WM_MOVE messages are not sent if an application handles the
822 * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient
823 * to perform any move or size change processing during the WM_WINDOWPOSCHANGED
824 * message without calling DefWindowProc.
826 event = processWindowEvent(GHOST_kEventWindowSize, window);
828 case WM_CAPTURECHANGED:
829 window->lostMouseCapture();
832 /* The WM_MOVING message is sent to a window that the user is moving. By processing
833 * this message, an application can monitor the size and position of the drag rectangle
834 * and, if needed, change its size or position.
837 /* The WM_SIZE and WM_MOVE messages are not sent if an application handles the
838 * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient
839 * to perform any move or size change processing during the WM_WINDOWPOSCHANGED
840 * message without calling DefWindowProc.
842 event = processWindowEvent(GHOST_kEventWindowMove, window);
844 ////////////////////////////////////////////////////////////////////////
845 // Window events, ignored
846 ////////////////////////////////////////////////////////////////////////
847 case WM_WINDOWPOSCHANGED:
848 /* The WM_WINDOWPOSCHANGED message is sent to a window whose size, position, or place
849 * in the Z order has changed as a result of a call to the SetWindowPos function or
850 * another window-management function.
851 * The WM_SIZE and WM_MOVE messages are not sent if an application handles the
852 * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient
853 * to perform any move or size change processing during the WM_WINDOWPOSCHANGED
854 * message without calling DefWindowProc.
857 /* An application sends the WM_ERASEBKGND message when the window background must be
858 * erased (for example, when a window is resized). The message is sent to prepare an
859 * invalidated portion of a window for painting.
862 /* An application sends the WM_NCPAINT message to a window when its frame must be painted. */
864 /* The WM_NCACTIVATE message is sent to a window when its nonclient area needs to be changed
865 * to indicate an active or inactive state.
868 /* The WM_DESTROY message is sent when a window is being destroyed. It is sent to the window
869 * procedure of the window being destroyed after the window is removed from the screen.
870 * This message is sent first to the window being destroyed and then to the child windows
871 * (if any) as they are destroyed. During the processing of the message, it can be assumed
872 * that all child windows still exist.
875 /* The WM_NCDESTROY message informs a window that its nonclient area is being destroyed. The
876 * DestroyWindow function sends the WM_NCDESTROY message to the window following the WM_DESTROY
877 * message. WM_DESTROY is used to free the allocated memory object associated with the window.
880 /* The WM_KILLFOCUS message is sent to a window immediately before it loses the keyboard focus. */
882 /* The WM_SHOWWINDOW message is sent to a window when the window is about to be hidden or shown. */
883 case WM_WINDOWPOSCHANGING:
884 /* The WM_WINDOWPOSCHANGING message is sent to a window whose size, position, or place in
885 * the Z order is about to change as a result of a call to the SetWindowPos function or
886 * another window-management function.
889 /* The WM_SETFOCUS message is sent to a window after it has gained the keyboard focus. */
890 case WM_ENTERSIZEMOVE:
891 /* The WM_ENTERSIZEMOVE message is sent one time to a window after it enters the moving
892 * or sizing modal loop. The window enters the moving or sizing modal loop when the user
893 * clicks the window's title bar or sizing border, or when the window passes the
894 * WM_SYSCOMMAND message to the DefWindowProc function and the wParam parameter of the
895 * message specifies the SC_MOVE or SC_SIZE value. The operation is complete when
896 * DefWindowProc returns.
900 ////////////////////////////////////////////////////////////////////////
902 ////////////////////////////////////////////////////////////////////////
904 /* An application sends a WM_GETTEXT message to copy the text that
905 * corresponds to a window into a buffer provided by the caller.
908 /* The WM_ACTIVATEAPP message is sent when a window belonging to a
909 * different application than the active window is about to be activated.
910 * The message is sent to the application whose window is being activated
911 * and to the application whose window is being deactivated.
914 /* The WIN32 docs say:
915 * The WM_TIMER message is posted to the installing thread's message queue
916 * when a timer expires. You can process the message by providing a WM_TIMER
917 * case in the window procedure. Otherwise, the default window procedure will
918 * call the TimerProc callback function specified in the call to the SetTimer
919 * function used to install the timer.
921 * In GHOST, we let DefWindowProc call the timer callback.
924 case WM_BLND_NDOF_AXIS:
926 GHOST_TEventNDOFData ndofdata;
927 system->m_ndofManager->GHOST_NDOFGetDatas(ndofdata);
928 system->m_eventManager->
929 pushEvent(new GHOST_EventNDOF(
930 system->getMilliSeconds(),
931 GHOST_kEventNDOFMotion,
935 case WM_BLND_NDOF_BTN:
937 GHOST_TEventNDOFData ndofdata;
938 system->m_ndofManager->GHOST_NDOFGetDatas(ndofdata);
939 system->m_eventManager->
940 pushEvent(new GHOST_EventNDOF(
941 system->getMilliSeconds(),
942 GHOST_kEventNDOFButton,
949 // Event found for a window before the pointer to the class has been set.
950 GHOST_PRINT("GHOST_SystemWin32::wndProc: GHOST window event before creation\n")
951 /* These are events we typically miss at this point:
952 WM_GETMINMAXINFO 0x24
956 We let DefWindowProc do the work.
961 // Events without valid hwnd
962 GHOST_PRINT("GHOST_SystemWin32::wndProc: event without window\n")
966 system->pushEvent(event);
969 lResult = ::DefWindowProc(hwnd, msg, wParam, lParam);
974 GHOST_TUns8* GHOST_SystemWin32::getClipboard(bool selection) const
979 if ( IsClipboardFormatAvailable(CF_TEXT) && OpenClipboard(NULL) ) {
980 HANDLE hData = GetClipboardData( CF_TEXT );
985 buffer = (char*)GlobalLock( hData );
987 temp_buff = (char*) malloc(strlen(buffer)+1);
988 strcpy(temp_buff, buffer);
990 GlobalUnlock( hData );
993 temp_buff[strlen(buffer)] = '\0';
995 return (GHOST_TUns8*)temp_buff;
1004 void GHOST_SystemWin32::putClipboard(GHOST_TInt8 *buffer, bool selection) const
1006 if(selection) {return;} // for copying the selection, used on X11
1008 if (OpenClipboard(NULL)) {
1015 clipbuffer = LocalAlloc(LMEM_FIXED,((strlen(buffer)+1)));
1016 data = (char*)GlobalLock(clipbuffer);
1018 strcpy(data, (char*)buffer);
1019 data[strlen(buffer)] = '\0';
1020 LocalUnlock(clipbuffer);
1021 SetClipboardData(CF_TEXT,clipbuffer);
1029 const GHOST_TUns8* GHOST_SystemWin32::getSystemDir() const
1031 static char knownpath[MAX_PATH];
1032 HRESULT hResult = SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, SHGFP_TYPE_CURRENT, knownpath);
1034 if (hResult == S_OK)
1036 return (GHOST_TUns8*)knownpath;
1042 const GHOST_TUns8* GHOST_SystemWin32::getUserDir() const
1044 static char knownpath[MAX_PATH];
1045 HRESULT hResult = SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, knownpath);
1047 if (hResult == S_OK)
1049 return (GHOST_TUns8*)knownpath;
1055 const GHOST_TUns8* GHOST_SystemWin32::getBinaryDir() const
1057 static char fullname[MAX_PATH];
1058 if(GetModuleFileName(0, fullname, MAX_PATH)) {
1059 return (GHOST_TUns8*)fullname;