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, Visibility ) )
148 SFG_Window *current_window = fgStructure.CurrentWindow ;
150 INVOKE_WCB( *window, Visibility, ( window->State.Visible ) );
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 void fghWindowUnderCursor(SFG_Window *window, SFG_Window **child_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.
329 if (window && window->Children.First)
332 SFG_WindowHandleType hwnd;
333 SFG_Window* temp_window;
335 /* Get mouse position at time of message */
336 DWORD mouse_pos_Dword = GetMessagePos();
337 mouse_pos.x = GET_X_LPARAM(mouse_pos_Dword);
338 mouse_pos.y = GET_Y_LPARAM(mouse_pos_Dword);
339 ScreenToClient( window->Window.Handle, &mouse_pos );
341 hwnd = ChildWindowFromPoint(window->Window.Handle, mouse_pos);
342 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 */
344 temp_window = fgWindowByHandle(hwnd);
345 if (temp_window) /* Verify we got a FreeGLUT window */
347 *child_window = temp_window;
348 /* ChildWindowFromPoint only searches immediate children, so search again to see if actually in grandchild or further descendant */
349 fghWindowUnderCursor(temp_window,child_window);
356 * The window procedure for handling Win32 events
358 LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
360 SFG_Window *window, *child_window = NULL;
364 FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Event Handler" ) ;
366 window = fgWindowByHandle( hWnd );
368 if ( ( window == NULL ) && ( uMsg != WM_CREATE ) )
369 return DefWindowProc( hWnd, uMsg, wParam, lParam );
371 /* printf ( "Window %3d message <%04x> %12d %12d\n", window?window->ID:0,
372 uMsg, wParam, lParam ); */
374 /* Some events only sent to main window. Check if the current window that
375 * the mouse is over is a child window. Below when handling some messages,
376 * we make sure that we process callbacks on the child window instead.
377 * This mirrors how GLUT does things.
379 fghWindowUnderCursor(window, &child_window);
384 /* The window structure is passed as the creation structure parameter... */
385 window = (SFG_Window *) (((LPCREATESTRUCT) lParam)->lpCreateParams);
386 FREEGLUT_INTERNAL_ERROR_EXIT ( ( window != NULL ), "Cannot create window",
387 "fgPlatformWindowProc" );
389 window->Window.Handle = hWnd;
390 window->Window.pContext.Device = GetDC( hWnd );
393 unsigned int current_DisplayMode = fgState.DisplayMode;
394 fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH;
395 #if !defined(_WIN32_WCE)
396 fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE );
398 fgState.DisplayMode = current_DisplayMode;
400 if( fgStructure.MenuContext )
401 wglMakeCurrent( window->Window.pContext.Device,
402 fgStructure.MenuContext->MContext
406 fgStructure.MenuContext =
407 (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) );
408 fgStructure.MenuContext->MContext =
409 wglCreateContext( window->Window.pContext.Device );
412 /* window->Window.Context = wglGetCurrentContext (); */
413 window->Window.Context = wglCreateContext( window->Window.pContext.Device );
417 #if !defined(_WIN32_WCE)
418 fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE );
421 if( ! fgState.UseCurrentContext )
422 window->Window.Context =
423 wglCreateContext( window->Window.pContext.Device );
426 window->Window.Context = wglGetCurrentContext( );
427 if( ! window->Window.Context )
428 window->Window.Context =
429 wglCreateContext( window->Window.pContext.Device );
432 #if !defined(_WIN32_WCE)
433 fgNewWGLCreateContext( window );
437 window->State.NeedToResize = GL_TRUE;
438 /* if we used CW_USEDEFAULT (thats a negative value) for the size
439 * of the window, query the window now for the size at which it
442 if( ( window->State.Width < 0 ) || ( window->State.Height < 0 ) )
444 SFG_Window *current_window = fgStructure.CurrentWindow;
446 fgSetWindow( window );
447 window->State.Width = glutGet( GLUT_WINDOW_WIDTH );
448 window->State.Height = glutGet( GLUT_WINDOW_HEIGHT );
449 fgSetWindow( current_window );
452 ReleaseDC( window->Window.Handle, window->Window.pContext.Device );
454 #if defined(_WIN32_WCE)
455 /* Take over button handling */
457 HINSTANCE dxDllLib=LoadLibrary(_T("gx.dll"));
460 GXGetDefaultKeys_=(GXGETDEFAULTKEYS)GetProcAddress(dxDllLib, _T("?GXGetDefaultKeys@@YA?AUGXKeyList@@H@Z"));
461 GXOpenInput_=(GXOPENINPUT)GetProcAddress(dxDllLib, _T("?GXOpenInput@@YAHXZ"));
466 if(GXGetDefaultKeys_)
467 gxKeyList = (*GXGetDefaultKeys_)(GX_LANDSCAPEKEYS);
470 #endif /* defined(_WIN32_WCE) */
475 * If the window is visible, then it is the user manually resizing it.
476 * If it is not, then it is the system sending us a dummy resize with
477 * zero dimensions on a "glutIconifyWindow" call.
479 if( window->State.Visible )
481 /* get old values first to compare to below */
482 int width = window->State.Width, height=window->State.Height;
483 #if defined(_WIN32_WCE)
484 window->State.Width = HIWORD(lParam);
485 window->State.Height = LOWORD(lParam);
487 window->State.Width = LOWORD(lParam);
488 window->State.Height = HIWORD(lParam);
489 #endif /* defined(_WIN32_WCE) */
491 if (width!=window->State.Width || height!=window->State.Height)
492 /* Something changed, need to resize */
493 window->State.NeedToResize = GL_TRUE;
500 SFG_Window* saved_window = fgStructure.CurrentWindow;
502 GetWindowRect( window->Window.Handle, &windowRect );
506 /* For child window, we should return relative to upper-left
507 * of parent's client area.
509 POINT topleft = {windowRect.left,windowRect.top};
511 ScreenToClient(window->Parent->Window.Handle,&topleft);
512 windowRect.left = topleft.x;
513 windowRect.top = topleft.y;
516 INVOKE_WCB( *window, Position, ( windowRect.left, windowRect.top ) );
517 fgSetWindow(saved_window);
522 /* printf("WM_SETFOCUS: %p\n", window ); */
524 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
528 /* If we're dealing with a child window, make sure it has input focus instead, set it here. */
529 SetFocus(child_window->Window.Handle);
530 SetActiveWindow( child_window->Window.Handle );
531 INVOKE_WCB( *child_window, Entry, ( GLUT_ENTERED ) );
532 UpdateWindow ( child_window->Window.Handle );
536 SetActiveWindow( window->Window.Handle );
537 INVOKE_WCB( *window, Entry, ( GLUT_ENTERED ) );
539 /* Always request update on main window to be safe */
540 UpdateWindow ( hWnd );
546 SFG_Window* saved_window = fgStructure.CurrentWindow;
547 /* printf("WM_KILLFOCUS: %p\n", window ); */
548 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
549 INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) );
550 fgSetWindow(saved_window);
552 /* Check if there are any open menus that need to be closed */
553 fgPlatformCheckMenuDeactivate();
559 //printf("WM_ACTIVATE: %x %d %d\n",lParam, HIWORD(wParam), LOWORD(wParam));
560 if (LOWORD(wParam) != WA_INACTIVE)
562 /* printf("WM_ACTIVATE: fgSetCursor( %p, %d)\n", window,
563 window->State.Cursor ); */
564 fgSetCursor( window, window->State.Cursor );
567 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
572 /* printf ( "Cursor event %x %x %x %x\n", window, window->State.Cursor, lParam, wParam ) ; */
573 if( LOWORD( lParam ) == HTCLIENT )
574 fgSetCursor ( window, window->State.Cursor ) ;
576 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
580 window->State.Visible = GL_TRUE;
581 window->State.Redisplay = GL_TRUE;
585 /* Turn on the visibility in case it was turned off somehow */
586 window->State.Visible = GL_TRUE;
587 InvalidateRect( hWnd, NULL, GL_FALSE ); /* Make sure whole window is repainted. Bit of a hack, but a safe one from what google turns up... */
588 BeginPaint( hWnd, &ps );
589 fghRedrawWindow( window );
590 EndPaint( hWnd, &ps );
594 fgDestroyWindow ( window );
595 if ( fgState.ActionOnWindowClose != GLUT_ACTION_CONTINUE_EXECUTION )
601 * The window already got destroyed, so don't bother with it.
607 #if defined(_WIN32_WCE)
608 window->State.MouseX = 320-HIWORD( lParam );
609 window->State.MouseY = LOWORD( lParam );
611 window->State.MouseX = LOWORD( lParam );
612 window->State.MouseY = HIWORD( lParam );
613 #endif /* defined(_WIN32_WCE) */
614 /* Restrict to [-32768, 32767] to match X11 behaviour */
615 /* See comment in "freeglut_developer" mailing list 10/4/04 */
616 if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
617 if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;
619 if ( window->ActiveMenu )
621 fgUpdateMenuHighlight( window->ActiveMenu );
625 fgState.Modifiers = fgPlatformGetModifiers( );
627 if( ( wParam & MK_LBUTTON ) ||
628 ( wParam & MK_MBUTTON ) ||
629 ( wParam & MK_RBUTTON ) )
630 INVOKE_WCB( *window, Motion, ( window->State.MouseX,
631 window->State.MouseY ) );
633 INVOKE_WCB( *window, Passive, ( window->State.MouseX,
634 window->State.MouseY ) );
636 fgState.Modifiers = INVALID_MODIFIERS;
647 GLboolean pressed = GL_TRUE;
650 #if defined(_WIN32_WCE)
651 window->State.MouseX = 320-HIWORD( lParam );
652 window->State.MouseY = LOWORD( lParam );
654 window->State.MouseX = LOWORD( lParam );
655 window->State.MouseY = HIWORD( lParam );
656 #endif /* defined(_WIN32_WCE) */
658 /* Restrict to [-32768, 32767] to match X11 behaviour */
659 /* See comment in "freeglut_developer" mailing list 10/4/04 */
660 if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
661 if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;
667 button = GLUT_LEFT_BUTTON;
671 button = GLUT_MIDDLE_BUTTON;
675 button = GLUT_RIGHT_BUTTON;
679 button = GLUT_LEFT_BUTTON;
683 button = GLUT_MIDDLE_BUTTON;
687 button = GLUT_RIGHT_BUTTON;
695 #if !defined(_WIN32_WCE)
696 if( GetSystemMetrics( SM_SWAPBUTTON ) )
698 if( button == GLUT_LEFT_BUTTON )
699 button = GLUT_RIGHT_BUTTON;
701 if( button == GLUT_RIGHT_BUTTON )
702 button = GLUT_LEFT_BUTTON;
704 #endif /* !defined(_WIN32_WCE) */
707 return DefWindowProc( hWnd, uMsg, lParam, wParam );
710 * Do not execute the application's mouse callback if a menu
711 * is hooked to this button. In that case an appropriate
712 * private call should be generated.
714 if( fgCheckActiveMenu( window, button, pressed,
715 window->State.MouseX, window->State.MouseY ) )
718 /* Set capture so that the window captures all the mouse messages */
720 * XXX - Multiple button support: Under X11, the mouse is not released
721 * XXX - from the window until all buttons have been released, even if the
722 * XXX - user presses a button in another window. This will take more
723 * XXX - code changes than I am up to at the moment (10/5/04). The present
724 * XXX - is a 90 percent solution.
726 if ( pressed == GL_TRUE )
727 SetCapture ( window->Window.Handle ) ;
731 if( ! FETCH_WCB( *window, Mouse ) )
734 fgSetWindow( window );
735 fgState.Modifiers = fgPlatformGetModifiers( );
740 pressed ? GLUT_DOWN : GLUT_UP,
741 window->State.MouseX,
746 fgState.Modifiers = INVALID_MODIFIERS;
752 int wheel_number = LOWORD( wParam );
753 short ticks = ( short )HIWORD( wParam );
754 fgState.MouseWheelTicks += ticks;
756 if ( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA )
758 int direction = ( fgState.MouseWheelTicks > 0 ) ? 1 : -1;
760 if( ! FETCH_WCB( *window, MouseWheel ) &&
761 ! FETCH_WCB( *window, Mouse ) )
764 fgSetWindow( window );
765 fgState.Modifiers = fgPlatformGetModifiers( );
767 while( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA )
769 if( FETCH_WCB( *window, MouseWheel ) )
770 INVOKE_WCB( *window, MouseWheel,
773 window->State.MouseX,
777 else /* No mouse wheel, call the mouse button callback twice */
780 * Map wheel zero to button 3 and 4; +1 to 3, -1 to 4
781 * " " one +1 to 5, -1 to 6, ...
783 * XXX The below assumes that you have no more than 3 mouse
784 * XXX buttons. Sorry.
786 int button = wheel_number * 2 + 3;
789 INVOKE_WCB( *window, Mouse,
791 window->State.MouseX, window->State.MouseY )
793 INVOKE_WCB( *window, Mouse,
795 window->State.MouseX, window->State.MouseY )
799 fgState.MouseWheelTicks -= WHEEL_DELTA * direction;
802 fgState.Modifiers = INVALID_MODIFIERS;
810 window = child_window;
811 lRet = fghWindowProcKeyPress(window,uMsg,GL_TRUE,wParam,lParam);
817 window = child_window;
818 lRet = fghWindowProcKeyPress(window,uMsg,GL_FALSE,wParam,lParam);
825 window = child_window;
827 if( (fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE) && (HIWORD(lParam) & KF_REPEAT) )
830 fgState.Modifiers = fgPlatformGetModifiers( );
831 INVOKE_WCB( *window, Keyboard,
833 window->State.MouseX, window->State.MouseY )
835 fgState.Modifiers = INVALID_MODIFIERS;
839 case WM_CAPTURECHANGED:
840 /* User has finished resizing the window, force a redraw */
841 INVOKE_WCB( *window, Display, ( ) );
843 /*lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); */
846 /* Other messages that I have seen and which are not handled already */
847 case WM_SETTEXT: /* 0x000c */
848 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
849 /* Pass it on to "DefWindowProc" to set the window text */
852 case WM_GETTEXT: /* 0x000d */
853 /* Ideally we would copy the title of the window into "lParam" */
854 /* strncpy ( (char *)lParam, "Window Title", wParam );
855 lRet = ( wParam > 12 ) ? 12 : wParam; */
856 /* the number of characters copied */
857 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
860 case WM_GETTEXTLENGTH: /* 0x000e */
861 /* Ideally we would get the length of the title of the window */
863 /* the number of characters in "Window Title\0" (see above) */
866 case WM_ERASEBKGND: /* 0x0014 */
867 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
870 #if !defined(_WIN32_WCE)
871 case WM_SYNCPAINT: /* 0x0088 */
872 /* Another window has moved, need to update this one */
873 window->State.Redisplay = GL_TRUE;
874 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
875 /* Help screen says this message must be passed to "DefWindowProc" */
878 case WM_NCPAINT: /* 0x0085 */
879 /* Need to update the border of this window */
880 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
881 /* Pass it on to "DefWindowProc" to repaint a standard border */
884 case WM_SYSCOMMAND : /* 0x0112 */
887 * We have received a system command message. Try to act on it.
888 * The commands are passed in through the "wParam" parameter:
889 * The least significant digit seems to be which edge of the window
890 * is being used for a resize event:
894 * Congratulations and thanks to Richard Rauch for figuring this out..
896 switch ( wParam & 0xfff0 )
905 /* User has clicked on the "-" to minimize the window */
906 /* Turn off the visibility */
907 window->State.Visible = GL_FALSE ;
921 /* Followed very closely by a WM_CLOSE message */
951 #if(WINVER >= 0x0400)
955 case SC_MONITORPOWER :
958 case SC_CONTEXTHELP :
960 #endif /* WINVER >= 0x0400 */
964 fgWarning( "Unknown wParam type 0x%x", wParam );
969 #endif /* !defined(_WIN32_WCE) */
971 /* We need to pass the message on to the operating system as well */
972 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
976 /* handle multi-touch messages */
979 unsigned int numInputs = (unsigned int)wParam;
981 TOUCHINPUT* ti = (TOUCHINPUT*)malloc( sizeof(TOUCHINPUT)*numInputs);
983 if (fghGetTouchInputInfo == (pGetTouchInputInfo)0xDEADBEEF) {
984 fghGetTouchInputInfo = (pGetTouchInputInfo)GetProcAddress(GetModuleHandle("user32"),"GetTouchInputInfo");
985 fghCloseTouchInputHandle = (pCloseTouchInputHandle)GetProcAddress(GetModuleHandle("user32"),"CloseTouchInputHandle");
988 if (!fghGetTouchInputInfo) {
993 if (fghGetTouchInputInfo( (HTOUCHINPUT)lParam, numInputs, ti, sizeof(TOUCHINPUT) )) {
994 /* Handle each contact point */
995 for (i = 0; i < numInputs; ++i ) {
998 tp.x = TOUCH_COORD_TO_PIXEL(ti[i].x);
999 tp.y = TOUCH_COORD_TO_PIXEL(ti[i].y);
1000 ScreenToClient( hWnd, &tp );
1002 ti[i].dwID = ti[i].dwID * 2;
1004 if (ti[i].dwFlags & TOUCHEVENTF_DOWN) {
1005 INVOKE_WCB( *window, MultiEntry, ( ti[i].dwID, GLUT_ENTERED ) );
1006 INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_DOWN ) );
1007 } else if (ti[i].dwFlags & TOUCHEVENTF_MOVE) {
1008 INVOKE_WCB( *window, MultiMotion, ( ti[i].dwID, tp.x, tp.y ) );
1009 } else if (ti[i].dwFlags & TOUCHEVENTF_UP) {
1010 INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_UP ) );
1011 INVOKE_WCB( *window, MultiEntry, ( ti[i].dwID, GLUT_LEFT ) );
1015 fghCloseTouchInputHandle((HTOUCHINPUT)lParam);
1017 lRet = 0; /*DefWindowProc( hWnd, uMsg, wParam, lParam );*/
1022 /* Handle unhandled messages */
1023 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );