Adding header files to the "freeglut" projects per e-mail from Paul Martz dated 1...
[freeglut] / src / freeglut_main.c
index 44876f2..5f9b0a5 100644 (file)
 
 #include <GL/freeglut.h>
 #include "freeglut_internal.h"
-#include <errno.h>
+#ifdef HAVE_ERRNO_H
+#    include <errno.h>
+#endif
 #include <stdarg.h>
-#if  HAVE_VPRINTF
+#ifdef  HAVE_VFPRINTF
 #    define VFPRINTF(s,f,a) vfprintf((s),(f),(a))
-#elif HAVE_DOPRNT
+#elif defined(HAVE__DOPRNT)
 #    define VFPRINTF(s,f,a) _doprnt((f),(a),(s))
 #else
 #    define VFPRINTF(s,f,a)
@@ -57,7 +59,7 @@ struct GXKeyList gxKeyList;
  * Try to get the maximum value allowed for ints, falling back to the minimum
  * guaranteed by ISO C99 if there is no suitable header.
  */
-#if HAVE_LIMITS_H
+#ifdef HAVE_LIMITS_H
 #    include <limits.h>
 #endif
 #ifndef INT_MAX
@@ -68,6 +70,12 @@ struct GXKeyList gxKeyList;
 #    define MIN(a,b) (((a)<(b)) ? (a) : (b))
 #endif
 
+#ifdef WM_TOUCH
+    typedef BOOL (WINAPI *pGetTouchInputInfo)(HTOUCHINPUT,UINT,PTOUCHINPUT,int);
+    typedef BOOL (WINAPI *pCloseTouchInputHandle)(HTOUCHINPUT);
+       static pGetTouchInputInfo fghGetTouchInputInfo = (pGetTouchInputInfo)0xDEADBEEF;
+       static pCloseTouchInputHandle fghCloseTouchInputHandle = (pCloseTouchInputHandle)0xDEADBEEF;
+#endif
 
 /*
  * TODO BEFORE THE STABLE RELEASE:
@@ -93,7 +101,6 @@ static void fghReshapeWindow ( SFG_Window *window, int width, int height )
 
     freeglut_return_if_fail( window != NULL );
 
-
 #if TARGET_HOST_POSIX_X11
 
     XResizeWindow( fgDisplay.Display, window->Window.Handle,
@@ -102,8 +109,7 @@ static void fghReshapeWindow ( SFG_Window *window, int width, int height )
 
 #elif TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)
     {
-        RECT winRect;
-        int x, y, w, h;
+        RECT windowRect;
 
         /*
          * For windowed mode, get the current position of the
@@ -112,50 +118,43 @@ static void fghReshapeWindow ( SFG_Window *window, int width, int height )
          */
 
         /* "GetWindowRect" returns the pixel coordinates of the outside of the window */
-        GetWindowRect( window->Window.Handle, &winRect );
-        x = winRect.left;
-        y = winRect.top;
-        w = width;
-        h = height;
+        GetWindowRect( window->Window.Handle, &windowRect );
 
-        if ( window->Parent == NULL )
-        {
-            if ( ! window->IsMenu && (window != fgStructure.GameModeWindow) )
-            {
-                w += GetSystemMetrics( SM_CXSIZEFRAME ) * 2;
-                h += GetSystemMetrics( SM_CYSIZEFRAME ) * 2 +
-                     GetSystemMetrics( SM_CYCAPTION );
-            }
-        }
+        /* Create rect in FreeGLUT format, (X,Y) topleft outside window, WxH of client area */
+        windowRect.right    = windowRect.left+width;
+        windowRect.bottom   = windowRect.top+height;
+
+        if (window->Parent == NULL)
+            /* get the window rect from this to feed to SetWindowPos, correct for window decorations */
+            fghComputeWindowRectFromClientArea_QueryWindow(window,&windowRect,TRUE);
         else
         {
+            /* correct rect for position client area of parent window
+             * (SetWindowPos input for child windows is in coordinates
+             * relative to the parent's client area).
+             * Child windows don't have decoration, so no need to correct
+             * for them.
+             */
             RECT parentRect;
-            GetWindowRect( window->Parent->Window.Handle, &parentRect );
-            x -= parentRect.left + GetSystemMetrics( SM_CXSIZEFRAME ) * 2;
-            y -= parentRect.top  + GetSystemMetrics( SM_CYSIZEFRAME ) * 2 +
-                                   GetSystemMetrics( SM_CYCAPTION );
+            parentRect = fghGetClientArea( window->Parent, FALSE );
+            windowRect.left   -= parentRect.left;
+            windowRect.right  -= parentRect.left;
+            windowRect.top    -= parentRect.top;
+            windowRect.bottom -= parentRect.top;
         }
-
-        /*
-         * SWP_NOACTIVATE      Do not activate the window
-         * SWP_NOOWNERZORDER   Do not change position in z-order
-         * SWP_NOSENDCHANGING  Supress WM_WINDOWPOSCHANGING message
-         * SWP_NOZORDER        Retains the current Z order (ignore 2nd param)
-         */
-
+        
+        /* Do the actual resizing */
         SetWindowPos( window->Window.Handle,
                       HWND_TOP,
-                      x, y, w, h,
+                      windowRect.left, windowRect.top,
+                      windowRect.right - windowRect.left,
+                      windowRect.bottom- windowRect.top,
                       SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING |
                       SWP_NOZORDER
         );
     }
 #endif
 
-    /*
-     * XXX Should update {window->State.OldWidth, window->State.OldHeight}
-     * XXX to keep in lockstep with POSIX_X11 code.
-     */
     if( FETCH_WCB( *window, Reshape ) )
         INVOKE_WCB( *window, Reshape, ( width, height ) );
     else
@@ -224,6 +223,7 @@ static void fghcbDisplayWindow( SFG_Window *window,
 #if TARGET_HOST_POSIX_X11
         fghRedrawWindow ( window ) ;
 #elif TARGET_HOST_MS_WINDOWS
+
         RedrawWindow(
             window->Window.Handle, NULL, NULL,
             RDW_NOERASE | RDW_INTERNALPAINT | RDW_INVALIDATE | RDW_UPDATENOW
@@ -308,7 +308,7 @@ static void fghCheckTimers( void )
  * 32-bit, where the GLUT API return value is also overflowed.
  */  
 unsigned long fgSystemTime(void) {
-#if TARGET_HOST_POSIX_X11
+#if TARGET_HOST_SOLARIS || HAVE_GETTIMEOFDAY
     struct timeval now;
     gettimeofday( &now, NULL );
     return now.tv_usec/1000 + now.tv_sec*1000;
@@ -336,37 +336,62 @@ void fgError( const char *fmt, ... )
 {
     va_list ap;
 
-    va_start( ap, fmt );
+    if (fgState.ErrorFunc) {
+
+        va_start( ap, fmt );
+
+        /* call user set error handler here */
+        fgState.ErrorFunc(fmt, ap);
+
+        va_end( ap );
 
-    fprintf( stderr, "freeglut ");
-    if( fgState.ProgramName )
-        fprintf( stderr, "(%s): ", fgState.ProgramName );
-    VFPRINTF( stderr, fmt, ap );
-    fprintf( stderr, "\n" );
+    } else {
 
-    va_end( ap );
+        va_start( ap, fmt );
 
-    if ( fgState.Initialised )
-        fgDeinitialize ();
+        fprintf( stderr, "freeglut ");
+        if( fgState.ProgramName )
+            fprintf( stderr, "(%s): ", fgState.ProgramName );
+        VFPRINTF( stderr, fmt, ap );
+        fprintf( stderr, "\n" );
 
-    exit( 1 );
+        va_end( ap );
+
+        if ( fgState.Initialised )
+            fgDeinitialize ();
+
+        exit( 1 );
+    }
 }
 
 void fgWarning( const char *fmt, ... )
 {
     va_list ap;
 
-    va_start( ap, fmt );
+    if (fgState.WarningFunc) {
+
+        va_start( ap, fmt );
+
+        /* call user set warning handler here */
+        fgState.WarningFunc(fmt, ap);
+
+        va_end( ap );
 
-    fprintf( stderr, "freeglut ");
-    if( fgState.ProgramName )
-        fprintf( stderr, "(%s): ", fgState.ProgramName );
-    VFPRINTF( stderr, fmt, ap );
-    fprintf( stderr, "\n" );
+    } else {
 
-    va_end( ap );
+        va_start( ap, fmt );
+
+        fprintf( stderr, "freeglut ");
+        if( fgState.ProgramName )
+            fprintf( stderr, "(%s): ", fgState.ProgramName );
+        VFPRINTF( stderr, fmt, ap );
+        fprintf( stderr, "\n" );
+
+        va_end( ap );
+    }
 }
 
+
 /*
  * Indicates whether Joystick events are being used by ANY window.
  *
@@ -471,8 +496,10 @@ static void fghSleepForEvents( void )
         wait.tv_usec = (msec % 1000) * 1000;
         err = select( socket+1, &fdset, NULL, NULL, &wait );
 
+#ifdef HAVE_ERRNO_H
         if( ( -1 == err ) && ( errno != EINTR ) )
             fgWarning ( "freeglut select() error: %d", errno );
+#endif
     }
 #elif TARGET_HOST_MS_WINDOWS
     MsgWaitForMultipleObjects( 0, NULL, FALSE, msec, QS_ALLINPUT );
@@ -483,7 +510,7 @@ static void fghSleepForEvents( void )
 /*
  * Returns GLUT modifier mask for the state field of an X11 event.
  */
-static int fghGetXModifiers( int state )
+int fghGetXModifiers( int state )
 {
     int ret = 0;
 
@@ -976,6 +1003,10 @@ void FGAPIENTRY glutMainLoopEvent( void )
         switch( event.type )
         {
         case ClientMessage:
+            if(fgIsSpaceballXEvent(&event)) {
+                fgSpaceballHandleXEvent(&event);
+                break;
+            }
             /* Destroy the window when the WM_DELETE_WINDOW message arrives */
             if( (Atom) event.xclient.data.l[ 0 ] == fgDisplay.DeleteWindow )
             {
@@ -1159,15 +1190,15 @@ void FGAPIENTRY glutMainLoopEvent( void )
              * XXX track ButtonPress/ButtonRelease events in our own
              * XXX bit-mask?
              */
-           fgState.Modifiers = fghGetXModifiers( event.xmotion.state );
+            fgState.Modifiers = fghGetXModifiers( event.xmotion.state );
             if ( event.xmotion.state & ( Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask ) ) {
                 INVOKE_WCB( *window, Motion, ( event.xmotion.x,
                                                event.xmotion.y ) );
             } else {
                 INVOKE_WCB( *window, Passive, ( event.xmotion.x,
                                                 event.xmotion.y ) );
-           }
-           fgState.Modifiers = INVALID_MODIFIERS;
+            }
+            fgState.Modifiers = INVALID_MODIFIERS;
         }
         break;
 
@@ -1233,8 +1264,10 @@ void FGAPIENTRY glutMainLoopEvent( void )
                  * XXX See XFree86 configuration docs (even back in the
                  * XXX 3.x days, and especially with 4.x).
                  *
-                 * XXX Note that {button} has already been decremeted
+                 * XXX Note that {button} has already been decremented
                  * XXX in mapping from X button numbering to GLUT.
+                                *
+                                * XXX Should add support for partial wheel turns as Windows does -- 5/27/11
                  */
                 int wheel_number = (button - glutDeviceGet ( GLUT_NUM_MOUSE_BUTTONS )) / 2;
                 int direction = -1;
@@ -1290,7 +1323,10 @@ void FGAPIENTRY glutMainLoopEvent( void )
             /* Cease processing this event if it is auto repeated */
 
             if (window->State.KeyRepeating)
+            {
+                if (event.type == KeyPress) window->State.KeyRepeating = GL_FALSE;
                 break;
+            }
 
             if( event.type == KeyPress )
             {
@@ -1353,9 +1389,13 @@ void FGAPIENTRY glutMainLoopEvent( void )
                     case XK_F11:    special = GLUT_KEY_F11;    break;
                     case XK_F12:    special = GLUT_KEY_F12;    break;
 
+                    case XK_KP_Left:
                     case XK_Left:   special = GLUT_KEY_LEFT;   break;
+                    case XK_KP_Right:
                     case XK_Right:  special = GLUT_KEY_RIGHT;  break;
+                    case XK_KP_Up:
                     case XK_Up:     special = GLUT_KEY_UP;     break;
+                    case XK_KP_Down:
                     case XK_Down:   special = GLUT_KEY_DOWN;   break;
 
                     case XK_KP_Prior:
@@ -1368,6 +1408,17 @@ void FGAPIENTRY glutMainLoopEvent( void )
                     case XK_End:    special = GLUT_KEY_END;    break;
                     case XK_KP_Insert:
                     case XK_Insert: special = GLUT_KEY_INSERT; break;
+
+                    case XK_Num_Lock :  special = GLUT_KEY_NUM_LOCK;  break;
+                    case XK_KP_Begin :  special = GLUT_KEY_BEGIN;     break;
+                    case XK_KP_Delete:  special = GLUT_KEY_DELETE;    break;
+
+                    case XK_Shift_L:   special = GLUT_KEY_SHIFT_L;    break;
+                    case XK_Shift_R:   special = GLUT_KEY_SHIFT_R;    break;
+                    case XK_Control_L: special = GLUT_KEY_CTRL_L;     break;
+                    case XK_Control_R: special = GLUT_KEY_CTRL_R;     break;
+                    case XK_Alt_L:     special = GLUT_KEY_ALT_L;      break;
+                    case XK_Alt_R:     special = GLUT_KEY_ALT_R;      break;
                     }
 
                     /*
@@ -1389,8 +1440,15 @@ void FGAPIENTRY glutMainLoopEvent( void )
         case ReparentNotify:
             break; /* XXX Should disable this event */
 
+        /* Not handled */
+        case GravityNotify:
+            break;
+
         default:
-            fgWarning ("Unknown X event type: %d\n", event.type);
+            /* enter handling of Extension Events here */
+            #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
+                fgHandleExtensionEvents( &event );
+            #endif
             break;
         }
     }
@@ -1543,9 +1601,12 @@ static int fghGetWin32Modifiers (void)
 LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam,
                                LPARAM lParam )
 {
+    static unsigned char lControl = 0, rControl = 0, lShift = 0,
+                         rShift = 0, lAlt = 0, rAlt = 0;
+
     SFG_Window* window;
     PAINTSTRUCT ps;
-    LONG lRet = 1;
+    LRESULT lRet = 1;
 
     FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Event Handler" ) ;
 
@@ -1556,10 +1617,124 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam,
 
     /* printf ( "Window %3d message <%04x> %12d %12d\n", window?window->ID:0,
              uMsg, wParam, lParam ); */
+
+    if ( window )
+    {
+      /* Checking for CTRL, ALT, and SHIFT key positions:  Key Down! */
+      if ( !lControl && GetAsyncKeyState ( VK_LCONTROL ) )
+      {
+          INVOKE_WCB   ( *window, Special,
+                        ( GLUT_KEY_CTRL_L, window->State.MouseX, window->State.MouseY )
+                      );
+
+          lControl = 1;
+      }
+
+      if ( !rControl && GetAsyncKeyState ( VK_RCONTROL ) )
+      {
+          INVOKE_WCB ( *window, Special,
+                       ( GLUT_KEY_CTRL_R, window->State.MouseX, window->State.MouseY )
+                     );
+
+          rControl = 1;
+      }
+
+      if ( !lShift && GetAsyncKeyState ( VK_LSHIFT ) )
+      {
+          INVOKE_WCB ( *window, Special,
+                       ( GLUT_KEY_SHIFT_L, window->State.MouseX, window->State.MouseY )
+                     );
+
+          lShift = 1;
+      }
+
+      if ( !rShift && GetAsyncKeyState ( VK_RSHIFT ) )
+      {
+          INVOKE_WCB ( *window, Special,
+                       ( GLUT_KEY_SHIFT_R, window->State.MouseX, window->State.MouseY )
+                     );
+
+          rShift = 1;
+      }
+
+      if ( !lAlt && GetAsyncKeyState ( VK_LMENU ) )
+      {
+          INVOKE_WCB ( *window, Special,
+                       ( GLUT_KEY_ALT_L, window->State.MouseX, window->State.MouseY )
+                     );
+
+          lAlt = 1;
+      }
+
+      if ( !rAlt && GetAsyncKeyState ( VK_RMENU ) )
+      {
+          INVOKE_WCB ( *window, Special,
+                       ( GLUT_KEY_ALT_R, window->State.MouseX, window->State.MouseY )
+                     );
+
+          rAlt = 1;
+      }
+
+      /* Checking for CTRL, ALT, and SHIFT key positions:  Key Up! */
+      if ( lControl && !GetAsyncKeyState ( VK_LCONTROL ) )
+      {
+          INVOKE_WCB ( *window, SpecialUp,
+                       ( GLUT_KEY_CTRL_L, window->State.MouseX, window->State.MouseY )
+                     );
+
+          lControl = 0;
+      }
+
+      if ( rControl && !GetAsyncKeyState ( VK_RCONTROL ) )
+      {
+          INVOKE_WCB ( *window, SpecialUp,
+                       ( GLUT_KEY_CTRL_R, window->State.MouseX, window->State.MouseY )
+                     );
+
+          rControl = 0;
+      }
+
+      if ( lShift && !GetAsyncKeyState ( VK_LSHIFT ) )
+      {
+          INVOKE_WCB ( *window, SpecialUp,
+                       ( GLUT_KEY_SHIFT_L, window->State.MouseX, window->State.MouseY )
+                     );
+
+          lShift = 0;
+      }
+
+      if ( rShift && !GetAsyncKeyState ( VK_RSHIFT ) )
+      {
+          INVOKE_WCB ( *window, SpecialUp,
+                       ( GLUT_KEY_SHIFT_R, window->State.MouseX, window->State.MouseY )
+                     );
+
+          rShift = 0;
+      }
+
+      if ( lAlt && !GetAsyncKeyState ( VK_LMENU ) )
+      {
+          INVOKE_WCB ( *window, SpecialUp,
+                       ( GLUT_KEY_ALT_L, window->State.MouseX, window->State.MouseY )
+                     );
+
+          lAlt = 0;
+      }
+
+      if ( rAlt && !GetAsyncKeyState ( VK_RMENU ) )
+      {
+          INVOKE_WCB ( *window, SpecialUp,
+                       ( GLUT_KEY_ALT_R, window->State.MouseX, window->State.MouseY )
+                     );
+
+          rAlt = 0;
+      }
+    }
+
     switch( uMsg )
     {
     case WM_CREATE:
-        /* The window structure is passed as the creation structure paramter... */
+        /* The window structure is passed as the creation structure parameter... */
         window = (SFG_Window *) (((LPCREATESTRUCT) lParam)->lpCreateParams);
         FREEGLUT_INTERNAL_ERROR_EXIT ( ( window != NULL ), "Cannot create window",
                                        "fgWindowProc" );
@@ -1606,9 +1781,17 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam,
                     window->Window.Context =
                         wglCreateContext( window->Window.Device );
             }
+
+#if !defined(_WIN32_WCE)
+            fgNewWGLCreateContext( window );
+#endif
         }
 
         window->State.NeedToResize = GL_TRUE;
+        /* if we used CW_USEDEFAULT (thats a negative value) for the size
+         * of the window, query the window now for the size at which it
+         * was created.
+         */
         if( ( window->State.Width < 0 ) || ( window->State.Height < 0 ) )
         {
             SFG_Window *current_window = fgStructure.CurrentWindow;
@@ -1659,12 +1842,25 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam,
         }
 
         break;
-#if 0
+
     case WM_SETFOCUS:
 /*        printf("WM_SETFOCUS: %p\n", window ); */
         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
+        INVOKE_WCB( *window, Entry, ( GLUT_ENTERED ) );
         break;
 
+    case WM_KILLFOCUS:
+/*        printf("WM_KILLFOCUS: %p\n", window ); */
+        lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
+        INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) );
+
+        if( window->IsMenu &&
+            window->ActiveMenu && window->ActiveMenu->IsActive )
+            fgUpdateMenuHighlight( window->ActiveMenu );
+
+        break;
+
+#if 0
     case WM_ACTIVATE:
         if (LOWORD(wParam) != WA_INACTIVE)
         {
@@ -1710,20 +1906,6 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam,
          */
         return 0;
 
-    /* XXX For a future patch:  we need a mouse entry event.  Unfortunately Windows
-     * XXX doesn't give us one, so we will probably need a "MouseInWindow" flag in
-     * XXX the SFG_Window structure.  Set it to true to begin with and then have the
-     * XXX WM_MOUSELEAVE code set it to false.  Then when we get a WM_MOUSEMOVE event,
-     * XXX if the flag is false we invoke the Entry callback and set the flag to true.
-     */
-    case 0x02a2:  /* This is the message we get when the mouse is leaving the window */
-        if( window->IsMenu &&
-            window->ActiveMenu && window->ActiveMenu->IsActive )
-            fgUpdateMenuHighlight( window->ActiveMenu );
-
-        INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) );
-        break ;
-
     case WM_MOUSEMOVE:
     {
 #if defined(_WIN32_WCE)
@@ -1743,6 +1925,7 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam,
             fgUpdateMenuHighlight( window->ActiveMenu );
             break;
         }
+        SetFocus(window->Window.Handle);
 
         fgState.Modifiers = fghGetWin32Modifiers( );
 
@@ -1872,67 +2055,67 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam,
     case 0x020a:
         /* Should be WM_MOUSEWHEEL but my compiler doesn't recognize it */
     {
-        /*
-         * XXX THIS IS SPECULATIVE -- John Fay, 10/2/03
-         * XXX Should use WHEEL_DELTA instead of 120
-         */
         int wheel_number = LOWORD( wParam );
-        short ticks = ( short )HIWORD( wParam ) / 120;
-        int direction = 1;
-
-        if( ticks < 0 )
-        {
-            direction = -1;
-            ticks = -ticks;
-        }
+        short ticks = ( short )HIWORD( wParam );
+               fgState.MouseWheelTicks += ticks;
 
         /*
-         * The mouse cursor has moved. Remember the new mouse cursor's position
+         * XXX Should use WHEEL_DELTA instead of 120
          */
-        /*        window->State.MouseX = LOWORD( lParam ); */
-        /* Need to adjust by window position, */
-        /*        window->State.MouseY = HIWORD( lParam ); */
-        /* change "lParam" to other parameter */
+               if ( abs ( fgState.MouseWheelTicks ) > 120 )
+               {
+                       int direction = ( fgState.MouseWheelTicks > 0 ) ? 1 : -1;
 
-        if( ! FETCH_WCB( *window, MouseWheel ) &&
-            ! FETCH_WCB( *window, Mouse ) )
-            break;
+            if( ! FETCH_WCB( *window, MouseWheel ) &&
+                ! FETCH_WCB( *window, Mouse ) )
+                break;
 
-        fgSetWindow( window );
-        fgState.Modifiers = fghGetWin32Modifiers( );
+            fgSetWindow( window );
+            fgState.Modifiers = fghGetWin32Modifiers( );
+
+            /*
+             * XXX Should use WHEEL_DELTA instead of 120
+             */
+            while( abs ( fgState.MouseWheelTicks ) > 120 )
+                       {
+                if( FETCH_WCB( *window, MouseWheel ) )
+                    INVOKE_WCB( *window, MouseWheel,
+                                ( wheel_number,
+                                  direction,
+                                  window->State.MouseX,
+                                  window->State.MouseY
+                                )
+                    );
+                else  /* No mouse wheel, call the mouse button callback twice */
+                               {
+                    /*
+                     * Map wheel zero to button 3 and 4; +1 to 3, -1 to 4
+                     *  "    "   one                     +1 to 5, -1 to 6, ...
+                     *
+                     * XXX The below assumes that you have no more than 3 mouse
+                     * XXX buttons.  Sorry.
+                     */
+                    int button = wheel_number * 2 + 3;
+                    if( direction < 0 )
+                        ++button;
+                    INVOKE_WCB( *window, Mouse,
+                                ( button, GLUT_DOWN,
+                                  window->State.MouseX, window->State.MouseY )
+                    );
+                    INVOKE_WCB( *window, Mouse,
+                                ( button, GLUT_UP,
+                                  window->State.MouseX, window->State.MouseY )
+                    );
+                               }
 
-        while( ticks-- )
-            if( FETCH_WCB( *window, MouseWheel ) )
-                INVOKE_WCB( *window, MouseWheel,
-                            ( wheel_number,
-                              direction,
-                              window->State.MouseX,
-                              window->State.MouseY
-                            )
-                );
-            else  /* No mouse wheel, call the mouse button callback twice */
-            {
                 /*
-                 * Map wheel zero to button 3 and 4; +1 to 3, -1 to 4
-                 *  "    "   one                     +1 to 5, -1 to 6, ...
-                 *
-                 * XXX The below assumes that you have no more than 3 mouse
-                 * XXX buttons.  Sorry.
+                 * XXX Should use WHEEL_DELTA instead of 120
                  */
-                int button = wheel_number * 2 + 3;
-                if( direction < 0 )
-                    ++button;
-                INVOKE_WCB( *window, Mouse,
-                            ( button, GLUT_DOWN,
-                              window->State.MouseX, window->State.MouseY )
-                );
-                INVOKE_WCB( *window, Mouse,
-                            ( button, GLUT_UP,
-                              window->State.MouseX, window->State.MouseY )
-                );
-            }
+                               fgState.MouseWheelTicks -= 120 * direction;
+                       }
 
-        fgState.Modifiers = INVALID_MODIFIERS;
+            fgState.Modifiers = INVALID_MODIFIERS;
+               }
     }
     break ;
 
@@ -1983,6 +2166,12 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam,
             KEY( VK_RIGHT,  GLUT_KEY_RIGHT     );
             KEY( VK_DOWN,   GLUT_KEY_DOWN      );
             KEY( VK_INSERT, GLUT_KEY_INSERT    );
+            KEY( VK_LCONTROL, GLUT_KEY_CTRL_L  );
+            KEY( VK_RCONTROL, GLUT_KEY_CTRL_R  );
+            KEY( VK_LSHIFT, GLUT_KEY_SHIFT_L   );
+            KEY( VK_RSHIFT, GLUT_KEY_SHIFT_R   );
+            KEY( VK_LMENU,  GLUT_KEY_ALT_L     );
+            KEY( VK_RMENU,  GLUT_KEY_ALT_R     );
 
         case VK_DELETE:
             /* The delete key should be treated as an ASCII keypress: */
@@ -2069,6 +2258,12 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam,
             KEY( VK_RIGHT,  GLUT_KEY_RIGHT     );
             KEY( VK_DOWN,   GLUT_KEY_DOWN      );
             KEY( VK_INSERT, GLUT_KEY_INSERT    );
+            KEY( VK_LCONTROL, GLUT_KEY_CTRL_L  );
+            KEY( VK_RCONTROL, GLUT_KEY_CTRL_R  );
+            KEY( VK_LSHIFT, GLUT_KEY_SHIFT_L   );
+            KEY( VK_RSHIFT, GLUT_KEY_SHIFT_R   );
+            KEY( VK_LMENU,  GLUT_KEY_ALT_L     );
+            KEY( VK_RMENU,  GLUT_KEY_ALT_R     );
 
           case VK_DELETE:
               /* The delete key should be treated as an ASCII keypress: */
@@ -2085,7 +2280,7 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam,
 
             GetKeyboardState( state );
 
-            if( ToAscii( wParam, 0, state, code, 0 ) == 1 )
+            if( ToAscii( (UINT)wParam, 0, state, code, 0 ) == 1 )
                 wParam=code[ 0 ];
 
             INVOKE_WCB( *window, KeyboardUp,
@@ -2233,6 +2428,17 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam,
             case SC_HOTKEY     :
                 break ;
 
+#if(WINVER >= 0x0400)
+            case SC_DEFAULT    :
+                break ;
+
+            case SC_MONITORPOWER    :
+                break ;
+
+            case SC_CONTEXTHELP    :
+                break ;
+#endif /* WINVER >= 0x0400 */
+
             default:
 #if _DEBUG
                 fgWarning( "Unknown wParam type 0x%x", wParam );
@@ -2246,6 +2452,52 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam,
         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
         break;
 
+#ifdef WM_TOUCH
+       /* handle multi-touch messages */
+       case WM_TOUCH:
+       {
+               unsigned int numInputs = (unsigned int)wParam;
+               unsigned int i = 0;
+               TOUCHINPUT* ti = (TOUCHINPUT*)malloc( sizeof(TOUCHINPUT)*numInputs);
+
+               if (fghGetTouchInputInfo == (pGetTouchInputInfo)0xDEADBEEF) {
+                   fghGetTouchInputInfo = (pGetTouchInputInfo)GetProcAddress(GetModuleHandle("user32"),"GetTouchInputInfo");
+                   fghCloseTouchInputHandle = (pCloseTouchInputHandle)GetProcAddress(GetModuleHandle("user32"),"CloseTouchInputHandle");
+               }
+
+               if (!fghGetTouchInputInfo) { 
+                       free( (void*)ti );
+                       break;
+               }
+
+               if (fghGetTouchInputInfo( (HTOUCHINPUT)lParam, numInputs, ti, sizeof(TOUCHINPUT) )) {
+                       /* Handle each contact point */
+                       for (i = 0; i < numInputs; ++i ) {
+
+                               POINT tp;
+                               tp.x = TOUCH_COORD_TO_PIXEL(ti[i].x);
+                               tp.y = TOUCH_COORD_TO_PIXEL(ti[i].y);
+                               ScreenToClient( hWnd, &tp );
+
+                               ti[i].dwID = ti[i].dwID * 2;
+
+                               if (ti[i].dwFlags & TOUCHEVENTF_DOWN) {
+                                       INVOKE_WCB( *window, MultiEntry,  ( ti[i].dwID, GLUT_ENTERED ) );
+                                       INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_DOWN ) );
+                               } else if (ti[i].dwFlags & TOUCHEVENTF_MOVE) {
+                                       INVOKE_WCB( *window, MultiMotion, ( ti[i].dwID, tp.x, tp.y ) );
+                               } else if (ti[i].dwFlags & TOUCHEVENTF_UP)   { 
+                                       INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_UP ) );
+                                       INVOKE_WCB( *window, MultiEntry,  ( ti[i].dwID, GLUT_LEFT ) );
+                               }
+                       }
+               }
+               fghCloseTouchInputHandle((HTOUCHINPUT)lParam);
+               free( (void*)ti );
+               lRet = 0; /*DefWindowProc( hWnd, uMsg, wParam, lParam );*/
+               break;
+       }
+#endif
     default:
         /* Handle unhandled messages */
         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );