2 * freeglut_main_mswin.c
4 * The Windows-specific mouse cursor related stuff.
6 * Copyright (c) 2012 Stephen J. Baker. All Rights Reserved.
7 * Written by John F. Fay, <fayjf@sourceforge.net>
8 * Creation date: Sat Jan 21, 2012
10 * Permission is hereby granted, free of charge, to any person obtaining a
11 * copy of this software and associated documentation files (the "Software"),
12 * to deal in the Software without restriction, including without limitation
13 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 * and/or sell copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following conditions:
17 * The above copyright notice and this permission notice shall be included
18 * in all copies or substantial portions of the Software.
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
24 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 #include <GL/freeglut.h>
29 #include "../fg_internal.h"
32 extern void fghRedrawWindow ( SFG_Window *window );
34 extern void fgNewWGLCreateContext( SFG_Window* window );
35 extern GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly,
36 unsigned char layer_type );
38 extern void fgPlatformCheckMenuDeactivate();
41 typedef BOOL (WINAPI *pGetTouchInputInfo)(HTOUCHINPUT,UINT,PTOUCHINPUT,int);
42 typedef BOOL (WINAPI *pCloseTouchInputHandle)(HTOUCHINPUT);
43 static pGetTouchInputInfo fghGetTouchInputInfo = (pGetTouchInputInfo)0xDEADBEEF;
44 static pCloseTouchInputHandle fghCloseTouchInputHandle = (pCloseTouchInputHandle)0xDEADBEEF;
48 typedef struct GXDisplayProperties GXDisplayProperties;
49 typedef struct GXKeyList GXKeyList;
52 typedef struct GXKeyList (*GXGETDEFAULTKEYS)(int);
53 typedef int (*GXOPENINPUT)();
55 GXGETDEFAULTKEYS GXGetDefaultKeys_ = NULL;
56 GXOPENINPUT GXOpenInput_ = NULL;
58 struct GXKeyList gxKeyList;
59 #endif /* _WIN32_WCE */
62 /* Get system time, taking special precautions against 32bit timer wrap.
63 We use timeGetTime and not GetTickCount because of its better stability,
64 and because we can increase its granularity (to 1 ms in
65 fgPlatformInitialize). For that reason we can't use GetTickCount64 which
66 wouldn't have the wrap issue.
67 Credit: this is based on code in glibc (https://mail.gnome.org/archives/commits-list/2011-November/msg04588.html)
69 static fg_time_t lastTime32 = 0;
70 static fg_time_t timeEpoch = 0;
71 void fgPlatformInitSystemTime()
73 #if defined(_WIN32_WCE)
74 lastTime32 = GetTickCount();
76 lastTime32 = timeGetTime();
79 fg_time_t fgPlatformSystemTime ( void )
82 #if defined(_WIN32_WCE)
83 currTime32 = GetTickCount();
85 currTime32 = timeGetTime();
87 /* Check if we just wrapped */
88 if (currTime32 < lastTime32)
91 lastTime32 = currTime32;
93 return currTime32 | timeEpoch << 32;
97 void fgPlatformSleepForEvents( fg_time_t msec )
99 MsgWaitForMultipleObjects( 0, NULL, FALSE, (DWORD) msec, QS_ALLINPUT );
103 void fgPlatformProcessSingleEvent ( void )
107 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMainLoopEvent" );
109 while( PeekMessage( &stMsg, NULL, 0, 0, PM_NOREMOVE ) )
111 if( GetMessage( &stMsg, NULL, 0, 0 ) == 0 )
113 if( fgState.ActionOnWindowClose == GLUT_ACTION_EXIT )
118 else if( fgState.ActionOnWindowClose == GLUT_ACTION_GLUTMAINLOOP_RETURNS )
119 fgState.ExecState = GLUT_EXEC_STATE_STOP;
124 TranslateMessage( &stMsg );
125 DispatchMessage( &stMsg );
131 static void fghUpdateWindowStatus(SFG_Window *window, GLboolean visState)
135 if (window->State.Visible != visState)
137 window->State.Visible = visState;
138 INVOKE_WCB( *window, WindowStatus, ( visState ? GLUT_FULLY_RETAINED:GLUT_HIDDEN ) );
141 /* Also set visibility state for children */
142 for( child = ( SFG_Window * )window->Children.First;
144 child = ( SFG_Window * )child->Node.Next )
146 fghUpdateWindowStatus(child, visState);
150 void fghNotifyWindowStatus(SFG_Window *window)
152 INVOKE_WCB( *window, WindowStatus, ( window->State.Visible?GLUT_FULLY_RETAINED:GLUT_HIDDEN ) );
154 /* Don't notify children, they get their own just before first time they're drawn */
157 void fgPlatformMainLoopPreliminaryWork ( void )
164 * Determine a GLUT modifier mask based on MS-WINDOWS system info.
166 static int fgPlatformGetModifiers (void)
169 ( ( ( GetKeyState( VK_LSHIFT ) < 0 ) ||
170 ( GetKeyState( VK_RSHIFT ) < 0 )) ? GLUT_ACTIVE_SHIFT : 0 ) |
171 ( ( ( GetKeyState( VK_LCONTROL ) < 0 ) ||
172 ( GetKeyState( VK_RCONTROL ) < 0 )) ? GLUT_ACTIVE_CTRL : 0 ) |
173 ( ( ( GetKeyState( VK_LMENU ) < 0 ) ||
174 ( GetKeyState( VK_RMENU ) < 0 )) ? GLUT_ACTIVE_ALT : 0 );
177 static LRESULT fghWindowProcKeyPress(SFG_Window *window, UINT uMsg, GLboolean keydown, WPARAM wParam, LPARAM lParam)
179 static unsigned char lControl = 0, lShift = 0, lAlt = 0,
180 rControl = 0, rShift = 0, rAlt = 0;
184 /* if keydown, check for repeat */
185 /* If repeat is globally switched off, it cannot be switched back on per window.
186 * But if it is globally switched on, it can be switched off per window. This matches
187 * GLUT's behavior on X11, but not Nate Robbins' win32 GLUT, as he didn't implement the
188 * global state switch.
190 if( keydown && ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE ) && (HIWORD(lParam) & KF_REPEAT) )
193 /* Remember the current modifiers state so user can query it from their callback */
194 fgState.Modifiers = fgPlatformGetModifiers( );
196 /* Convert the Win32 keystroke codes to GLUTtish way */
197 # define KEY(a,b) case a: keypress = b; break;
201 KEY( VK_F1, GLUT_KEY_F1 );
202 KEY( VK_F2, GLUT_KEY_F2 );
203 KEY( VK_F3, GLUT_KEY_F3 );
204 KEY( VK_F4, GLUT_KEY_F4 );
205 KEY( VK_F5, GLUT_KEY_F5 );
206 KEY( VK_F6, GLUT_KEY_F6 );
207 KEY( VK_F7, GLUT_KEY_F7 );
208 KEY( VK_F8, GLUT_KEY_F8 );
209 KEY( VK_F9, GLUT_KEY_F9 );
210 KEY( VK_F10, GLUT_KEY_F10 );
211 KEY( VK_F11, GLUT_KEY_F11 );
212 KEY( VK_F12, GLUT_KEY_F12 );
213 KEY( VK_PRIOR, GLUT_KEY_PAGE_UP );
214 KEY( VK_NEXT, GLUT_KEY_PAGE_DOWN );
215 KEY( VK_HOME, GLUT_KEY_HOME );
216 KEY( VK_END, GLUT_KEY_END );
217 KEY( VK_LEFT, GLUT_KEY_LEFT );
218 KEY( VK_UP, GLUT_KEY_UP );
219 KEY( VK_RIGHT, GLUT_KEY_RIGHT );
220 KEY( VK_DOWN, GLUT_KEY_DOWN );
221 KEY( VK_INSERT, GLUT_KEY_INSERT );
223 /* handle control, alt and shift. For GLUT, we want to distinguish between left and right presses.
224 * The VK_L* & VK_R* left and right Alt, Ctrl and Shift virtual keys are however only used as parameters to GetAsyncKeyState() and GetKeyState()
225 * so when we get an alt, shift or control keypress here, we manually check whether it was the left or the right
227 #define ASYNC_KEY_EVENT(winKey,glutKey,keyStateVar)\
228 if (!keyStateVar && GetAsyncKeyState ( winKey ))\
233 else if (keyStateVar && !GetAsyncKeyState ( winKey ))\
239 ASYNC_KEY_EVENT(VK_LCONTROL,GLUT_KEY_CTRL_L,lControl);
240 ASYNC_KEY_EVENT(VK_RCONTROL,GLUT_KEY_CTRL_R,rControl);
243 ASYNC_KEY_EVENT(VK_LSHIFT,GLUT_KEY_SHIFT_L,lShift);
244 ASYNC_KEY_EVENT(VK_RSHIFT,GLUT_KEY_SHIFT_R,rShift);
247 ASYNC_KEY_EVENT(VK_LMENU,GLUT_KEY_ALT_L,lAlt);
248 ASYNC_KEY_EVENT(VK_RMENU,GLUT_KEY_ALT_R,rAlt);
250 #undef ASYNC_KEY_EVENT
253 /* The delete key should be treated as an ASCII keypress: */
255 INVOKE_WCB( *window, Keyboard,
256 ( 127, window->State.MouseX, window->State.MouseY )
259 INVOKE_WCB( *window, KeyboardUp,
260 ( 127, window->State.MouseX, window->State.MouseY )
264 #if !defined(_WIN32_WCE)
266 /* keydown displayable characters are handled with WM_CHAR message, but no corresponding up is generated. So get that here. */
272 GetKeyboardState( state );
274 if( ToAscii( (UINT)wParam, 0, state, code, 0 ) == 1 )
277 INVOKE_WCB( *window, KeyboardUp,
279 window->State.MouseX, window->State.MouseY )
285 #if defined(_WIN32_WCE)
286 if(keydown && !(lParam & 0x40000000)) /* Prevent auto-repeat */
288 if(wParam==(unsigned)gxKeyList.vkRight)
289 keypress = GLUT_KEY_RIGHT;
290 else if(wParam==(unsigned)gxKeyList.vkLeft)
291 keypress = GLUT_KEY_LEFT;
292 else if(wParam==(unsigned)gxKeyList.vkUp)
293 keypress = GLUT_KEY_UP;
294 else if(wParam==(unsigned)gxKeyList.vkDown)
295 keypress = GLUT_KEY_DOWN;
296 else if(wParam==(unsigned)gxKeyList.vkA)
297 keypress = GLUT_KEY_F1;
298 else if(wParam==(unsigned)gxKeyList.vkB)
299 keypress = GLUT_KEY_F2;
300 else if(wParam==(unsigned)gxKeyList.vkC)
301 keypress = GLUT_KEY_F3;
302 else if(wParam==(unsigned)gxKeyList.vkStart)
303 keypress = GLUT_KEY_F4;
309 INVOKE_WCB( *window, Special,
311 window->State.MouseX, window->State.MouseY )
314 INVOKE_WCB( *window, SpecialUp,
316 window->State.MouseX, window->State.MouseY )
319 fgState.Modifiers = INVALID_MODIFIERS;
321 /* SYSKEY events should be sent to default window proc for system to handle them */
322 if (uMsg==WM_SYSKEYDOWN || uMsg==WM_SYSKEYUP)
323 return DefWindowProc( window->Window.Handle, uMsg, wParam, lParam );
328 static SFG_Window* fghWindowUnderCursor(SFG_Window *window)
330 /* Check if the current window that the mouse is over is a child window
331 * of the window the message was sent to. Some events only sent to main window,
332 * and when handling some messages, we need to make sure that we process
333 * callbacks on the child window instead. This mirrors how GLUT does things.
334 * returns either the original window or the found child.
336 if (window && window->Children.First) /* This window has childs */
338 SFG_WindowHandleType hwnd;
339 SFG_Window* child_window;
341 /* Get mouse position at time of message */
342 DWORD mouse_pos_dw = GetMessagePos();
343 POINT mouse_pos = {GET_X_LPARAM(mouse_pos_dw), GET_Y_LPARAM(mouse_pos_dw)};
344 ScreenToClient( window->Window.Handle, &mouse_pos );
346 hwnd = ChildWindowFromPoint(window->Window.Handle, mouse_pos);
347 if (hwnd && hwnd!=window->Window.Handle) /* can be NULL if mouse outside parent by the time we get here, or can be same as parent if we didn't find a child */
349 child_window = fgWindowByHandle(hwnd);
350 if (child_window) /* Verify we got a FreeGLUT window */
352 /* ChildWindowFromPoint only searches immediate children, so search again to see if actually in grandchild or further descendant */
353 window = fghWindowUnderCursor(child_window);
362 * The window procedure for handling Win32 events
364 LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
368 static int setCaptureActive = 0;
370 FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Event Handler" ) ;
372 window = fgWindowByHandle( hWnd );
374 if ( ( window == NULL ) && ( uMsg != WM_CREATE ) )
375 return DefWindowProc( hWnd, uMsg, wParam, lParam );
377 /* printf ( "Window %3d message <%04x> %12d %12d\n", window?window->ID:0,
378 uMsg, wParam, lParam ); */
383 /* The window structure is passed as the creation structure parameter... */
384 window = (SFG_Window *) (((LPCREATESTRUCT) lParam)->lpCreateParams);
385 FREEGLUT_INTERNAL_ERROR_EXIT ( ( window != NULL ), "Cannot create window",
386 "fgPlatformWindowProc" );
388 window->Window.Handle = hWnd;
389 window->Window.pContext.Device = GetDC( hWnd );
392 unsigned int current_DisplayMode = fgState.DisplayMode;
393 fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH;
394 #if !defined(_WIN32_WCE)
395 fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE );
397 fgState.DisplayMode = current_DisplayMode;
399 if( fgStructure.MenuContext )
400 wglMakeCurrent( window->Window.pContext.Device,
401 fgStructure.MenuContext->MContext
405 fgStructure.MenuContext =
406 (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) );
407 fgStructure.MenuContext->MContext =
408 wglCreateContext( window->Window.pContext.Device );
411 /* window->Window.Context = wglGetCurrentContext (); */
412 window->Window.Context = wglCreateContext( window->Window.pContext.Device );
416 #if !defined(_WIN32_WCE)
417 fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE );
420 if( ! fgState.UseCurrentContext )
421 window->Window.Context =
422 wglCreateContext( window->Window.pContext.Device );
425 window->Window.Context = wglGetCurrentContext( );
426 if( ! window->Window.Context )
427 window->Window.Context =
428 wglCreateContext( window->Window.pContext.Device );
431 #if !defined(_WIN32_WCE)
432 fgNewWGLCreateContext( window );
436 window->State.NeedToResize = GL_TRUE;
437 /* if we used CW_USEDEFAULT (thats a negative value) for the size
438 * of the window, query the window now for the size at which it
441 if( ( window->State.Width < 0 ) || ( window->State.Height < 0 ) )
443 SFG_Window *current_window = fgStructure.CurrentWindow;
445 fgSetWindow( window );
446 window->State.Width = glutGet( GLUT_WINDOW_WIDTH );
447 window->State.Height = glutGet( GLUT_WINDOW_HEIGHT );
448 fgSetWindow( current_window );
451 ReleaseDC( window->Window.Handle, window->Window.pContext.Device );
453 #if defined(_WIN32_WCE)
454 /* Take over button handling */
456 HINSTANCE dxDllLib=LoadLibrary(_T("gx.dll"));
459 GXGetDefaultKeys_=(GXGETDEFAULTKEYS)GetProcAddress(dxDllLib, _T("?GXGetDefaultKeys@@YA?AUGXKeyList@@H@Z"));
460 GXOpenInput_=(GXOPENINPUT)GetProcAddress(dxDllLib, _T("?GXOpenInput@@YAHXZ"));
465 if(GXGetDefaultKeys_)
466 gxKeyList = (*GXGetDefaultKeys_)(GX_LANDSCAPEKEYS);
469 #endif /* defined(_WIN32_WCE) */
473 /* printf("WM_SIZE (ID: %i): wParam: %i, new size: %ix%i \n",window->ID,wParam,LOWORD(lParam),HIWORD(lParam)); */
475 /* Update visibility state of the window */
476 if (wParam==SIZE_MINIMIZED)
477 fghUpdateWindowStatus(window,GL_FALSE);
478 else if (wParam==SIZE_RESTORED && !window->State.Visible)
479 fghUpdateWindowStatus(window,GL_TRUE);
481 /* Check window visible, we don't want to resize when the user or glutIconifyWindow minimized the window */
482 if( window->State.Visible )
484 /* get old values first to compare to below */
485 int width = window->State.Width, height=window->State.Height;
486 #if defined(_WIN32_WCE)
487 window->State.Width = HIWORD(lParam);
488 window->State.Height = LOWORD(lParam);
490 window->State.Width = LOWORD(lParam);
491 window->State.Height = HIWORD(lParam);
492 #endif /* defined(_WIN32_WCE) */
494 if (width!=window->State.Width || height!=window->State.Height)
495 /* Something changed, need to resize */
496 window->State.NeedToResize = GL_TRUE;
499 /* according to docs, should return 0 */
505 SFG_Window* saved_window = fgStructure.CurrentWindow;
508 /* Check window is minimized, we don't want to call the position callback when the user or glutIconifyWindow minimized the window */
509 if (!IsIconic(window->Window.Handle))
511 /* Get top-left of non-client area of window, matching coordinates of
512 * glutInitPosition and glutPositionWindow, but not those of
513 * glutGet(GLUT_WINDOW_X) and glutGet(GLUT_WINDOW_Y), which return
514 * top-left of client area.
516 GetWindowRect( window->Window.Handle, &windowRect );
520 /* For child window, we should return relative to upper-left
521 * of parent's client area.
523 POINT topleft = {windowRect.left,windowRect.top};
525 ScreenToClient(window->Parent->Window.Handle,&topleft);
526 windowRect.left = topleft.x;
527 windowRect.top = topleft.y;
530 INVOKE_WCB( *window, Position, ( windowRect.left, windowRect.top ) );
531 fgSetWindow(saved_window);
535 /* according to docs, should return 0 */
540 /* printf("WM_SETFOCUS: %p\n", window ); */
542 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
544 SetActiveWindow( window->Window.Handle );
545 UpdateWindow ( hWnd );
551 /* printf("WM_KILLFOCUS: %p\n", window ); */
552 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
554 /* Check if there are any open menus that need to be closed */
555 fgPlatformCheckMenuDeactivate();
561 //printf("WM_ACTIVATE: %x (ID: %i) %d %d\n",lParam, window->ID, HIWORD(wParam), LOWORD(wParam));
562 if (LOWORD(wParam) != WA_INACTIVE)
564 /* printf("WM_ACTIVATE: fgSetCursor( %p, %d)\n", window,
565 window->State.Cursor ); */
566 fgSetCursor( window, window->State.Cursor );
569 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
574 /* printf ( "Cursor event %x %x %x %x\n", window, window->State.Cursor, lParam, wParam ) ; */
575 if( LOWORD( lParam ) == HTCLIENT )
577 if (!window->State.pWState.MouseTracking)
581 /* Cursor just entered window, set cursor look */
582 fgSetCursor ( window, window->State.Cursor ) ;
584 /* If an EntryFunc callback is specified by the user, also
585 * invoke that callback and start mouse tracking so that
586 * we get a WM_MOUSELEAVE message
588 if (FETCH_WCB( *window, Entry ))
590 INVOKE_WCB( *window, Entry, ( GLUT_ENTERED ) );
592 tme.cbSize = sizeof(TRACKMOUSEEVENT);
593 tme.dwFlags = TME_LEAVE;
594 tme.hwndTrack = window->Window.Handle;
595 TrackMouseEvent(&tme);
597 window->State.pWState.MouseTracking = GL_TRUE;
602 /* Only pass non-client WM_SETCURSOR to DefWindowProc, or we get WM_SETCURSOR on parents of children as well */
603 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
608 /* NB: This message is only received when a EntryFunc callback
609 * is specified by the user, as that is the only condition under
610 * which mouse tracking is setup in WM_SETCURSOR handler above
612 SFG_Window* saved_window = fgStructure.CurrentWindow;
613 INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) );
614 fgSetWindow(saved_window);
616 window->State.pWState.MouseTracking = GL_FALSE;
617 lRet = 0; /* As per docs, must return zero */
622 /* printf("WM_SHOWWINDOW, shown? %i, source: %i\n",wParam,lParam); */
625 fghUpdateWindowStatus(window, GL_TRUE);
626 window->State.Redisplay = GL_TRUE;
630 fghUpdateWindowStatus(window, GL_FALSE);
631 window->State.Redisplay = GL_FALSE;
638 /* Turn on the visibility in case it was turned off somehow */
639 window->State.Visible = GL_TRUE;
641 InvalidateRect( hWnd, NULL, GL_FALSE ); /* Make sure whole window is repainted. Bit of a hack, but a safe one from what google turns up... */
642 BeginPaint( hWnd, &ps );
643 fghRedrawWindow( window );
644 EndPaint( hWnd, &ps );
649 fgDestroyWindow ( window );
650 if ( fgState.ActionOnWindowClose != GLUT_ACTION_CONTINUE_EXECUTION )
656 * The window already got destroyed, so don't bother with it.
662 #if defined(_WIN32_WCE)
663 window->State.MouseX = 320-HIWORD( lParam );
664 window->State.MouseY = LOWORD( lParam );
666 window->State.MouseX = LOWORD( lParam );
667 window->State.MouseY = HIWORD( lParam );
668 #endif /* defined(_WIN32_WCE) */
669 /* Restrict to [-32768, 32767] to match X11 behaviour */
670 /* See comment in "freeglut_developer" mailing list 10/4/04 */
671 if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
672 if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;
674 if ( window->ActiveMenu )
676 fgUpdateMenuHighlight( window->ActiveMenu );
680 fgState.Modifiers = fgPlatformGetModifiers( );
682 if( ( wParam & MK_LBUTTON ) ||
683 ( wParam & MK_MBUTTON ) ||
684 ( wParam & MK_RBUTTON ) )
685 INVOKE_WCB( *window, Motion, ( window->State.MouseX,
686 window->State.MouseY ) );
688 INVOKE_WCB( *window, Passive, ( window->State.MouseX,
689 window->State.MouseY ) );
691 fgState.Modifiers = INVALID_MODIFIERS;
702 GLboolean pressed = GL_TRUE;
705 #if defined(_WIN32_WCE)
706 window->State.MouseX = 320-HIWORD( lParam );
707 window->State.MouseY = LOWORD( lParam );
709 window->State.MouseX = LOWORD( lParam );
710 window->State.MouseY = HIWORD( lParam );
711 #endif /* defined(_WIN32_WCE) */
713 /* Restrict to [-32768, 32767] to match X11 behaviour */
714 /* See comment in "freeglut_developer" mailing list 10/4/04 */
715 if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
716 if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;
722 button = GLUT_LEFT_BUTTON;
726 button = GLUT_MIDDLE_BUTTON;
730 button = GLUT_RIGHT_BUTTON;
734 button = GLUT_LEFT_BUTTON;
738 button = GLUT_MIDDLE_BUTTON;
742 button = GLUT_RIGHT_BUTTON;
750 #if !defined(_WIN32_WCE)
751 if( GetSystemMetrics( SM_SWAPBUTTON ) )
753 if( button == GLUT_LEFT_BUTTON )
754 button = GLUT_RIGHT_BUTTON;
756 if( button == GLUT_RIGHT_BUTTON )
757 button = GLUT_LEFT_BUTTON;
759 #endif /* !defined(_WIN32_WCE) */
762 return DefWindowProc( hWnd, uMsg, lParam, wParam );
765 * Do not execute the application's mouse callback if a menu
766 * is hooked to this button. In that case an appropriate
767 * private call should be generated.
769 if( fgCheckActiveMenu( window, button, pressed,
770 window->State.MouseX, window->State.MouseY ) )
773 /* Set capture so that the window captures all the mouse messages
775 * The mouse is not released from the window until all buttons have
776 * been released, even if the user presses a button in another window.
777 * This is consistent with the behavior on X11.
779 if ( pressed == GL_TRUE )
781 if (!setCaptureActive)
782 SetCapture ( window->Window.Handle ) ;
783 setCaptureActive = 1; /* Set to false in WM_CAPTURECHANGED handler */
785 else if (!GetAsyncKeyState(VK_LBUTTON) && !GetAsyncKeyState(VK_MBUTTON) && !GetAsyncKeyState(VK_RBUTTON))
786 /* Make sure all mouse buttons are released before releasing capture */
789 if( ! FETCH_WCB( *window, Mouse ) )
792 fgSetWindow( window );
793 fgState.Modifiers = fgPlatformGetModifiers( );
798 pressed ? GLUT_DOWN : GLUT_UP,
799 window->State.MouseX,
804 fgState.Modifiers = INVALID_MODIFIERS;
806 /* As per docs, should return zero */
813 SFG_Window *child_window = NULL;
814 int wheel_number = 0; /* Only one scroll wheel on windows */
815 /* int GET_KEYSTATE_WPARAM( wParam ); */
816 short ticks = GET_WHEEL_DELTA_WPARAM( wParam );
818 window = fghWindowUnderCursor(window);
820 fgState.MouseWheelTicks += ticks;
821 if ( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA )
823 int direction = ( fgState.MouseWheelTicks > 0 ) ? 1 : -1;
825 if( ! FETCH_WCB( *window, MouseWheel ) &&
826 ! FETCH_WCB( *window, Mouse ) )
829 fgSetWindow( window );
830 fgState.Modifiers = fgPlatformGetModifiers( );
832 while( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA )
834 if( FETCH_WCB( *window, MouseWheel ) )
835 INVOKE_WCB( *window, MouseWheel,
838 window->State.MouseX,
842 else /* No mouse wheel, call the mouse button callback twice */
845 * Map wheel zero to button 3 and 4; +1 to 3, -1 to 4
846 * " " one +1 to 5, -1 to 6, ...
848 * XXX The below assumes that you have no more than 3 mouse
849 * XXX buttons. Sorry.
851 int button = wheel_number * 2 + 3;
854 INVOKE_WCB( *window, Mouse,
856 window->State.MouseX, window->State.MouseY )
858 INVOKE_WCB( *window, Mouse,
860 window->State.MouseX, window->State.MouseY )
864 fgState.MouseWheelTicks -= WHEEL_DELTA * direction;
867 fgState.Modifiers = INVALID_MODIFIERS;
869 /* Per docs, should return zero */
877 window = fghWindowUnderCursor(window);
878 lRet = fghWindowProcKeyPress(window,uMsg,GL_TRUE,wParam,lParam);
885 window = fghWindowUnderCursor(window);
886 lRet = fghWindowProcKeyPress(window,uMsg,GL_FALSE,wParam,lParam);
893 window = fghWindowUnderCursor(window);
895 if( (fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE) && (HIWORD(lParam) & KF_REPEAT) )
898 fgState.Modifiers = fgPlatformGetModifiers( );
899 INVOKE_WCB( *window, Keyboard,
901 window->State.MouseX, window->State.MouseY )
903 fgState.Modifiers = INVALID_MODIFIERS;
907 case WM_CAPTURECHANGED:
908 if (!lParam || !fgWindowByHandle((HWND)lParam))
909 /* Capture released or capture taken by non-FreeGLUT window */
910 setCaptureActive = 0;
911 /* Docs advise a redraw */
912 InvalidateRect( hWnd, NULL, GL_FALSE );
914 lRet = 0; /* Per docs, should return zero */
917 /* Other messages that I have seen and which are not handled already */
918 case WM_SETTEXT: /* 0x000c */
919 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
920 /* Pass it on to "DefWindowProc" to set the window text */
923 case WM_GETTEXT: /* 0x000d */
924 /* Ideally we would copy the title of the window into "lParam" */
925 /* strncpy ( (char *)lParam, "Window Title", wParam );
926 lRet = ( wParam > 12 ) ? 12 : wParam; */
927 /* the number of characters copied */
928 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
931 case WM_GETTEXTLENGTH: /* 0x000e */
932 /* Ideally we would get the length of the title of the window */
934 /* the number of characters in "Window Title\0" (see above) */
937 case WM_ERASEBKGND: /* 0x0014 */
938 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
941 #if !defined(_WIN32_WCE)
942 case WM_SYNCPAINT: /* 0x0088 */
943 /* Another window has moved, need to update this one */
944 window->State.Redisplay = GL_TRUE;
945 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
946 /* Help screen says this message must be passed to "DefWindowProc" */
949 case WM_NCPAINT: /* 0x0085 */
950 /* Need to update the border of this window */
951 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
952 /* Pass it on to "DefWindowProc" to repaint a standard border */
955 case WM_SYSCOMMAND : /* 0x0112 */
958 * We have received a system command message. Try to act on it.
959 * The commands are passed in through the "wParam" parameter:
960 * The least significant digit seems to be which edge of the window
961 * is being used for a resize event:
965 * Congratulations and thanks to Richard Rauch for figuring this out..
967 switch ( wParam & 0xfff0 )
976 /* User has clicked on the "-" to minimize the window */
977 /* Turning off the visibility is handled in WM_SIZE handler */
991 /* Followed very closely by a WM_CLOSE message */
1015 case SC_SCREENSAVE :
1021 #if(WINVER >= 0x0400)
1025 case SC_MONITORPOWER :
1028 case SC_CONTEXTHELP :
1030 #endif /* WINVER >= 0x0400 */
1034 fgWarning( "Unknown wParam type 0x%x", wParam );
1039 #endif /* !defined(_WIN32_WCE) */
1041 /* We need to pass the message on to the operating system as well */
1042 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1046 /* handle multi-touch messages */
1049 unsigned int numInputs = (unsigned int)wParam;
1051 TOUCHINPUT* ti = (TOUCHINPUT*)malloc( sizeof(TOUCHINPUT)*numInputs);
1053 if (fghGetTouchInputInfo == (pGetTouchInputInfo)0xDEADBEEF) {
1054 fghGetTouchInputInfo = (pGetTouchInputInfo)GetProcAddress(GetModuleHandle("user32"),"GetTouchInputInfo");
1055 fghCloseTouchInputHandle = (pCloseTouchInputHandle)GetProcAddress(GetModuleHandle("user32"),"CloseTouchInputHandle");
1058 if (!fghGetTouchInputInfo) {
1063 if (fghGetTouchInputInfo( (HTOUCHINPUT)lParam, numInputs, ti, sizeof(TOUCHINPUT) )) {
1064 /* Handle each contact point */
1065 for (i = 0; i < numInputs; ++i ) {
1068 tp.x = TOUCH_COORD_TO_PIXEL(ti[i].x);
1069 tp.y = TOUCH_COORD_TO_PIXEL(ti[i].y);
1070 ScreenToClient( hWnd, &tp );
1072 ti[i].dwID = ti[i].dwID * 2;
1074 if (ti[i].dwFlags & TOUCHEVENTF_DOWN) {
1075 INVOKE_WCB( *window, MultiEntry, ( ti[i].dwID, GLUT_ENTERED ) );
1076 INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_DOWN ) );
1077 } else if (ti[i].dwFlags & TOUCHEVENTF_MOVE) {
1078 INVOKE_WCB( *window, MultiMotion, ( ti[i].dwID, tp.x, tp.y ) );
1079 } else if (ti[i].dwFlags & TOUCHEVENTF_UP) {
1080 INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_UP ) );
1081 INVOKE_WCB( *window, MultiEntry, ( ti[i].dwID, GLUT_LEFT ) );
1085 fghCloseTouchInputHandle((HTOUCHINPUT)lParam);
1087 lRet = 0; /*DefWindowProc( hWnd, uMsg, wParam, lParam );*/
1092 /* Handle unhandled messages */
1093 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );