Fixing multitouch for Windows per e-mail from Florian Echtler dated 5/3/11 10:33 AM
[freeglut] / src / freeglut_main.c
index 19f584e..f73953d 100644 (file)
@@ -70,6 +70,12 @@ struct GXKeyList gxKeyList;
 #    define MIN(a,b) (((a)<(b)) ? (a) : (b))
 #endif
 
+#ifdef WM_TOUCH
+    typedef BOOL (*pGetTouchInputInfo)(HTOUCHINPUT,UINT,PTOUCHINPUT,int);
+    typedef BOOL (*pCloseTouchInputHandle)(HTOUCHINPUT);
+       static pGetTouchInputInfo fghGetTouchInputInfo = (pGetTouchInputInfo)0xDEADBEEF;
+       static pCloseTouchInputHandle fghCloseTouchInputHandle = (pCloseTouchInputHandle)0xDEADBEEF;
+#endif
 
 /*
  * TODO BEFORE THE STABLE RELEASE:
@@ -122,7 +128,8 @@ static void fghReshapeWindow ( SFG_Window *window, int width, int height )
 
         if ( window->Parent == NULL )
         {
-            if ( ! window->IsMenu && (window != fgStructure.GameModeWindow) )
+          if ( ! window->IsMenu && (window != fgStructure.GameModeWindow) &&
+              !( fgState.DisplayMode & GLUT_BORDERLESS ))
             {
                 w += GetSystemMetrics( SM_CXSIZEFRAME ) * 2;
                 h += GetSystemMetrics( SM_CYSIZEFRAME ) * 2 +
@@ -338,37 +345,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 );
+
+    } else {
+
+        va_start( ap, fmt );
 
-    fprintf( stderr, "freeglut ");
-    if( fgState.ProgramName )
-        fprintf( stderr, "(%s): ", fgState.ProgramName );
-    VFPRINTF( stderr, fmt, ap );
-    fprintf( stderr, "\n" );
+        fprintf( stderr, "freeglut ");
+        if( fgState.ProgramName )
+            fprintf( stderr, "(%s): ", fgState.ProgramName );
+        VFPRINTF( stderr, fmt, ap );
+        fprintf( stderr, "\n" );
 
-    va_end( ap );
+        va_end( ap );
 
-    if ( fgState.Initialised )
-        fgDeinitialize ();
+        if ( fgState.Initialised )
+            fgDeinitialize ();
 
-    exit( 1 );
+        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 );
+
+    } else {
 
-    fprintf( stderr, "freeglut ");
-    if( fgState.ProgramName )
-        fprintf( stderr, "(%s): ", fgState.ProgramName );
-    VFPRINTF( stderr, fmt, ap );
-    fprintf( stderr, "\n" );
+        va_start( ap, fmt );
 
-    va_end( ap );
+        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.
  *
@@ -487,7 +519,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;
 
@@ -1387,6 +1419,13 @@ void FGAPIENTRY glutMainLoopEvent( void )
                     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;
                     }
 
                     /*
@@ -1413,7 +1452,10 @@ void FGAPIENTRY glutMainLoopEvent( void )
             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;
         }
     }
@@ -1566,6 +1608,9 @@ 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;
     LRESULT lRet = 1;
@@ -1579,6 +1624,120 @@ 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:
@@ -1769,6 +1928,7 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam,
             fgUpdateMenuHighlight( window->ActiveMenu );
             break;
         }
+        SetFocus(window->Window.Handle);
 
         fgState.Modifiers = fghGetWin32Modifiers( );
 
@@ -2009,6 +2169,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: */
@@ -2095,6 +2261,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: */
@@ -2283,6 +2455,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 );