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 void fgPlatformMainLoopPreliminaryWork ( void )
133 SFG_Window *window = (SFG_Window *)fgStructure.Windows.First ;
136 * Processing before the main loop: If there is a window which is open and
137 * which has a visibility callback, call it. I know this is an ugly hack,
138 * but I'm not sure what else to do about it. Ideally we should leave
139 * something uninitialized in the create window code and initialize it in
140 * the main loop, and have that initialization create a "WM_ACTIVATE"
141 * message. Then we would put the visibility callback code in the
142 * "case WM_ACTIVATE" block below. - John Fay -- 10/24/02
146 if ( FETCH_WCB( *window, WindowStatus ) )
148 SFG_Window *current_window = fgStructure.CurrentWindow ;
150 INVOKE_WCB( *window, WindowStatus, ( window->State.Visible?GLUT_FULLY_RETAINED:GLUT_HIDDEN ) );
151 fgSetWindow( current_window );
154 window = (SFG_Window *)window->Node.Next ;
160 * Determine a GLUT modifier mask based on MS-WINDOWS system info.
162 static int fgPlatformGetModifiers (void)
165 ( ( ( GetKeyState( VK_LSHIFT ) < 0 ) ||
166 ( GetKeyState( VK_RSHIFT ) < 0 )) ? GLUT_ACTIVE_SHIFT : 0 ) |
167 ( ( ( GetKeyState( VK_LCONTROL ) < 0 ) ||
168 ( GetKeyState( VK_RCONTROL ) < 0 )) ? GLUT_ACTIVE_CTRL : 0 ) |
169 ( ( ( GetKeyState( VK_LMENU ) < 0 ) ||
170 ( GetKeyState( VK_RMENU ) < 0 )) ? GLUT_ACTIVE_ALT : 0 );
173 static LRESULT fghWindowProcKeyPress(SFG_Window *window, UINT uMsg, GLboolean keydown, WPARAM wParam, LPARAM lParam)
175 static unsigned char lControl = 0, lShift = 0, lAlt = 0,
176 rControl = 0, rShift = 0, rAlt = 0;
180 /* if keydown, check for repeat */
181 /* If repeat is globally switched off, it cannot be switched back on per window.
182 * But if it is globally switched on, it can be switched off per window. This matches
183 * GLUT's behavior on X11, but not Nate Robbins' win32 GLUT, as he didn't implement the
184 * global state switch.
186 if( keydown && ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE ) && (HIWORD(lParam) & KF_REPEAT) )
189 /* Remember the current modifiers state so user can query it from their callback */
190 fgState.Modifiers = fgPlatformGetModifiers( );
192 /* Convert the Win32 keystroke codes to GLUTtish way */
193 # define KEY(a,b) case a: keypress = b; break;
197 KEY( VK_F1, GLUT_KEY_F1 );
198 KEY( VK_F2, GLUT_KEY_F2 );
199 KEY( VK_F3, GLUT_KEY_F3 );
200 KEY( VK_F4, GLUT_KEY_F4 );
201 KEY( VK_F5, GLUT_KEY_F5 );
202 KEY( VK_F6, GLUT_KEY_F6 );
203 KEY( VK_F7, GLUT_KEY_F7 );
204 KEY( VK_F8, GLUT_KEY_F8 );
205 KEY( VK_F9, GLUT_KEY_F9 );
206 KEY( VK_F10, GLUT_KEY_F10 );
207 KEY( VK_F11, GLUT_KEY_F11 );
208 KEY( VK_F12, GLUT_KEY_F12 );
209 KEY( VK_PRIOR, GLUT_KEY_PAGE_UP );
210 KEY( VK_NEXT, GLUT_KEY_PAGE_DOWN );
211 KEY( VK_HOME, GLUT_KEY_HOME );
212 KEY( VK_END, GLUT_KEY_END );
213 KEY( VK_LEFT, GLUT_KEY_LEFT );
214 KEY( VK_UP, GLUT_KEY_UP );
215 KEY( VK_RIGHT, GLUT_KEY_RIGHT );
216 KEY( VK_DOWN, GLUT_KEY_DOWN );
217 KEY( VK_INSERT, GLUT_KEY_INSERT );
219 /* handle control, alt and shift. For GLUT, we want to distinguish between left and right presses.
220 * The VK_L* & VK_R* left and right Alt, Ctrl and Shift virtual keys are however only used as parameters to GetAsyncKeyState() and GetKeyState()
221 * so when we get an alt, shift or control keypress here, we manually check whether it was the left or the right
223 #define ASYNC_KEY_EVENT(winKey,glutKey,keyStateVar)\
224 if (!keyStateVar && GetAsyncKeyState ( winKey ))\
229 else if (keyStateVar && !GetAsyncKeyState ( winKey ))\
235 ASYNC_KEY_EVENT(VK_LCONTROL,GLUT_KEY_CTRL_L,lControl);
236 ASYNC_KEY_EVENT(VK_RCONTROL,GLUT_KEY_CTRL_R,rControl);
239 ASYNC_KEY_EVENT(VK_LSHIFT,GLUT_KEY_SHIFT_L,lShift);
240 ASYNC_KEY_EVENT(VK_RSHIFT,GLUT_KEY_SHIFT_R,rShift);
243 ASYNC_KEY_EVENT(VK_LMENU,GLUT_KEY_ALT_L,lAlt);
244 ASYNC_KEY_EVENT(VK_RMENU,GLUT_KEY_ALT_R,rAlt);
246 #undef ASYNC_KEY_EVENT
249 /* The delete key should be treated as an ASCII keypress: */
251 INVOKE_WCB( *window, Keyboard,
252 ( 127, window->State.MouseX, window->State.MouseY )
255 INVOKE_WCB( *window, KeyboardUp,
256 ( 127, window->State.MouseX, window->State.MouseY )
260 #if !defined(_WIN32_WCE)
262 /* keydown displayable characters are handled with WM_CHAR message, but no corresponding up is generated. So get that here. */
268 GetKeyboardState( state );
270 if( ToAscii( (UINT)wParam, 0, state, code, 0 ) == 1 )
273 INVOKE_WCB( *window, KeyboardUp,
275 window->State.MouseX, window->State.MouseY )
281 #if defined(_WIN32_WCE)
282 if(keydown && !(lParam & 0x40000000)) /* Prevent auto-repeat */
284 if(wParam==(unsigned)gxKeyList.vkRight)
285 keypress = GLUT_KEY_RIGHT;
286 else if(wParam==(unsigned)gxKeyList.vkLeft)
287 keypress = GLUT_KEY_LEFT;
288 else if(wParam==(unsigned)gxKeyList.vkUp)
289 keypress = GLUT_KEY_UP;
290 else if(wParam==(unsigned)gxKeyList.vkDown)
291 keypress = GLUT_KEY_DOWN;
292 else if(wParam==(unsigned)gxKeyList.vkA)
293 keypress = GLUT_KEY_F1;
294 else if(wParam==(unsigned)gxKeyList.vkB)
295 keypress = GLUT_KEY_F2;
296 else if(wParam==(unsigned)gxKeyList.vkC)
297 keypress = GLUT_KEY_F3;
298 else if(wParam==(unsigned)gxKeyList.vkStart)
299 keypress = GLUT_KEY_F4;
305 INVOKE_WCB( *window, Special,
307 window->State.MouseX, window->State.MouseY )
310 INVOKE_WCB( *window, SpecialUp,
312 window->State.MouseX, window->State.MouseY )
315 fgState.Modifiers = INVALID_MODIFIERS;
317 /* SYSKEY events should be sent to default window proc for system to handle them */
318 if (uMsg==WM_SYSKEYDOWN || uMsg==WM_SYSKEYUP)
319 return DefWindowProc( window->Window.Handle, uMsg, wParam, lParam );
324 static SFG_Window* fghWindowUnderCursor(SFG_Window *window)
326 /* Check if the current window that the mouse is over is a child window
327 * of the window the message was sent to. Some events only sent to main window,
328 * and when handling some messages, we need to make sure that we process
329 * callbacks on the child window instead. This mirrors how GLUT does things.
330 * returns either the original window or the found child.
332 if (window && window->Children.First) /* This window has childs */
334 SFG_WindowHandleType hwnd;
335 SFG_Window* child_window;
337 /* Get mouse position at time of message */
338 DWORD mouse_pos_dw = GetMessagePos();
339 POINT mouse_pos = {GET_X_LPARAM(mouse_pos_dw), GET_Y_LPARAM(mouse_pos_dw)};
340 ScreenToClient( window->Window.Handle, &mouse_pos );
342 hwnd = ChildWindowFromPoint(window->Window.Handle, mouse_pos);
343 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 */
345 child_window = fgWindowByHandle(hwnd);
346 if (child_window) /* Verify we got a FreeGLUT window */
348 /* ChildWindowFromPoint only searches immediate children, so search again to see if actually in grandchild or further descendant */
349 window = fghWindowUnderCursor(child_window);
358 * The window procedure for handling Win32 events
360 LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
364 static int setCaptureActive = 0;
366 FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Event Handler" ) ;
368 window = fgWindowByHandle( hWnd );
370 if ( ( window == NULL ) && ( uMsg != WM_CREATE ) )
371 return DefWindowProc( hWnd, uMsg, wParam, lParam );
373 /* printf ( "Window %3d message <%04x> %12d %12d\n", window?window->ID:0,
374 uMsg, wParam, lParam ); */
379 /* The window structure is passed as the creation structure parameter... */
380 window = (SFG_Window *) (((LPCREATESTRUCT) lParam)->lpCreateParams);
381 FREEGLUT_INTERNAL_ERROR_EXIT ( ( window != NULL ), "Cannot create window",
382 "fgPlatformWindowProc" );
384 window->Window.Handle = hWnd;
385 window->Window.pContext.Device = GetDC( hWnd );
388 unsigned int current_DisplayMode = fgState.DisplayMode;
389 fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH;
390 #if !defined(_WIN32_WCE)
391 fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE );
393 fgState.DisplayMode = current_DisplayMode;
395 if( fgStructure.MenuContext )
396 wglMakeCurrent( window->Window.pContext.Device,
397 fgStructure.MenuContext->MContext
401 fgStructure.MenuContext =
402 (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) );
403 fgStructure.MenuContext->MContext =
404 wglCreateContext( window->Window.pContext.Device );
407 /* window->Window.Context = wglGetCurrentContext (); */
408 window->Window.Context = wglCreateContext( window->Window.pContext.Device );
412 #if !defined(_WIN32_WCE)
413 fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE );
416 if( ! fgState.UseCurrentContext )
417 window->Window.Context =
418 wglCreateContext( window->Window.pContext.Device );
421 window->Window.Context = wglGetCurrentContext( );
422 if( ! window->Window.Context )
423 window->Window.Context =
424 wglCreateContext( window->Window.pContext.Device );
427 #if !defined(_WIN32_WCE)
428 fgNewWGLCreateContext( window );
432 window->State.NeedToResize = GL_TRUE;
433 /* if we used CW_USEDEFAULT (thats a negative value) for the size
434 * of the window, query the window now for the size at which it
437 if( ( window->State.Width < 0 ) || ( window->State.Height < 0 ) )
439 SFG_Window *current_window = fgStructure.CurrentWindow;
441 fgSetWindow( window );
442 window->State.Width = glutGet( GLUT_WINDOW_WIDTH );
443 window->State.Height = glutGet( GLUT_WINDOW_HEIGHT );
444 fgSetWindow( current_window );
447 ReleaseDC( window->Window.Handle, window->Window.pContext.Device );
449 #if defined(_WIN32_WCE)
450 /* Take over button handling */
452 HINSTANCE dxDllLib=LoadLibrary(_T("gx.dll"));
455 GXGetDefaultKeys_=(GXGETDEFAULTKEYS)GetProcAddress(dxDllLib, _T("?GXGetDefaultKeys@@YA?AUGXKeyList@@H@Z"));
456 GXOpenInput_=(GXOPENINPUT)GetProcAddress(dxDllLib, _T("?GXOpenInput@@YAHXZ"));
461 if(GXGetDefaultKeys_)
462 gxKeyList = (*GXGetDefaultKeys_)(GX_LANDSCAPEKEYS);
465 #endif /* defined(_WIN32_WCE) */
470 * If the window is visible, then it is the user manually resizing it.
471 * If it is not, then it is the system sending us a dummy resize with
472 * zero dimensions on a "glutIconifyWindow" call.
474 if( window->State.Visible )
476 /* get old values first to compare to below */
477 int width = window->State.Width, height=window->State.Height;
478 #if defined(_WIN32_WCE)
479 window->State.Width = HIWORD(lParam);
480 window->State.Height = LOWORD(lParam);
482 window->State.Width = LOWORD(lParam);
483 window->State.Height = HIWORD(lParam);
484 #endif /* defined(_WIN32_WCE) */
486 if (width!=window->State.Width || height!=window->State.Height)
487 /* Something changed, need to resize */
488 window->State.NeedToResize = GL_TRUE;
495 SFG_Window* saved_window = fgStructure.CurrentWindow;
497 GetWindowRect( window->Window.Handle, &windowRect );
501 /* For child window, we should return relative to upper-left
502 * of parent's client area.
504 POINT topleft = {windowRect.left,windowRect.top};
506 ScreenToClient(window->Parent->Window.Handle,&topleft);
507 windowRect.left = topleft.x;
508 windowRect.top = topleft.y;
511 INVOKE_WCB( *window, Position, ( windowRect.left, windowRect.top ) );
512 fgSetWindow(saved_window);
517 /* printf("WM_SETFOCUS: %p\n", window ); */
519 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
521 SetActiveWindow( window->Window.Handle );
522 UpdateWindow ( hWnd );
528 /* printf("WM_KILLFOCUS: %p\n", window ); */
529 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
531 /* Check if there are any open menus that need to be closed */
532 fgPlatformCheckMenuDeactivate();
538 //printf("WM_ACTIVATE: %x %d %d\n",lParam, HIWORD(wParam), LOWORD(wParam));
539 if (LOWORD(wParam) != WA_INACTIVE)
541 /* printf("WM_ACTIVATE: fgSetCursor( %p, %d)\n", window,
542 window->State.Cursor ); */
543 fgSetCursor( window, window->State.Cursor );
546 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
551 /* printf ( "Cursor event %x %x %x %x\n", window, window->State.Cursor, lParam, wParam ) ; */
552 if( LOWORD( lParam ) == HTCLIENT )
554 if (!window->State.pWState.MouseTracking)
558 /* Cursor just entered window, set cursor look */
559 fgSetCursor ( window, window->State.Cursor ) ;
561 /* If an EntryFunc callback is specified by the user, also
562 * invoke that callback and start mouse tracking so that
563 * we get a WM_MOUSELEAVE message
565 if (FETCH_WCB( *window, Entry ))
567 INVOKE_WCB( *window, Entry, ( GLUT_ENTERED ) );
569 tme.cbSize = sizeof(TRACKMOUSEEVENT);
570 tme.dwFlags = TME_LEAVE;
571 tme.hwndTrack = window->Window.Handle;
572 TrackMouseEvent(&tme);
574 window->State.pWState.MouseTracking = GL_TRUE;
579 /* Only pass non-client WM_SETCURSOR to DefWindowProc, or we get WM_SETCURSOR on parents of children as well */
580 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
585 /* NB: This message is only received when a EntryFunc callback
586 * is specified by the user, as that is the only condition under
587 * which mouse tracking is setup in WM_SETCURSOR handler above
589 SFG_Window* saved_window = fgStructure.CurrentWindow;
590 INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) );
591 fgSetWindow(saved_window);
593 window->State.pWState.MouseTracking = GL_FALSE;
594 lRet = 0; /* As per docs, must return zero */
599 window->State.Visible = GL_TRUE;
600 window->State.Redisplay = GL_TRUE;
606 /* Turn on the visibility in case it was turned off somehow */
607 window->State.Visible = GL_TRUE;
608 InvalidateRect( hWnd, NULL, GL_FALSE ); /* Make sure whole window is repainted. Bit of a hack, but a safe one from what google turns up... */
609 BeginPaint( hWnd, &ps );
610 fghRedrawWindow( window );
611 EndPaint( hWnd, &ps );
616 fgDestroyWindow ( window );
617 if ( fgState.ActionOnWindowClose != GLUT_ACTION_CONTINUE_EXECUTION )
623 * The window already got destroyed, so don't bother with it.
629 #if defined(_WIN32_WCE)
630 window->State.MouseX = 320-HIWORD( lParam );
631 window->State.MouseY = LOWORD( lParam );
633 window->State.MouseX = LOWORD( lParam );
634 window->State.MouseY = HIWORD( lParam );
635 #endif /* defined(_WIN32_WCE) */
636 /* Restrict to [-32768, 32767] to match X11 behaviour */
637 /* See comment in "freeglut_developer" mailing list 10/4/04 */
638 if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
639 if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;
641 if ( window->ActiveMenu )
643 fgUpdateMenuHighlight( window->ActiveMenu );
647 fgState.Modifiers = fgPlatformGetModifiers( );
649 if( ( wParam & MK_LBUTTON ) ||
650 ( wParam & MK_MBUTTON ) ||
651 ( wParam & MK_RBUTTON ) )
652 INVOKE_WCB( *window, Motion, ( window->State.MouseX,
653 window->State.MouseY ) );
655 INVOKE_WCB( *window, Passive, ( window->State.MouseX,
656 window->State.MouseY ) );
658 fgState.Modifiers = INVALID_MODIFIERS;
669 GLboolean pressed = GL_TRUE;
672 #if defined(_WIN32_WCE)
673 window->State.MouseX = 320-HIWORD( lParam );
674 window->State.MouseY = LOWORD( lParam );
676 window->State.MouseX = LOWORD( lParam );
677 window->State.MouseY = HIWORD( lParam );
678 #endif /* defined(_WIN32_WCE) */
680 /* Restrict to [-32768, 32767] to match X11 behaviour */
681 /* See comment in "freeglut_developer" mailing list 10/4/04 */
682 if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
683 if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;
689 button = GLUT_LEFT_BUTTON;
693 button = GLUT_MIDDLE_BUTTON;
697 button = GLUT_RIGHT_BUTTON;
701 button = GLUT_LEFT_BUTTON;
705 button = GLUT_MIDDLE_BUTTON;
709 button = GLUT_RIGHT_BUTTON;
717 #if !defined(_WIN32_WCE)
718 if( GetSystemMetrics( SM_SWAPBUTTON ) )
720 if( button == GLUT_LEFT_BUTTON )
721 button = GLUT_RIGHT_BUTTON;
723 if( button == GLUT_RIGHT_BUTTON )
724 button = GLUT_LEFT_BUTTON;
726 #endif /* !defined(_WIN32_WCE) */
729 return DefWindowProc( hWnd, uMsg, lParam, wParam );
732 * Do not execute the application's mouse callback if a menu
733 * is hooked to this button. In that case an appropriate
734 * private call should be generated.
736 if( fgCheckActiveMenu( window, button, pressed,
737 window->State.MouseX, window->State.MouseY ) )
740 /* Set capture so that the window captures all the mouse messages
742 * The mouse is not released from the window until all buttons have
743 * been released, even if the user presses a button in another window.
744 * This is consistent with the behavior on X11.
746 if ( pressed == GL_TRUE )
748 if (!setCaptureActive)
749 SetCapture ( window->Window.Handle ) ;
750 setCaptureActive = 1; /* Set to false in WM_CAPTURECHANGED handler */
752 else if (!GetAsyncKeyState(VK_LBUTTON) && !GetAsyncKeyState(VK_MBUTTON) && !GetAsyncKeyState(VK_RBUTTON))
753 /* Make sure all mouse buttons are released before releasing capture */
756 if( ! FETCH_WCB( *window, Mouse ) )
759 fgSetWindow( window );
760 fgState.Modifiers = fgPlatformGetModifiers( );
765 pressed ? GLUT_DOWN : GLUT_UP,
766 window->State.MouseX,
771 fgState.Modifiers = INVALID_MODIFIERS;
773 /* As per docs, should return zero */
780 SFG_Window *child_window = NULL;
781 int wheel_number = LOWORD( wParam );
782 short ticks = ( short )HIWORD( wParam );
784 window = fghWindowUnderCursor(window);
786 fgState.MouseWheelTicks += ticks;
787 if ( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA )
789 int direction = ( fgState.MouseWheelTicks > 0 ) ? 1 : -1;
791 if( ! FETCH_WCB( *window, MouseWheel ) &&
792 ! FETCH_WCB( *window, Mouse ) )
795 fgSetWindow( window );
796 fgState.Modifiers = fgPlatformGetModifiers( );
798 while( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA )
800 if( FETCH_WCB( *window, MouseWheel ) )
801 INVOKE_WCB( *window, MouseWheel,
804 window->State.MouseX,
808 else /* No mouse wheel, call the mouse button callback twice */
811 * Map wheel zero to button 3 and 4; +1 to 3, -1 to 4
812 * " " one +1 to 5, -1 to 6, ...
814 * XXX The below assumes that you have no more than 3 mouse
815 * XXX buttons. Sorry.
817 int button = wheel_number * 2 + 3;
820 INVOKE_WCB( *window, Mouse,
822 window->State.MouseX, window->State.MouseY )
824 INVOKE_WCB( *window, Mouse,
826 window->State.MouseX, window->State.MouseY )
830 fgState.MouseWheelTicks -= WHEEL_DELTA * direction;
833 fgState.Modifiers = INVALID_MODIFIERS;
841 window = fghWindowUnderCursor(window);
842 lRet = fghWindowProcKeyPress(window,uMsg,GL_TRUE,wParam,lParam);
849 window = fghWindowUnderCursor(window);
850 lRet = fghWindowProcKeyPress(window,uMsg,GL_FALSE,wParam,lParam);
857 window = fghWindowUnderCursor(window);
859 if( (fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE) && (HIWORD(lParam) & KF_REPEAT) )
862 fgState.Modifiers = fgPlatformGetModifiers( );
863 INVOKE_WCB( *window, Keyboard,
865 window->State.MouseX, window->State.MouseY )
867 fgState.Modifiers = INVALID_MODIFIERS;
871 case WM_CAPTURECHANGED:
872 if (!lParam || !fgWindowByHandle((HWND)lParam))
873 /* Capture released or capture taken by non-FreeGLUT window */
874 setCaptureActive = 0;
875 /* Docs advise a redraw */
876 InvalidateRect( hWnd, NULL, GL_FALSE );
878 lRet = 0; /* Per docs, should return zero */
881 /* Other messages that I have seen and which are not handled already */
882 case WM_SETTEXT: /* 0x000c */
883 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
884 /* Pass it on to "DefWindowProc" to set the window text */
887 case WM_GETTEXT: /* 0x000d */
888 /* Ideally we would copy the title of the window into "lParam" */
889 /* strncpy ( (char *)lParam, "Window Title", wParam );
890 lRet = ( wParam > 12 ) ? 12 : wParam; */
891 /* the number of characters copied */
892 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
895 case WM_GETTEXTLENGTH: /* 0x000e */
896 /* Ideally we would get the length of the title of the window */
898 /* the number of characters in "Window Title\0" (see above) */
901 case WM_ERASEBKGND: /* 0x0014 */
902 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
905 #if !defined(_WIN32_WCE)
906 case WM_SYNCPAINT: /* 0x0088 */
907 /* Another window has moved, need to update this one */
908 window->State.Redisplay = GL_TRUE;
909 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
910 /* Help screen says this message must be passed to "DefWindowProc" */
913 case WM_NCPAINT: /* 0x0085 */
914 /* Need to update the border of this window */
915 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
916 /* Pass it on to "DefWindowProc" to repaint a standard border */
919 case WM_SYSCOMMAND : /* 0x0112 */
922 * We have received a system command message. Try to act on it.
923 * The commands are passed in through the "wParam" parameter:
924 * The least significant digit seems to be which edge of the window
925 * is being used for a resize event:
929 * Congratulations and thanks to Richard Rauch for figuring this out..
931 switch ( wParam & 0xfff0 )
940 /* User has clicked on the "-" to minimize the window */
941 /* Turn off the visibility */
942 window->State.Visible = GL_FALSE ;
956 /* Followed very closely by a WM_CLOSE message */
986 #if(WINVER >= 0x0400)
990 case SC_MONITORPOWER :
993 case SC_CONTEXTHELP :
995 #endif /* WINVER >= 0x0400 */
999 fgWarning( "Unknown wParam type 0x%x", wParam );
1004 #endif /* !defined(_WIN32_WCE) */
1006 /* We need to pass the message on to the operating system as well */
1007 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1011 /* handle multi-touch messages */
1014 unsigned int numInputs = (unsigned int)wParam;
1016 TOUCHINPUT* ti = (TOUCHINPUT*)malloc( sizeof(TOUCHINPUT)*numInputs);
1018 if (fghGetTouchInputInfo == (pGetTouchInputInfo)0xDEADBEEF) {
1019 fghGetTouchInputInfo = (pGetTouchInputInfo)GetProcAddress(GetModuleHandle("user32"),"GetTouchInputInfo");
1020 fghCloseTouchInputHandle = (pCloseTouchInputHandle)GetProcAddress(GetModuleHandle("user32"),"CloseTouchInputHandle");
1023 if (!fghGetTouchInputInfo) {
1028 if (fghGetTouchInputInfo( (HTOUCHINPUT)lParam, numInputs, ti, sizeof(TOUCHINPUT) )) {
1029 /* Handle each contact point */
1030 for (i = 0; i < numInputs; ++i ) {
1033 tp.x = TOUCH_COORD_TO_PIXEL(ti[i].x);
1034 tp.y = TOUCH_COORD_TO_PIXEL(ti[i].y);
1035 ScreenToClient( hWnd, &tp );
1037 ti[i].dwID = ti[i].dwID * 2;
1039 if (ti[i].dwFlags & TOUCHEVENTF_DOWN) {
1040 INVOKE_WCB( *window, MultiEntry, ( ti[i].dwID, GLUT_ENTERED ) );
1041 INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_DOWN ) );
1042 } else if (ti[i].dwFlags & TOUCHEVENTF_MOVE) {
1043 INVOKE_WCB( *window, MultiMotion, ( ti[i].dwID, tp.x, tp.y ) );
1044 } else if (ti[i].dwFlags & TOUCHEVENTF_UP) {
1045 INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_UP ) );
1046 INVOKE_WCB( *window, MultiEntry, ( ti[i].dwID, GLUT_LEFT ) );
1050 fghCloseTouchInputHandle((HTOUCHINPUT)lParam);
1052 lRet = 0; /*DefWindowProc( hWnd, uMsg, wParam, lParam );*/
1057 /* Handle unhandled messages */
1058 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );