Esempio n. 1
0
/* Step through the work list */
void fgProcessWork(SFG_Window *window)
{
    unsigned int workMask = window->State.WorkMask;
    /* Now clear it so that any callback generated by the actions below can set work again */
    window->State.WorkMask = 0;

    if (workMask&~GLUT_DISPLAY_WORK)    /* Display work is the common case, skip all the below at once */
    {
        if (workMask & GLUT_INIT_WORK)
        {
            /* This is before the first display callback: if needed for the platform,
             * call a few callbacks to inform user of window size, position, etc
             */
            fgPlatformInitWork(window);

            /* Call init context callback */
            INVOKE_WCB( *window, InitContext, ());

            /* Lastly, check if we have a display callback, error out if not
             * This is the right place to do it, as the redisplay will be
             * next right after we exit this function, so there is no more
             * opportunity for the user to register a callback for this window.
             */
            if (!FETCH_WCB(*window, Display))
                fgError ( "ERROR:  No display callback registered for window %d\n", window->ID );
        }

        /* On windows we can position, resize and change z order at the same time */
        if (workMask & (GLUT_POSITION_WORK|GLUT_SIZE_WORK|GLUT_ZORDER_WORK|GLUT_FULL_SCREEN_WORK))
        {
            fgPlatformPosResZordWork(window,workMask);
        }

        if (workMask & GLUT_VISIBILITY_WORK)
        {
            fgPlatformVisibilityWork(window);
        }
    }
Esempio n. 2
0
void fgPlatformProcessSingleEvent ( void )
{
    SFG_Window* window;
    XEvent event;

    /* This code was repeated constantly, so here it goes into a definition: */
#define GETWINDOW(a)                             \
    window = fgWindowByHandle( event.a.window ); \
    if( window == NULL )                         \
        break;

#define GETMOUSE(a)                              \
    window->State.MouseX = event.a.x;            \
    window->State.MouseY = event.a.y;

    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMainLoopEvent" );

    while( XPending( fgDisplay.pDisplay.Display ) )
    {
        XNextEvent( fgDisplay.pDisplay.Display, &event );
#if _DEBUG
        fghPrintEvent( &event );
#endif

        switch( event.type )
        {
        case ClientMessage:
            if (fgStructure.CurrentWindow)
                if(fgIsSpaceballXEvent(&event)) {
                    fgSpaceballHandleXEvent(&event);
                    break;
                }
            /* Destroy the window when the WM_DELETE_WINDOW message arrives */
            if( (Atom) event.xclient.data.l[ 0 ] == fgDisplay.pDisplay.DeleteWindow )
            {
                GETWINDOW( xclient );

                fgDestroyWindow ( window );

                if( fgState.ActionOnWindowClose == GLUT_ACTION_EXIT )
                {
                    fgDeinitialize( );
                    exit( 0 );
                }
                else if( fgState.ActionOnWindowClose == GLUT_ACTION_GLUTMAINLOOP_RETURNS )
                    fgState.ExecState = GLUT_EXEC_STATE_STOP;

                return;
            }
            break;

            /*
             * CreateNotify causes a configure-event so that sub-windows are
             * handled compatibly with GLUT.  Otherwise, your sub-windows
             * (in freeglut only) will not get an initial reshape event,
             * which can break things.
             *
             * GLUT presumably does this because it generally tries to treat
             * sub-windows the same as windows.
             */
        case CreateNotify:
        case ConfigureNotify:
            {
                int width, height, x, y;
                if( event.type == CreateNotify ) {
                    GETWINDOW( xcreatewindow );
                    width = event.xcreatewindow.width;
                    height = event.xcreatewindow.height;
                    x = event.xcreatewindow.x;
                    y = event.xcreatewindow.y;
                } else {
                    GETWINDOW( xconfigure );
                    width = event.xconfigure.width;
                    height = event.xconfigure.height;
                    x = event.xconfigure.x;
                    y = event.xconfigure.y;
                }

                /* Update state and call callback, if there was a change */
                fghOnPositionNotify(window, x, y, GL_FALSE);
                /* Update state and call callback, if there was a change */
                fghOnReshapeNotify(window, width, height, GL_FALSE);
            }
            break;

        case DestroyNotify:
            /*
             * This is sent to confirm the XDestroyWindow call.
             *
             * XXX WHY is this commented out?  Should we re-enable it?
             */
            /* fgAddToWindowDestroyList ( window ); */
            break;

        case Expose:
            /*
             * We are too dumb to process partial exposes...
             *
             * XXX Well, we could do it.  However, it seems to only
             * XXX be potentially useful for single-buffered (since
             * XXX double-buffered does not respect viewport when we
             * XXX do a buffer-swap).
             *
             */
            if( event.xexpose.count == 0 )
            {
                GETWINDOW( xexpose );
                window->State.WorkMask |= GLUT_DISPLAY_WORK;
            }
            break;

        case MapNotify:
            break;

        case UnmapNotify:
            /* We get this when iconifying a window. */ 
            GETWINDOW( xunmap );
            INVOKE_WCB( *window, WindowStatus, ( GLUT_HIDDEN ) );
            window->State.Visible = GL_FALSE;
            break;

        case MappingNotify:
            /*
             * Have the client's keyboard knowledge updated (xlib.ps,
             * page 206, says that's a good thing to do)
             */
            XRefreshKeyboardMapping( (XMappingEvent *) &event );
            break;

        case VisibilityNotify:
        {
            /*
             * Sending this event, the X server can notify us that the window
             * has just acquired one of the three possible visibility states:
             * VisibilityUnobscured, VisibilityPartiallyObscured or
             * VisibilityFullyObscured. Note that we DO NOT receive a
             * VisibilityNotify event when iconifying a window, we only get an
             * UnmapNotify then.
             */
            GETWINDOW( xvisibility );
            switch( event.xvisibility.state )
            {
            case VisibilityUnobscured:
                INVOKE_WCB( *window, WindowStatus, ( GLUT_FULLY_RETAINED ) );
                window->State.Visible = GL_TRUE;
                break;

            case VisibilityPartiallyObscured:
                INVOKE_WCB( *window, WindowStatus,
                            ( GLUT_PARTIALLY_RETAINED ) );
                window->State.Visible = GL_TRUE;
                break;

            case VisibilityFullyObscured:
                INVOKE_WCB( *window, WindowStatus, ( GLUT_FULLY_COVERED ) );
                window->State.Visible = GL_FALSE;
                break;

            default:
                fgWarning( "Unknown X visibility state: %d",
                           event.xvisibility.state );
                break;
            }
        }
        break;

        case EnterNotify:
        case LeaveNotify:
            GETWINDOW( xcrossing );
            GETMOUSE( xcrossing );
            if( ( event.type == LeaveNotify ) && window->IsMenu &&
                window->ActiveMenu && window->ActiveMenu->IsActive )
                fgUpdateMenuHighlight( window->ActiveMenu );

            INVOKE_WCB( *window, Entry, ( ( EnterNotify == event.type ) ?
                                          GLUT_ENTERED :
                                          GLUT_LEFT ) );
            break;

        case MotionNotify:
        {
            /* if GLUT_SKIP_STALE_MOTION_EVENTS is true, then discard all but
             * the last motion event from the queue
             */
            if(fgState.SkipStaleMotion) {
                while(XCheckIfEvent(fgDisplay.pDisplay.Display, &event, match_motion, 0));
            }

            GETWINDOW( xmotion );
            GETMOUSE( xmotion );

            if( window->ActiveMenu )
            {
                if( window == window->ActiveMenu->ParentWindow )
                {
                    window->ActiveMenu->Window->State.MouseX =
                        event.xmotion.x_root - window->ActiveMenu->X;
                    window->ActiveMenu->Window->State.MouseY =
                        event.xmotion.y_root - window->ActiveMenu->Y;
                }

                fgUpdateMenuHighlight( window->ActiveMenu );

                break;
            }

            /*
             * XXX For more than 5 buttons, just check {event.xmotion.state},
             * XXX rather than a host of bit-masks?  Or maybe we need to
             * XXX track ButtonPress/ButtonRelease events in our own
             * XXX bit-mask?
             */
            fgState.Modifiers = fgPlatformGetModifiers( 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;
        }
        break;

        case ButtonRelease:
        case ButtonPress:
        {
            GLboolean pressed = GL_TRUE;
            int button;

            if( event.type == ButtonRelease )
                pressed = GL_FALSE ;

            /*
             * A mouse button has been pressed or released. Traditionally,
             * break if the window was found within the freeglut structures.
             */
            GETWINDOW( xbutton );
            GETMOUSE( xbutton );

            /*
             * An X button (at least in XFree86) is numbered from 1.
             * A GLUT button is numbered from 0.
             * Old GLUT passed through buttons other than just the first
             * three, though it only gave symbolic names and official
             * support to the first three.
             */
            button = event.xbutton.button - 1;

            /*
             * Do not execute the application's mouse callback if a menu
             * is hooked to this button.  In that case an appropriate
             * private call should be generated.
             */
            if( fgCheckActiveMenu( window, button, pressed,
                                   event.xbutton.x, event.xbutton.y ) )
                break;

            /*
             * Check if there is a mouse or mouse wheel callback hooked to the
             * window
             */
            if( ! FETCH_WCB( *window, Mouse ) &&
                ! FETCH_WCB( *window, MouseWheel ) )
                break;

            fgState.Modifiers = fgPlatformGetModifiers( event.xbutton.state );

            /* Finally execute the mouse or mouse wheel callback */
            if( ( button < glutDeviceGet ( GLUT_NUM_MOUSE_BUTTONS ) ) || ( ! FETCH_WCB( *window, MouseWheel ) ) )
                INVOKE_WCB( *window, Mouse, ( button,
                                              pressed ? GLUT_DOWN : GLUT_UP,
                                              event.xbutton.x,
                                              event.xbutton.y )
                );
            else
            {
                /*
                 * Map 4 and 5 to wheel zero; EVEN to +1, ODD to -1
                 *  "  6 and 7 "    "   one; ...
                 *
                 * XXX This *should* be behind some variables/macros,
                 * XXX since the order and numbering isn't certain
                 * 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 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;
                if( button % 2 )
                    direction = 1;

                if( pressed )
                    INVOKE_WCB( *window, MouseWheel, ( wheel_number,
                                                       direction,
                                                       event.xbutton.x,
                                                       event.xbutton.y )
                    );
            }
            fgState.Modifiers = INVALID_MODIFIERS;
        }
        break;

        case KeyRelease:
        case KeyPress:
        {
            FGCBKeyboard keyboard_cb;
            FGCBSpecial special_cb;

            GETWINDOW( xkey );
            GETMOUSE( xkey );

            /* Detect auto repeated keys, if configured globally or per-window */

            if ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE )
            {
                if (event.type==KeyRelease)
                {
                    /*
                     * Look at X11 keystate to detect repeat mode.
                     * While X11 says the key is actually held down, we'll ignore KeyRelease/KeyPress pairs.
                     */

                    char keys[32];
                    XQueryKeymap( fgDisplay.pDisplay.Display, keys ); /* Look at X11 keystate to detect repeat mode */

                    if ( event.xkey.keycode<256 )            /* XQueryKeymap is limited to 256 keycodes    */
                    {
                        if ( keys[event.xkey.keycode>>3] & (1<<(event.xkey.keycode%8)) )
                            window->State.pWState.KeyRepeating = GL_TRUE;
                        else
                            window->State.pWState.KeyRepeating = GL_FALSE;
                    }
                }
            }
            else
                window->State.pWState.KeyRepeating = GL_FALSE;

            /* Cease processing this event if it is auto repeated */

            if (window->State.pWState.KeyRepeating)
            {
                if (event.type == KeyPress) window->State.pWState.KeyRepeating = GL_FALSE;
                break;
            }

            if( event.type == KeyPress )
            {
                keyboard_cb = (FGCBKeyboard)( FETCH_WCB( *window, Keyboard ));
                special_cb  = (FGCBSpecial) ( FETCH_WCB( *window, Special  ));
            }
            else
            {
                keyboard_cb = (FGCBKeyboard)( FETCH_WCB( *window, KeyboardUp ));
                special_cb  = (FGCBSpecial) ( FETCH_WCB( *window, SpecialUp  ));
            }

            /* Is there a keyboard/special callback hooked for this window? */
            if( keyboard_cb || special_cb )
            {
                XComposeStatus composeStatus;
                char asciiCode[ 32 ];
                KeySym keySym;
                int len;

                /* Check for the ASCII/KeySym codes associated with the event: */
                len = XLookupString( &event.xkey, asciiCode, sizeof(asciiCode),
                                     &keySym, &composeStatus
                );

                /* GLUT API tells us to have two separate callbacks... */
                if( len > 0 )
                {
                    /* ...one for the ASCII translateable keypresses... */
                    if( keyboard_cb )
                    {
                        fgSetWindow( window );
                        fgState.Modifiers = fgPlatformGetModifiers( event.xkey.state );
                        keyboard_cb( asciiCode[ 0 ],
                                     event.xkey.x, event.xkey.y
                        );
                        fgState.Modifiers = INVALID_MODIFIERS;
                    }
                }
                else
                {
                    int special = -1;

                    /*
                     * ...and one for all the others, which need to be
                     * translated to GLUT_KEY_Xs...
                     */
                    switch( keySym )
                    {
                    case XK_F1:     special = GLUT_KEY_F1;     break;
                    case XK_F2:     special = GLUT_KEY_F2;     break;
                    case XK_F3:     special = GLUT_KEY_F3;     break;
                    case XK_F4:     special = GLUT_KEY_F4;     break;
                    case XK_F5:     special = GLUT_KEY_F5;     break;
                    case XK_F6:     special = GLUT_KEY_F6;     break;
                    case XK_F7:     special = GLUT_KEY_F7;     break;
                    case XK_F8:     special = GLUT_KEY_F8;     break;
                    case XK_F9:     special = GLUT_KEY_F9;     break;
                    case XK_F10:    special = GLUT_KEY_F10;    break;
                    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:
                    case XK_Prior:  special = GLUT_KEY_PAGE_UP; break;
                    case XK_KP_Next:
                    case XK_Next:   special = GLUT_KEY_PAGE_DOWN; break;
                    case XK_KP_Home:
                    case XK_Home:   special = GLUT_KEY_HOME;   break;
                    case XK_KP_End:
                    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;
                    }

                    /*
                     * Execute the callback (if one has been specified),
                     * given that the special code seems to be valid...
                     */
                    if( special_cb && (special != -1) )
                    {
                        fgSetWindow( window );
                        fgState.Modifiers = fgPlatformGetModifiers( event.xkey.state );
                        special_cb( special, event.xkey.x, event.xkey.y );
                        fgState.Modifiers = INVALID_MODIFIERS;
                    }
                }
            }
        }
Esempio n. 3
0
/*
 * The window procedure for handling Win32 events
 */
LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
    SFG_Window *window;
    LRESULT lRet = 1;
    static int setCaptureActive = 0;

    FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Event Handler" ) ;

    window = fgWindowByHandle( hWnd );

    if ( ( window == NULL ) && ( uMsg != WM_CREATE ) )
      return DefWindowProc( hWnd, uMsg, wParam, lParam );

    /* printf ( "Window %3d message <%04x> %12d %12d\n", window?window->ID:0,
             uMsg, wParam, lParam ); */

    switch( uMsg )
    {
    case WM_CREATE:
        /* 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",
                                       "fgPlatformWindowProc" );

        window->Window.Handle = hWnd;
        window->Window.pContext.Device = GetDC( hWnd );
        if( window->IsMenu )
        {
            unsigned int current_DisplayMode = fgState.DisplayMode;
            fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH;
#if !defined(_WIN32_WCE)
            fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE );
#endif
            fgState.DisplayMode = current_DisplayMode;

            if( fgStructure.MenuContext )
                wglMakeCurrent( window->Window.pContext.Device,
                                fgStructure.MenuContext->MContext
                );
            else
            {
                fgStructure.MenuContext =
                    (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) );
                fgStructure.MenuContext->MContext =
                    wglCreateContext( window->Window.pContext.Device );
            }

            /* window->Window.Context = wglGetCurrentContext ();   */
            window->Window.Context = wglCreateContext( window->Window.pContext.Device );
        }
        else
        {
#if !defined(_WIN32_WCE)
            fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE );
#endif

            if( ! fgState.UseCurrentContext )
                window->Window.Context =
                    wglCreateContext( window->Window.pContext.Device );
            else
            {
                window->Window.Context = wglGetCurrentContext( );
                if( ! window->Window.Context )
                    window->Window.Context =
                        wglCreateContext( window->Window.pContext.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;

            fgSetWindow( window );
            window->State.Width = glutGet( GLUT_WINDOW_WIDTH );
            window->State.Height = glutGet( GLUT_WINDOW_HEIGHT );
            fgSetWindow( current_window );
        }

        ReleaseDC( window->Window.Handle, window->Window.pContext.Device );

#if defined(_WIN32_WCE)
        /* Take over button handling */
        {
            HINSTANCE dxDllLib=LoadLibrary(_T("gx.dll"));
            if (dxDllLib)
            {
                GXGetDefaultKeys_=(GXGETDEFAULTKEYS)GetProcAddress(dxDllLib, _T("?GXGetDefaultKeys@@YA?AUGXKeyList@@H@Z"));
                GXOpenInput_=(GXOPENINPUT)GetProcAddress(dxDllLib, _T("?GXOpenInput@@YAHXZ"));
            }

            if(GXOpenInput_)
                (*GXOpenInput_)();
            if(GXGetDefaultKeys_)
                gxKeyList = (*GXGetDefaultKeys_)(GX_LANDSCAPEKEYS);
        }

#endif /* defined(_WIN32_WCE) */
        break;

    case WM_SIZE:
        /* printf("WM_SIZE (ID: %i): wParam: %i, new size: %ix%i \n",window->ID,wParam,LOWORD(lParam),HIWORD(lParam)); */

        /* Update visibility state of the window */
        if (wParam==SIZE_MINIMIZED)
            fghUpdateWindowStatus(window,GL_FALSE);
        else if (wParam==SIZE_RESTORED && !window->State.Visible)
            fghUpdateWindowStatus(window,GL_TRUE);

        /* Check window visible, we don't want to resize when the user or glutIconifyWindow minimized the window */
        if( window->State.Visible )
        {
            /* get old values first to compare to below */
            int width = window->State.Width, height=window->State.Height;
#if defined(_WIN32_WCE)
            window->State.Width  = HIWORD(lParam);
            window->State.Height = LOWORD(lParam);
#else
            window->State.Width  = LOWORD(lParam);
            window->State.Height = HIWORD(lParam);
#endif /* defined(_WIN32_WCE) */
            
            if (width!=window->State.Width || height!=window->State.Height)
            {
                SFG_Window* saved_window = fgStructure.CurrentWindow;
                
                /* size changed, call reshape callback */
                INVOKE_WCB( *window, Reshape, ( width, height ) );
                glutPostRedisplay( );
                if( window->IsMenu )
                    fgSetWindow( saved_window );
            }
        }

        /* according to docs, should return 0 */
        lRet = 0;
        break;

    case WM_MOVE:
        {
            SFG_Window* saved_window = fgStructure.CurrentWindow;
            RECT windowRect;

            /* Check window is minimized, we don't want to call the position callback when the user or glutIconifyWindow minimized the window */
            if (!IsIconic(window->Window.Handle))
            {
                /* Get top-left of non-client area of window, matching coordinates of
                 * glutInitPosition and glutPositionWindow, but not those of 
                 * glutGet(GLUT_WINDOW_X) and glutGet(GLUT_WINDOW_Y), which return
                 * top-left of client area.
                 */
                GetWindowRect( window->Window.Handle, &windowRect );
            
                if (window->Parent)
                {
                    /* For child window, we should return relative to upper-left
                     * of parent's client area.
                     */
                    POINT topleft = {windowRect.left,windowRect.top};

                    ScreenToClient(window->Parent->Window.Handle,&topleft);
                    windowRect.left = topleft.x;
                    windowRect.top  = topleft.y;
                }

                INVOKE_WCB( *window, Position, ( windowRect.left, windowRect.top ) );
                fgSetWindow(saved_window);
            }
        }

        /* according to docs, should return 0 */
        lRet = 0;
        break;

    case WM_SETFOCUS:
        /*printf("WM_SETFOCUS: %p\n", window );*/
        lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );

        SetActiveWindow( window->Window.Handle );
        UpdateWindow ( hWnd );

        break;

    case WM_KILLFOCUS:
        /*printf("WM_KILLFOCUS: %p\n", window ); */
        lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );

        /* Check if there are any open menus that need to be closed */
        fgPlatformCheckMenuDeactivate();
        break;

#if 0
    case WM_ACTIVATE:
        //printf("WM_ACTIVATE: %x (ID: %i) %d %d\n",lParam, window->ID, HIWORD(wParam), LOWORD(wParam));
        if (LOWORD(wParam) != WA_INACTIVE)
        {
/*            printf("WM_ACTIVATE: fgSetCursor( %p, %d)\n", window,
                   window->State.Cursor ); */
            fgSetCursor( window, window->State.Cursor );
        }

        lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
        break;
#endif

    case WM_SETCURSOR:
/*      printf ( "Cursor event %x %x %x %x\n", window, window->State.Cursor, lParam, wParam ) ; */
        if( LOWORD( lParam ) == HTCLIENT )
        {
            if (!window->State.pWState.MouseTracking)
            {
                TRACKMOUSEEVENT tme;

                /* Cursor just entered window, set cursor look */ 
                fgSetCursor ( window, window->State.Cursor ) ;

                /* If an EntryFunc callback is specified by the user, also
                 * invoke that callback and start mouse tracking so that
                 * we get a WM_MOUSELEAVE message
                 */
                if (FETCH_WCB( *window, Entry ))
                {
                    SFG_Window* saved_window = fgStructure.CurrentWindow;
                    INVOKE_WCB( *window, Entry, ( GLUT_ENTERED ) );
                    fgSetWindow(saved_window);

                    tme.cbSize = sizeof(TRACKMOUSEEVENT);
                    tme.dwFlags = TME_LEAVE;
                    tme.hwndTrack = window->Window.Handle;
                    TrackMouseEvent(&tme);

                    window->State.pWState.MouseTracking = GL_TRUE;
                }
            }
        }
        else
            /* Only pass non-client WM_SETCURSOR to DefWindowProc, or we get WM_SETCURSOR on parents of children as well */
            lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
        break;

    case WM_MOUSELEAVE:
        {
            /* NB: This message is only received when a EntryFunc callback
             * is specified by the user, as that is the only condition under
             * which mouse tracking is setup in WM_SETCURSOR handler above
             */
            SFG_Window* saved_window = fgStructure.CurrentWindow;
            INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) );
            fgSetWindow(saved_window);

            window->State.pWState.MouseTracking = GL_FALSE;
            lRet = 0;   /* As per docs, must return zero */
        }
        break;

    case WM_SHOWWINDOW:
        /* printf("WM_SHOWWINDOW, shown? %i, source: %i\n",wParam,lParam); */
        if (wParam)
        {
            fghUpdateWindowStatus(window, GL_TRUE);
            window->State.Redisplay = GL_TRUE;
        }
        else
        {
            fghUpdateWindowStatus(window, GL_FALSE);
            window->State.Redisplay = GL_FALSE;
        }
        break;

    case WM_PAINT:
    {
        RECT rect;

        if (GetUpdateRect(hWnd,&rect,FALSE))
        {
            /* As per docs, upon receiving WM_PAINT, first check if the update region is not empty before you call BeginPaint */
            PAINTSTRUCT ps;

            /* Turn on the visibility in case it was turned off somehow */
            window->State.Visible = GL_TRUE;

            InvalidateRect( hWnd, NULL, GL_FALSE );
            BeginPaint( hWnd, &ps );
            fghRedrawWindow( window );
            EndPaint( hWnd, &ps );
        }
        lRet = 0;   /* As per docs, should return 0 */
    }
    break;

    case WM_CLOSE:
        fgDestroyWindow ( window );
        if ( fgState.ActionOnWindowClose != GLUT_ACTION_CONTINUE_EXECUTION )
            PostQuitMessage(0);
        break;

    case WM_DESTROY:
        /*
         * The window already got destroyed, so don't bother with it.
         */
        return 0;

    case WM_MOUSEMOVE:
    {
        /* Per docs, use LOWORD/HIWORD for WinCE and GET_X_LPARAM/GET_Y_LPARAM for desktop windows */
#if defined(_WIN32_WCE)
        window->State.MouseX = 320-HIWORD( lParam );    /* XXX: Docs say x should be loword and y hiword? */
        window->State.MouseY = LOWORD( lParam );
#else
        window->State.MouseX = GET_X_LPARAM( lParam );
        window->State.MouseY = GET_Y_LPARAM( lParam );
#endif /* defined(_WIN32_WCE) */
        /* Restrict to [-32768, 32767] to match X11 behaviour       */
        /* See comment in "freeglut_developer" mailing list 10/4/04 */
        if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
        if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;

        if ( window->ActiveMenu )
        {
            fgUpdateMenuHighlight( window->ActiveMenu );
            break;
        }

        fgState.Modifiers = fgPlatformGetModifiers( );

        if( ( wParam & MK_LBUTTON ) ||
            ( wParam & MK_MBUTTON ) ||
            ( wParam & MK_RBUTTON ) )
            INVOKE_WCB( *window, Motion, ( window->State.MouseX,
                                           window->State.MouseY ) );
        else
            INVOKE_WCB( *window, Passive, ( window->State.MouseX,
                                            window->State.MouseY ) );

        fgState.Modifiers = INVALID_MODIFIERS;
    }
    break;

    case WM_LBUTTONDOWN:
    case WM_MBUTTONDOWN:
    case WM_RBUTTONDOWN:
    case WM_LBUTTONUP:
    case WM_MBUTTONUP:
    case WM_RBUTTONUP:
    {
        GLboolean pressed = GL_TRUE;
        int button;

        /* Per docs, use LOWORD/HIWORD for WinCE and GET_X_LPARAM/GET_Y_LPARAM for desktop windows */
#if defined(_WIN32_WCE)
        window->State.MouseX = 320-HIWORD( lParam );    /* XXX: Docs say x should be loword and y hiword? */
        window->State.MouseY = LOWORD( lParam );
#else
        window->State.MouseX = GET_X_LPARAM( lParam );
        window->State.MouseY = GET_Y_LPARAM( lParam );
#endif /* defined(_WIN32_WCE) */

        /* Restrict to [-32768, 32767] to match X11 behaviour       */
        /* See comment in "freeglut_developer" mailing list 10/4/04 */
        if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
        if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;

        switch( uMsg )
        {
        case WM_LBUTTONDOWN:
            pressed = GL_TRUE;
            button = GLUT_LEFT_BUTTON;
            break;
        case WM_MBUTTONDOWN:
            pressed = GL_TRUE;
            button = GLUT_MIDDLE_BUTTON;
            break;
        case WM_RBUTTONDOWN:
            pressed = GL_TRUE;
            button = GLUT_RIGHT_BUTTON;
            break;
        case WM_LBUTTONUP:
            pressed = GL_FALSE;
            button = GLUT_LEFT_BUTTON;
            break;
        case WM_MBUTTONUP:
            pressed = GL_FALSE;
            button = GLUT_MIDDLE_BUTTON;
            break;
        case WM_RBUTTONUP:
            pressed = GL_FALSE;
            button = GLUT_RIGHT_BUTTON;
            break;
        default:
            pressed = GL_FALSE;
            button = -1;
            break;
        }

#if !defined(_WIN32_WCE)
        if( GetSystemMetrics( SM_SWAPBUTTON ) )
        {
            if( button == GLUT_LEFT_BUTTON )
                button = GLUT_RIGHT_BUTTON;
            else
                if( button == GLUT_RIGHT_BUTTON )
                    button = GLUT_LEFT_BUTTON;
        }
#endif /* !defined(_WIN32_WCE) */

        if( button == -1 )
            return DefWindowProc( hWnd, uMsg, lParam, wParam );

        /*
         * Do not execute the application's mouse callback if a menu
         * is hooked to this button.  In that case an appropriate
         * private call should be generated.
         */
        if( fgCheckActiveMenu( window, button, pressed,
                               window->State.MouseX, window->State.MouseY ) )
            break;

        /* Set capture so that the window captures all the mouse messages
         *
         * The mouse is not released from the window until all buttons have
         * been released, even if the user presses a button in another window.
         * This is consistent with the behavior on X11.
         */
        if ( pressed == GL_TRUE )
        {
            if (!setCaptureActive)
                SetCapture ( window->Window.Handle ) ;
            setCaptureActive = 1; /* Set to false in WM_CAPTURECHANGED handler */
        }
        else if (!GetAsyncKeyState(VK_LBUTTON) && !GetAsyncKeyState(VK_MBUTTON) && !GetAsyncKeyState(VK_RBUTTON))
          /* Make sure all mouse buttons are released before releasing capture */
          ReleaseCapture () ;

        if( ! FETCH_WCB( *window, Mouse ) )
            break;

        fgSetWindow( window );
        fgState.Modifiers = fgPlatformGetModifiers( );

        INVOKE_WCB(
            *window, Mouse,
            ( button,
              pressed ? GLUT_DOWN : GLUT_UP,
              window->State.MouseX,
              window->State.MouseY
            )
        );

        fgState.Modifiers = INVALID_MODIFIERS;

        /* As per docs, should return zero */
        lRet = 0;
    }
    break;

    case WM_MOUSEWHEEL:
    {
        int wheel_number = 0;   /* Only one scroll wheel on windows */
#if defined(_WIN32_WCE)
        int modkeys = LOWORD(wParam); 
        short ticks = (short)HIWORD(wParam);
        /* commented out as should not be needed here, mouse motion is processed in WM_MOUSEMOVE first:
        xPos = LOWORD(lParam);  -- straight from docs, not consistent with mouse nutton and mouse motion above (which i think is wrong)
        yPos = HIWORD(lParam);
        */
#else
        /* int modkeys = GET_KEYSTATE_WPARAM( wParam ); */
        short ticks = GET_WHEEL_DELTA_WPARAM( wParam );
        /* commented out as should not be needed here, mouse motion is processed in WM_MOUSEMOVE first:
        window->State.MouseX = GET_X_LPARAM( lParam );
        window->State.MouseY = GET_Y_LPARAM( lParam );
        */
#endif /* defined(_WIN32_WCE) */

        window = fghWindowUnderCursor(window);

		fgState.MouseWheelTicks += ticks;
        if ( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA )
		{
			int direction = ( fgState.MouseWheelTicks > 0 ) ? 1 : -1;

            if( ! FETCH_WCB( *window, MouseWheel ) &&
                ! FETCH_WCB( *window, Mouse ) )
                break;

            fgSetWindow( window );
            fgState.Modifiers = fgPlatformGetModifiers( );

            while( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA )
			{
                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 )
                    );
				}

				fgState.MouseWheelTicks -= WHEEL_DELTA * direction;
			}

            fgState.Modifiers = INVALID_MODIFIERS;
		}
        /* Per docs, should return zero */
        lRet = 0;
    }
    break ;

    case WM_SYSKEYDOWN:
    case WM_KEYDOWN:
    {
        window = fghWindowUnderCursor(window);
        lRet = fghWindowProcKeyPress(window,uMsg,GL_TRUE,wParam,lParam);
    }
    break;

    case WM_SYSKEYUP:
    case WM_KEYUP:
    {
        window = fghWindowUnderCursor(window);
        lRet = fghWindowProcKeyPress(window,uMsg,GL_FALSE,wParam,lParam);
    }
    break;

    case WM_SYSCHAR:
    case WM_CHAR:
    {
      window = fghWindowUnderCursor(window);

      if( (fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE) && (HIWORD(lParam) & KF_REPEAT) )
            break;

        fgState.Modifiers = fgPlatformGetModifiers( );
        INVOKE_WCB( *window, Keyboard,
                    ( (char)wParam,
                      window->State.MouseX, window->State.MouseY )
        );
        fgState.Modifiers = INVALID_MODIFIERS;
    }
    break;

    case WM_CAPTURECHANGED:
        if (!lParam || !fgWindowByHandle((HWND)lParam))
            /* Capture released or capture taken by non-FreeGLUT window */
            setCaptureActive = 0;
        /* Docs advise a redraw */
        InvalidateRect( hWnd, NULL, GL_FALSE );
        UpdateWindow(hWnd);
        lRet = 0;   /* Per docs, should return zero */
        break;

#if !defined(_WIN32_WCE)
    case WM_SYNCPAINT:  /* 0x0088 */
        /* Another window has moved, need to update this one */
        window->State.Redisplay = GL_TRUE;
        lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
        /* Help screen says this message must be passed to "DefWindowProc" */
        break;

    case WM_SYSCOMMAND :  /* 0x0112 */
        {
          /*
           * We have received a system command message.  Try to act on it.
           * The commands are passed in through the "wParam" parameter:
           * The least significant digit seems to be which edge of the window
           * is being used for a resize event:
           *     4  3  5
           *     1     2
           *     7  6  8
           * Congratulations and thanks to Richard Rauch for figuring this out..
           */
            switch ( wParam & 0xfff0 )
            {
            case SC_SIZE       :
                break ;

            case SC_MOVE       :
                break ;

            case SC_MINIMIZE   :
                /* User has clicked on the "-" to minimize the window */
                /* Turning off the visibility is handled in WM_SIZE handler */

                break ;

            case SC_MAXIMIZE   :
                break ;

            case SC_NEXTWINDOW :
                break ;

            case SC_PREVWINDOW :
                break ;

            case SC_CLOSE      :
                /* Followed very closely by a WM_CLOSE message */
                break ;

            case SC_VSCROLL    :
                break ;

            case SC_HSCROLL    :
                break ;

            case SC_MOUSEMENU  :
                break ;

            case SC_KEYMENU    :
                break ;

            case SC_ARRANGE    :
                break ;

            case SC_RESTORE    :
                break ;

            case SC_TASKLIST   :
                break ;

            case SC_SCREENSAVE :
                break ;

            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 );
#endif
                break;
            }
        }
#endif /* !defined(_WIN32_WCE) */

        /* We need to pass the message on to the operating system as well */
        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 );
        break;
    }

    return lRet;
}
Esempio n. 4
0
/*
 * The window procedure for handling Win32 events
 */
LRESULT CALLBACK fgPlatformWindowProc( 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;

    FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Event Handler" ) ;

    window = fgWindowByHandle( hWnd );

    if ( ( window == NULL ) && ( uMsg != WM_CREATE ) )
      return DefWindowProc( hWnd, uMsg, wParam, lParam );

    /* 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 parameter... */
        window = (SFG_Window *) (((LPCREATESTRUCT) lParam)->lpCreateParams);
        FREEGLUT_INTERNAL_ERROR_EXIT ( ( window != NULL ), "Cannot create window",
                                       "fgPlatformWindowProc" );

        window->Window.Handle = hWnd;
        window->Window.pContext.Device = GetDC( hWnd );
        if( window->IsMenu )
        {
            unsigned int current_DisplayMode = fgState.DisplayMode;
            fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH;
#if !defined(_WIN32_WCE)
            fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE );
#endif
            fgState.DisplayMode = current_DisplayMode;

            if( fgStructure.MenuContext )
                wglMakeCurrent( window->Window.pContext.Device,
                                fgStructure.MenuContext->MContext
                );
            else
            {
                fgStructure.MenuContext =
                    (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) );
                fgStructure.MenuContext->MContext =
                    wglCreateContext( window->Window.pContext.Device );
            }

            /* window->Window.Context = wglGetCurrentContext ();   */
            window->Window.Context = wglCreateContext( window->Window.pContext.Device );
        }
        else
        {
#if !defined(_WIN32_WCE)
            fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE );
#endif

            if( ! fgState.UseCurrentContext )
                window->Window.Context =
                    wglCreateContext( window->Window.pContext.Device );
            else
            {
                window->Window.Context = wglGetCurrentContext( );
                if( ! window->Window.Context )
                    window->Window.Context =
                        wglCreateContext( window->Window.pContext.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;

            fgSetWindow( window );
            window->State.Width = glutGet( GLUT_WINDOW_WIDTH );
            window->State.Height = glutGet( GLUT_WINDOW_HEIGHT );
            fgSetWindow( current_window );
        }

        ReleaseDC( window->Window.Handle, window->Window.pContext.Device );

#if defined(_WIN32_WCE)
        /* Take over button handling */
        {
            HINSTANCE dxDllLib=LoadLibrary(_T("gx.dll"));
            if (dxDllLib)
            {
                GXGetDefaultKeys_=(GXGETDEFAULTKEYS)GetProcAddress(dxDllLib, _T("?GXGetDefaultKeys@@YA?AUGXKeyList@@H@Z"));
                GXOpenInput_=(GXOPENINPUT)GetProcAddress(dxDllLib, _T("?GXOpenInput@@YAHXZ"));
            }

            if(GXOpenInput_)
                (*GXOpenInput_)();
            if(GXGetDefaultKeys_)
                gxKeyList = (*GXGetDefaultKeys_)(GX_LANDSCAPEKEYS);
        }

#endif /* defined(_WIN32_WCE) */
        break;

    case WM_SIZE:
        /*
         * If the window is visible, then it is the user manually resizing it.
         * If it is not, then it is the system sending us a dummy resize with
         * zero dimensions on a "glutIconifyWindow" call.
         */
        if( window->State.Visible )
        {
            window->State.NeedToResize = GL_TRUE;
#if defined(_WIN32_WCE)
            window->State.Width  = HIWORD(lParam);
            window->State.Height = LOWORD(lParam);
#else
            window->State.Width  = LOWORD(lParam);
            window->State.Height = HIWORD(lParam);
#endif /* defined(_WIN32_WCE) */
        }

        break;

    case WM_SETFOCUS:
/*        printf("WM_SETFOCUS: %p\n", window ); */
        lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
        INVOKE_WCB( *window, Entry, ( GLUT_ENTERED ) );

		UpdateWindow ( hWnd );
        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)
        {
/*            printf("WM_ACTIVATE: fgSetCursor( %p, %d)\n", window,
                   window->State.Cursor ); */
            fgSetCursor( window, window->State.Cursor );
        }

        lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
        break;
#endif

    case WM_SETCURSOR:
/*      printf ( "Cursor event %x %x %x %x\n", window, window->State.Cursor, lParam, wParam ) ; */
        if( LOWORD( lParam ) == HTCLIENT )
            fgSetCursor ( window, window->State.Cursor ) ;
        else
            lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
        break;

    case WM_SHOWWINDOW:
        window->State.Visible = GL_TRUE;
        window->State.Redisplay = GL_TRUE;
        break;

    case WM_PAINT:
        /* Turn on the visibility in case it was turned off somehow */
        window->State.Visible = GL_TRUE;
        BeginPaint( hWnd, &ps );
        fghRedrawWindow( window );
        EndPaint( hWnd, &ps );
        break;

    case WM_CLOSE:
        fgDestroyWindow ( window );
        if ( fgState.ActionOnWindowClose != GLUT_ACTION_CONTINUE_EXECUTION )
            PostQuitMessage(0);
        break;

    case WM_DESTROY:
        /*
         * The window already got destroyed, so don't bother with it.
         */
        return 0;

    case WM_MOUSEMOVE:
    {
#if defined(_WIN32_WCE)
        window->State.MouseX = 320-HIWORD( lParam );
        window->State.MouseY = LOWORD( lParam );
#else
        window->State.MouseX = LOWORD( lParam );
        window->State.MouseY = HIWORD( lParam );
#endif /* defined(_WIN32_WCE) */
        /* Restrict to [-32768, 32767] to match X11 behaviour       */
        /* See comment in "freeglut_developer" mailing list 10/4/04 */
        if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
        if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;

        if ( window->ActiveMenu )
        {
            fgUpdateMenuHighlight( window->ActiveMenu );
            break;
        }
        SetFocus(window->Window.Handle);

        fgState.Modifiers = fgPlatformGetModifiers( );

        if( ( wParam & MK_LBUTTON ) ||
            ( wParam & MK_MBUTTON ) ||
            ( wParam & MK_RBUTTON ) )
            INVOKE_WCB( *window, Motion, ( window->State.MouseX,
                                           window->State.MouseY ) );
        else
            INVOKE_WCB( *window, Passive, ( window->State.MouseX,
                                            window->State.MouseY ) );

        fgState.Modifiers = INVALID_MODIFIERS;
    }
    break;

    case WM_LBUTTONDOWN:
    case WM_MBUTTONDOWN:
    case WM_RBUTTONDOWN:
    case WM_LBUTTONUP:
    case WM_MBUTTONUP:
    case WM_RBUTTONUP:
    {
        GLboolean pressed = GL_TRUE;
        int button;

#if defined(_WIN32_WCE)
        window->State.MouseX = 320-HIWORD( lParam );
        window->State.MouseY = LOWORD( lParam );
#else
        window->State.MouseX = LOWORD( lParam );
        window->State.MouseY = HIWORD( lParam );
#endif /* defined(_WIN32_WCE) */

        /* Restrict to [-32768, 32767] to match X11 behaviour       */
        /* See comment in "freeglut_developer" mailing list 10/4/04 */
        if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
        if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;

        switch( uMsg )
        {
        case WM_LBUTTONDOWN:
            pressed = GL_TRUE;
            button = GLUT_LEFT_BUTTON;
            break;
        case WM_MBUTTONDOWN:
            pressed = GL_TRUE;
            button = GLUT_MIDDLE_BUTTON;
            break;
        case WM_RBUTTONDOWN:
            pressed = GL_TRUE;
            button = GLUT_RIGHT_BUTTON;
            break;
        case WM_LBUTTONUP:
            pressed = GL_FALSE;
            button = GLUT_LEFT_BUTTON;
            break;
        case WM_MBUTTONUP:
            pressed = GL_FALSE;
            button = GLUT_MIDDLE_BUTTON;
            break;
        case WM_RBUTTONUP:
            pressed = GL_FALSE;
            button = GLUT_RIGHT_BUTTON;
            break;
        default:
            pressed = GL_FALSE;
            button = -1;
            break;
        }

#if !defined(_WIN32_WCE)
        if( GetSystemMetrics( SM_SWAPBUTTON ) )
        {
            if( button == GLUT_LEFT_BUTTON )
                button = GLUT_RIGHT_BUTTON;
            else
                if( button == GLUT_RIGHT_BUTTON )
                    button = GLUT_LEFT_BUTTON;
        }
#endif /* !defined(_WIN32_WCE) */

        if( button == -1 )
            return DefWindowProc( hWnd, uMsg, lParam, wParam );

        /*
         * Do not execute the application's mouse callback if a menu
         * is hooked to this button.  In that case an appropriate
         * private call should be generated.
         */
        if( fgCheckActiveMenu( window, button, pressed,
                               window->State.MouseX, window->State.MouseY ) )
            break;

        /* Set capture so that the window captures all the mouse messages */
        /*
         * XXX - Multiple button support:  Under X11, the mouse is not released
         * XXX - from the window until all buttons have been released, even if the
         * XXX - user presses a button in another window.  This will take more
         * XXX - code changes than I am up to at the moment (10/5/04).  The present
         * XXX - is a 90 percent solution.
         */
        if ( pressed == GL_TRUE )
          SetCapture ( window->Window.Handle ) ;
        else
          ReleaseCapture () ;

        if( ! FETCH_WCB( *window, Mouse ) )
            break;

        fgSetWindow( window );
        fgState.Modifiers = fgPlatformGetModifiers( );

        INVOKE_WCB(
            *window, Mouse,
            ( button,
              pressed ? GLUT_DOWN : GLUT_UP,
              window->State.MouseX,
              window->State.MouseY
            )
        );

        fgState.Modifiers = INVALID_MODIFIERS;
    }
    break;

    case 0x020a:
        /* Should be WM_MOUSEWHEEL but my compiler doesn't recognize it */
    {
        int wheel_number = LOWORD( wParam );
        short ticks = ( short )HIWORD( wParam );
		fgState.MouseWheelTicks += ticks;

        /*
         * XXX Should use WHEEL_DELTA instead of 120
         */
		if ( abs ( fgState.MouseWheelTicks ) > 120 )
		{
			int direction = ( fgState.MouseWheelTicks > 0 ) ? 1 : -1;

            if( ! FETCH_WCB( *window, MouseWheel ) &&
                ! FETCH_WCB( *window, Mouse ) )
                break;

            fgSetWindow( window );
            fgState.Modifiers = fgPlatformGetModifiers( );

            /*
             * 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 )
                    );
				}

                /*
                 * XXX Should use WHEEL_DELTA instead of 120
                 */
				fgState.MouseWheelTicks -= 120 * direction;
			}

            fgState.Modifiers = INVALID_MODIFIERS;
		}
    }
    break ;

    case WM_SYSKEYDOWN:
    case WM_KEYDOWN:
    {
        int keypress = -1;
        POINT mouse_pos ;

        if( ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE ) && (HIWORD(lParam) & KF_REPEAT) )
            break;

        /*
         * Remember the current modifiers state. This is done here in order
         * to make sure the VK_DELETE keyboard callback is executed properly.
         */
        fgState.Modifiers = fgPlatformGetModifiers( );

        GetCursorPos( &mouse_pos );
        ScreenToClient( window->Window.Handle, &mouse_pos );

        window->State.MouseX = mouse_pos.x;
        window->State.MouseY = mouse_pos.y;

        /* Convert the Win32 keystroke codes to GLUTtish way */
#       define KEY(a,b) case a: keypress = b; break;

        switch( wParam )
        {
            KEY( VK_F1,     GLUT_KEY_F1        );
            KEY( VK_F2,     GLUT_KEY_F2        );
            KEY( VK_F3,     GLUT_KEY_F3        );
            KEY( VK_F4,     GLUT_KEY_F4        );
            KEY( VK_F5,     GLUT_KEY_F5        );
            KEY( VK_F6,     GLUT_KEY_F6        );
            KEY( VK_F7,     GLUT_KEY_F7        );
            KEY( VK_F8,     GLUT_KEY_F8        );
            KEY( VK_F9,     GLUT_KEY_F9        );
            KEY( VK_F10,    GLUT_KEY_F10       );
            KEY( VK_F11,    GLUT_KEY_F11       );
            KEY( VK_F12,    GLUT_KEY_F12       );
            KEY( VK_PRIOR,  GLUT_KEY_PAGE_UP   );
            KEY( VK_NEXT,   GLUT_KEY_PAGE_DOWN );
            KEY( VK_HOME,   GLUT_KEY_HOME      );
            KEY( VK_END,    GLUT_KEY_END       );
            KEY( VK_LEFT,   GLUT_KEY_LEFT      );
            KEY( VK_UP,     GLUT_KEY_UP        );
            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: */
            INVOKE_WCB( *window, Keyboard,
                        ( 127, window->State.MouseX, window->State.MouseY )
            );
        }

#if defined(_WIN32_WCE)
        if(!(lParam & 0x40000000)) /* Prevent auto-repeat */
        {
            if(wParam==(unsigned)gxKeyList.vkRight)
                keypress = GLUT_KEY_RIGHT;
            else if(wParam==(unsigned)gxKeyList.vkLeft)
                keypress = GLUT_KEY_LEFT;
            else if(wParam==(unsigned)gxKeyList.vkUp)
                keypress = GLUT_KEY_UP;
            else if(wParam==(unsigned)gxKeyList.vkDown)
                keypress = GLUT_KEY_DOWN;
            else if(wParam==(unsigned)gxKeyList.vkA)
                keypress = GLUT_KEY_F1;
            else if(wParam==(unsigned)gxKeyList.vkB)
                keypress = GLUT_KEY_F2;
            else if(wParam==(unsigned)gxKeyList.vkC)
                keypress = GLUT_KEY_F3;
            else if(wParam==(unsigned)gxKeyList.vkStart)
                keypress = GLUT_KEY_F4;
        }
#endif

        if( keypress != -1 )
            INVOKE_WCB( *window, Special,
                        ( keypress,
                          window->State.MouseX, window->State.MouseY )
            );

        fgState.Modifiers = INVALID_MODIFIERS;
    }
    break;

    case WM_SYSKEYUP:
    case WM_KEYUP:
    {
        int keypress = -1;
        POINT mouse_pos;

        /*
         * Remember the current modifiers state. This is done here in order
         * to make sure the VK_DELETE keyboard callback is executed properly.
         */
        fgState.Modifiers = fgPlatformGetModifiers( );

        GetCursorPos( &mouse_pos );
        ScreenToClient( window->Window.Handle, &mouse_pos );

        window->State.MouseX = mouse_pos.x;
        window->State.MouseY = mouse_pos.y;

        /*
         * Convert the Win32 keystroke codes to GLUTtish way.
         * "KEY(a,b)" was defined under "WM_KEYDOWN"
         */

        switch( wParam )
        {
            KEY( VK_F1,     GLUT_KEY_F1        );
            KEY( VK_F2,     GLUT_KEY_F2        );
            KEY( VK_F3,     GLUT_KEY_F3        );
            KEY( VK_F4,     GLUT_KEY_F4        );
            KEY( VK_F5,     GLUT_KEY_F5        );
            KEY( VK_F6,     GLUT_KEY_F6        );
            KEY( VK_F7,     GLUT_KEY_F7        );
            KEY( VK_F8,     GLUT_KEY_F8        );
            KEY( VK_F9,     GLUT_KEY_F9        );
            KEY( VK_F10,    GLUT_KEY_F10       );
            KEY( VK_F11,    GLUT_KEY_F11       );
            KEY( VK_F12,    GLUT_KEY_F12       );
            KEY( VK_PRIOR,  GLUT_KEY_PAGE_UP   );
            KEY( VK_NEXT,   GLUT_KEY_PAGE_DOWN );
            KEY( VK_HOME,   GLUT_KEY_HOME      );
            KEY( VK_END,    GLUT_KEY_END       );
            KEY( VK_LEFT,   GLUT_KEY_LEFT      );
            KEY( VK_UP,     GLUT_KEY_UP        );
            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: */
              INVOKE_WCB( *window, KeyboardUp,
                          ( 127, window->State.MouseX, window->State.MouseY )
              );
              break;

        default:
        {
#if !defined(_WIN32_WCE)
            BYTE state[ 256 ];
            WORD code[ 2 ];

            GetKeyboardState( state );

            if( ToAscii( (UINT)wParam, 0, state, code, 0 ) == 1 )
                wParam=code[ 0 ];

            INVOKE_WCB( *window, KeyboardUp,
                        ( (char)wParam,
                          window->State.MouseX, window->State.MouseY )
            );
#endif /* !defined(_WIN32_WCE) */
        }
        }

        if( keypress != -1 )
            INVOKE_WCB( *window, SpecialUp,
                        ( keypress,
                          window->State.MouseX, window->State.MouseY )
            );

        fgState.Modifiers = INVALID_MODIFIERS;
    }
    break;

    case WM_SYSCHAR:
    case WM_CHAR:
    {
      if( (fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE) && (HIWORD(lParam) & KF_REPEAT) )
            break;

        fgState.Modifiers = fgPlatformGetModifiers( );
        INVOKE_WCB( *window, Keyboard,
                    ( (char)wParam,
                      window->State.MouseX, window->State.MouseY )
        );
        fgState.Modifiers = INVALID_MODIFIERS;
    }
    break;

    case WM_CAPTURECHANGED:
        /* User has finished resizing the window, force a redraw */
        INVOKE_WCB( *window, Display, ( ) );

        /*lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); */
        break;

        /* Other messages that I have seen and which are not handled already */
    case WM_SETTEXT:  /* 0x000c */
        lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
        /* Pass it on to "DefWindowProc" to set the window text */
        break;

    case WM_GETTEXT:  /* 0x000d */
        /* Ideally we would copy the title of the window into "lParam" */
        /* strncpy ( (char *)lParam, "Window Title", wParam );
           lRet = ( wParam > 12 ) ? 12 : wParam;  */
        /* the number of characters copied */
        lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
        break;

    case WM_GETTEXTLENGTH:  /* 0x000e */
        /* Ideally we would get the length of the title of the window */
        lRet = 12;
        /* the number of characters in "Window Title\0" (see above) */
        break;

    case WM_ERASEBKGND:  /* 0x0014 */
        lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
        break;

#if !defined(_WIN32_WCE)
    case WM_SYNCPAINT:  /* 0x0088 */
        /* Another window has moved, need to update this one */
        window->State.Redisplay = GL_TRUE;
        lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
        /* Help screen says this message must be passed to "DefWindowProc" */
        break;

    case WM_NCPAINT:  /* 0x0085 */
      /* Need to update the border of this window */
        lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
        /* Pass it on to "DefWindowProc" to repaint a standard border */
        break;

    case WM_SYSCOMMAND :  /* 0x0112 */
        {
          /*
           * We have received a system command message.  Try to act on it.
           * The commands are passed in through the "wParam" parameter:
           * The least significant digit seems to be which edge of the window
           * is being used for a resize event:
           *     4  3  5
           *     1     2
           *     7  6  8
           * Congratulations and thanks to Richard Rauch for figuring this out..
           */
            switch ( wParam & 0xfff0 )
            {
            case SC_SIZE       :
                break ;

            case SC_MOVE       :
                break ;

            case SC_MINIMIZE   :
                /* User has clicked on the "-" to minimize the window */
                /* Turn off the visibility */
                window->State.Visible = GL_FALSE ;

                break ;

            case SC_MAXIMIZE   :
                break ;

            case SC_NEXTWINDOW :
                break ;

            case SC_PREVWINDOW :
                break ;

            case SC_CLOSE      :
                /* Followed very closely by a WM_CLOSE message */
                break ;

            case SC_VSCROLL    :
                break ;

            case SC_HSCROLL    :
                break ;

            case SC_MOUSEMENU  :
                break ;

            case SC_KEYMENU    :
                break ;

            case SC_ARRANGE    :
                break ;

            case SC_RESTORE    :
                break ;

            case SC_TASKLIST   :
                break ;

            case SC_SCREENSAVE :
                break ;

            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 );
#endif
                break;
            }
        }
#endif /* !defined(_WIN32_WCE) */

        /* We need to pass the message on to the operating system as well */
        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 );
        break;
    }

    return lRet;
}
Esempio n. 5
0
/**
 * Process the next input event.
 */
int32_t handle_input(struct android_app* app, AInputEvent* event) {
  SFG_Window* window = fgStructure.CurrentWindow;

  /* FIXME: in Android, when key is repeated, down and up events
     happen most often at the exact same time.  This makes it
     impossible to animate based on key press time. */
  /* e.g. down/up/wait/down/up rather than down/wait/down/wait/up */
  
  if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY) {
    /* LOGI("action: %d", AKeyEvent_getAction(event)); */
    /* LOGI("keycode: %d", code); */
    int32_t code = AKeyEvent_getKeyCode(event);

    if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN) {
      int32_t keypress = 0;
      unsigned char ascii = 0;
      if ((keypress = key_a2fg[code]) && FETCH_WCB(*window, Special)) {
	INVOKE_WCB(*window, Special, (keypress, window->State.MouseX, window->State.MouseY));
	return EVENT_HANDLED;
      } else if ((ascii = key_ascii(app, event)) && FETCH_WCB(*window, Keyboard)) {
	INVOKE_WCB(*window, Keyboard, (ascii, window->State.MouseX, window->State.MouseY));
	return EVENT_HANDLED;
      }
    }
    else if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_UP) {
      int32_t keypress = 0;
      unsigned char ascii = 0;
      if ((keypress = key_a2fg[code]) && FETCH_WCB(*window, Special)) {
	INVOKE_WCB(*window, SpecialUp, (keypress, window->State.MouseX, window->State.MouseY));
	return EVENT_HANDLED;
      } else if ((ascii = key_ascii(app, event)) && FETCH_WCB(*window, Keyboard)) {
	INVOKE_WCB(*window, KeyboardUp, (ascii, window->State.MouseX, window->State.MouseY));
	return EVENT_HANDLED;
      }
    }
  }

  if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) {
    int32_t action = AMotionEvent_getAction(event);
    float x = AMotionEvent_getX(event, 0);
    float y = AMotionEvent_getY(event, 0);
    LOGI("motion %.01f,%.01f action=%d", x, y, AMotionEvent_getAction(event));
    
    /* Virtual arrows PAD */
    // Don't interfere with existing mouse move event
    if (!touchscreen.in_mmotion) {
      struct vpad_state prev_vpad = touchscreen.vpad;
      touchscreen.vpad.left = touchscreen.vpad.right
	= touchscreen.vpad.up = touchscreen.vpad.down = false;

      int32_t width = ANativeWindow_getWidth(window->Window.Handle);
      int32_t height = ANativeWindow_getHeight(window->Window.Handle);
      if (action == AMOTION_EVENT_ACTION_DOWN || action == AMOTION_EVENT_ACTION_MOVE) {
	if ((x > 0 && x < 100) && (y > (height - 100) && y < height))
	  touchscreen.vpad.left = true;
	if ((x > 200 && x < 300) && (y > (height - 100) && y < height))
	  touchscreen.vpad.right = true;
	if ((x > 100 && x < 200) && (y > (height - 100) && y < height))
	  touchscreen.vpad.down = true;
	if ((x > 100 && x < 200) && (y > (height - 200) && y < (height - 100)))
	  touchscreen.vpad.up = true;
      }
      if (action == AMOTION_EVENT_ACTION_DOWN && 
	  (touchscreen.vpad.left || touchscreen.vpad.right || touchscreen.vpad.down || touchscreen.vpad.up))
	touchscreen.vpad.on = true;
      if (action == AMOTION_EVENT_ACTION_UP)
	touchscreen.vpad.on = false;
      if (prev_vpad.left != touchscreen.vpad.left
	  || prev_vpad.right != touchscreen.vpad.right
	  || prev_vpad.up != touchscreen.vpad.up
	  || prev_vpad.down != touchscreen.vpad.down
	  || prev_vpad.on != touchscreen.vpad.on) {
	if (FETCH_WCB(*window, Special)) {
	  if (prev_vpad.left == false && touchscreen.vpad.left == true)
	    INVOKE_WCB(*window, Special, (GLUT_KEY_LEFT, x, y));
	  else if (prev_vpad.right == false && touchscreen.vpad.right == true)
	    INVOKE_WCB(*window, Special, (GLUT_KEY_RIGHT, x, y));
	  else if (prev_vpad.up == false && touchscreen.vpad.up == true)
	    INVOKE_WCB(*window, Special, (GLUT_KEY_UP, x, y));
	  else if (prev_vpad.down == false && touchscreen.vpad.down == true)
	    INVOKE_WCB(*window, Special, (GLUT_KEY_DOWN, x, y));
	}
	if (FETCH_WCB(*window, SpecialUp)) {
	  if (prev_vpad.left == true && touchscreen.vpad.left == false)
	    INVOKE_WCB(*window, SpecialUp, (GLUT_KEY_LEFT, x, y));
	  if (prev_vpad.right == true && touchscreen.vpad.right == false)
	    INVOKE_WCB(*window, SpecialUp, (GLUT_KEY_RIGHT, x, y));
	  if (prev_vpad.up == true && touchscreen.vpad.up == false)
	    INVOKE_WCB(*window, SpecialUp, (GLUT_KEY_UP, x, y));
	  if (prev_vpad.down == true && touchscreen.vpad.down == false)
	    INVOKE_WCB(*window, SpecialUp, (GLUT_KEY_DOWN, x, y));
	}
	return EVENT_HANDLED;
      }
    }
    
    /* Normal mouse events */
    if (!touchscreen.vpad.on) {
      window->State.MouseX = x;
      window->State.MouseY = y;
      LOGI("Changed mouse position: %d,%d", x, y);
      if (action == AMOTION_EVENT_ACTION_DOWN && FETCH_WCB(*window, Mouse)) {
	touchscreen.in_mmotion = true;
	INVOKE_WCB(*window, Mouse, (GLUT_LEFT_BUTTON, GLUT_DOWN, x, y));
      } else if (action == AMOTION_EVENT_ACTION_UP && FETCH_WCB(*window, Mouse)) {
	touchscreen.in_mmotion = false;
	INVOKE_WCB(*window, Mouse, (GLUT_LEFT_BUTTON, GLUT_UP, x, y));
      } else if (action == AMOTION_EVENT_ACTION_MOVE && FETCH_WCB(*window, Motion)) {
	INVOKE_WCB(*window, Motion, (x, y));
      }
    }
    
    return EVENT_HANDLED;
  }

  /* Let Android handle other events (e.g. Back and Menu buttons) */
  return EVENT_NOT_HANDLED;
}
Esempio n. 6
0
/*
 * Enters the freeglut processing loop.
 * Stays until the "ExecState" changes to "GLUT_EXEC_STATE_STOP".
 */
void FGAPIENTRY glutMainLoopMT( void )
{
    //int action; //MT

#if TARGET_HOST_WIN32 || TARGET_HOST_WINCE
    SFG_Window *window = (SFG_Window *)fgStructure.Windows.First ;
#endif

    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMainLoop" );

#if TARGET_HOST_WIN32 || TARGET_HOST_WINCE
    /*
     * Processing before the main loop:  If there is a window which is open and
     * which has a visibility callback, call it.  I know this is an ugly hack,
     * but I'm not sure what else to do about it.  Ideally we should leave
     * something uninitialized in the create window code and initialize it in
     * the main loop, and have that initialization create a "WM_ACTIVATE"
     * message.  Then we would put the visibility callback code in the
     * "case WM_ACTIVATE" block below.         - John Fay -- 10/24/02
     */
    while( window )
    {
        if ( FETCH_WCB( *window, Visibility ) )
        {
            SFG_Window *current_window = fgStructure.CurrentWindow ;

            INVOKE_WCB( *window, Visibility, ( window->State.Visible ) );
            fgSetWindow( current_window );
        }

        window = (SFG_Window *)window->Node.Next ;
    }
#endif

    fgState.ExecState = GLUT_EXEC_STATE_RUNNING ;
    while( fgState.ExecState == GLUT_EXEC_STATE_RUNNING )
    {
        SFG_Window *window;

        glutMainLoopEvent( );
        /*
         * Step through the list of windows, seeing if there are any
         * that are not menus
         */
        for( window = ( SFG_Window * )fgStructure.Windows.First;
             window;
             window = ( SFG_Window * )window->Node.Next )
            if ( ! ( window->IsMenu ) )
                break;

        if( ! window )
            fgState.ExecState = GLUT_EXEC_STATE_STOP;
        else
        {
            if( fgState.IdleCallback )
            {
                if( fgStructure.CurrentWindow &&
                    fgStructure.CurrentWindow->IsMenu )
                    /* fail safe */
                    fgSetWindow( window );
                fgState.IdleCallback( );
            }

            fghSleepForEvents( );
        }
    }

#if 0 //Marc Toussaint
    /*
     * When this loop terminates, destroy the display, state and structure
     * of a freeglut session, so that another glutInit() call can happen
     *
     * Save the "ActionOnWindowClose" because "fgDeinitialize" resets it.
     */
    action = fgState.ActionOnWindowClose;
    fgDeinitialize( );
    if( action == GLUT_ACTION_EXIT )
        exit( 0 );
#endif
}
void fgPlatformProcessSingleEvent ( void )
{
    if(fgStructure.CurrentWindow == NULL) {
        //XXX Is this right? Would this just cause a whole lot of busy looping while we wait for events?
        LOGW("fgPlatformProcessSingleEvent: Missing current window. Skipping event processing");
        return;
    }

    if(fgDisplay.pDisplay.event == NULL)
        /* Nothing to do */
        return;

    int domain;
    do
    {
        SFG_Window* window = fgStructure.CurrentWindow;
#ifdef __PLAYBOOK__
        /* Get the keyboard height before doing anything since we otherwise don't get it until it changes */
        if(window->State.pWState.keyboardHeight == 0) {
            virtualkeyboard_get_height(&window->State.pWState.keyboardHeight);
        }
#endif
        domain = bps_event_get_domain(fgDisplay.pDisplay.event);
        if (domain == screen_get_domain()) {
            int eventType;
            int mod;
            screen_event_t screenEvent = screen_event_get_event(fgDisplay.pDisplay.event);
            screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_TYPE, &eventType);
            switch (eventType) {

            //Mostly from fg_main_android
            case SCREEN_EVENT_MTOUCH_TOUCH:
            case SCREEN_EVENT_MTOUCH_RELEASE:
            case SCREEN_EVENT_MTOUCH_MOVE:
            {
                mtouch_event_t touchEvent;
                screen_get_mtouch_event(screenEvent, &touchEvent, 0);
#ifndef __PLAYBOOK__
                screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_KEY_MODIFIERS, &mod);
#else
                mod = 0;
#endif

                LOGI("fgPlatformProcessSingleEvent: SCREEN_EVENT_MTOUCH_*: Type: 0x%X, X: %d, Y: %d, Contact Id: %d, Mod: 0x%X", SLOG2_FA_SIGNED(eventType), SLOG2_FA_SIGNED(touchEvent.x), SLOG2_FA_SIGNED(touchEvent.y), SLOG2_FA_SIGNED(touchEvent.contact_id), SLOG2_FA_SIGNED(mod));

                /* Remember the current modifiers state so user can query it from their callback */
                fgState.Modifiers = fgPlatformGetModifiers(mod);

                if(touchEvent.contact_id == 0) {
                    int size[2];
                    screen_get_window_property_iv(window->Window.Handle, SCREEN_PROPERTY_BUFFER_SIZE, size);
                    handle_left_mouse(touchEvent.x, touchEvent.y, size[1], eventType, window);
                }

                //Now handle mutlitouch (adapted from fg_main_windows)
                if (eventType == SCREEN_EVENT_MTOUCH_TOUCH) {
                    INVOKE_WCB( *window, MultiEntry,  ( touchEvent.contact_id, GLUT_ENTERED ) );
                    INVOKE_WCB( *window, MultiButton, ( touchEvent.contact_id, touchEvent.x, touchEvent.y, 0, GLUT_DOWN ) );
                } else if (eventType == SCREEN_EVENT_MTOUCH_MOVE) {
                    INVOKE_WCB( *window, MultiMotion, ( touchEvent.contact_id, touchEvent.x, touchEvent.y ) );
                    //XXX No motion is performed without contact, thus MultiPassive is never used
                } else if (eventType == SCREEN_EVENT_MTOUCH_RELEASE) {
                    INVOKE_WCB( *window, MultiButton, ( touchEvent.contact_id, touchEvent.x, touchEvent.y, 0, GLUT_UP ) );
                    INVOKE_WCB( *window, MultiEntry,  ( touchEvent.contact_id, GLUT_LEFT ) );
                }

                fgState.Modifiers = INVALID_MODIFIERS;
                break;
            }

            case SCREEN_EVENT_POINTER:
            {
                //Based off/part taken from GamePlay3d PlatformBlackBerry
                static int mouse_pressed = 0;
                int buttons;
                int position[2];
                int wheel;
                // A move event will be fired unless a button state changed.
                bool move = true;
                bool left_move = false;
                // This is a mouse move event, it is applicable to a device with a usb mouse or simulator.
                screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_BUTTONS, &buttons);
                screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_SOURCE_POSITION, position);
#ifndef __PLAYBOOK__
                screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_MOUSE_WHEEL, &wheel);
                screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_KEY_MODIFIERS, &mod);
#else
                wheel = mod = 0;
#endif
                int size[2];
                screen_get_window_property_iv(window->Window.Handle, SCREEN_PROPERTY_BUFFER_SIZE, size);

                LOGI("fgPlatformProcessSingleEvent: SCREEN_EVENT_POINTER: Buttons: 0x%X, X: %d, Y: %d, Wheel: %d, Mod: 0x%X", SLOG2_FA_SIGNED(buttons), SLOG2_FA_SIGNED(position[0]), SLOG2_FA_SIGNED(position[1]), SLOG2_FA_SIGNED(wheel), SLOG2_FA_SIGNED(mod));

                //XXX Is multitouch be handled in a good way?

                /* Remember the current modifiers state so user can query it from their callback */
                fgState.Modifiers = fgPlatformGetModifiers(mod);

                // Handle left mouse. Interpret as touch if the left mouse event is not consumed.
                if (buttons & SCREEN_LEFT_MOUSE_BUTTON) {
                    if (mouse_pressed & SCREEN_LEFT_MOUSE_BUTTON) {
                        left_move = true;
                    } else {
                        move = false;
                        mouse_pressed |= SCREEN_LEFT_MOUSE_BUTTON;
                        handle_left_mouse(position[0], position[1], size[1], SCREEN_EVENT_MTOUCH_TOUCH, window);
                    }
                } else if (mouse_pressed & SCREEN_LEFT_MOUSE_BUTTON) {
                    move = false;
                    mouse_pressed &= ~SCREEN_LEFT_MOUSE_BUTTON;
                    handle_left_mouse(position[0], position[1], size[1], SCREEN_EVENT_MTOUCH_RELEASE, window);
                }

                // Handle right mouse.
                if (buttons & SCREEN_RIGHT_MOUSE_BUTTON) {
                    if ((mouse_pressed & SCREEN_RIGHT_MOUSE_BUTTON) == 0) {
                        move = false;
                        mouse_pressed |= SCREEN_RIGHT_MOUSE_BUTTON;
                        INVOKE_WCB(*window, Mouse, (GLUT_RIGHT_BUTTON, GLUT_DOWN, position[0], position[1]));
                    }
                } else if (mouse_pressed & SCREEN_RIGHT_MOUSE_BUTTON) {
                    move = false;
                    mouse_pressed &= ~SCREEN_RIGHT_MOUSE_BUTTON;
                    INVOKE_WCB(*window, Mouse, (GLUT_RIGHT_BUTTON, GLUT_UP, position[0], position[1]));
                }

                // Handle middle mouse.
                if (buttons & SCREEN_MIDDLE_MOUSE_BUTTON) {
                    if ((mouse_pressed & SCREEN_MIDDLE_MOUSE_BUTTON) == 0) {
                        move = false;
                        mouse_pressed |= SCREEN_MIDDLE_MOUSE_BUTTON;
                        INVOKE_WCB(*window, Mouse, (GLUT_MIDDLE_BUTTON, GLUT_DOWN, position[0], position[1]));
                    }
                } else if (mouse_pressed & SCREEN_MIDDLE_MOUSE_BUTTON) {
                    move = false;
                    mouse_pressed &= ~SCREEN_MIDDLE_MOUSE_BUTTON;
                    INVOKE_WCB(*window, Mouse, (GLUT_MIDDLE_BUTTON, GLUT_UP, position[0], position[1]));
                }

                // Fire a move event if none of the buttons changed.
                if (left_move || move) {
                    handle_left_mouse(position[0], position[1], size[1], SCREEN_EVENT_MTOUCH_MOVE, window);
                }

                if (wheel) {
                    /* Very slightly modified from fg_main_mswin.
                     * Because we don't want MouseWheel to be called every. single. time.
                     * That the action occurs, we mimic the Windows version with "wheel deltas"
                     * XXX Do we even want this?
                     * XXX If we want this, it's possible to get horizontal scroll as well.
                     * XXX -Vertical scroll=wheel 0, horizontal=wheel 1? */
                    fgState.MouseWheelTicks -= wheel;
                    if (abs(fgState.MouseWheelTicks) >= WHEEL_DELTA)
                    {
                        int wheel_number = 0;
                        int direction = (fgState.MouseWheelTicks > 0) ? -1 : 1;

                        if (!FETCH_WCB(*window, MouseWheel) && !FETCH_WCB(*window, Mouse))
                            break;

                        //XXX fgSetWindow(window);

                        while(abs(fgState.MouseWheelTicks) >= WHEEL_DELTA)
                        {
                            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));
                            }

                            fgState.MouseWheelTicks -= WHEEL_DELTA * direction;
                        }
                    }
                }

                fgState.Modifiers = INVALID_MODIFIERS;
                break;
            }

            //Based off fg_main_android
            case SCREEN_EVENT_KEYBOARD:
            {
                int flags;
                int value;
                screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_KEY_FLAGS, &flags);
                screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_KEY_SYM, &value);
                screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_KEY_MODIFIERS, &mod);

                LOGI("fgPlatformProcessSingleEvent: SCREEN_EVENT_KEYBOARD. Flags: 0x%X, Sym: 0x%X, Mod: 0x%X", SLOG2_FA_SIGNED(flags), SLOG2_FA_SIGNED(value), SLOG2_FA_SIGNED(mod));

                /* Suppress key repeats if desired. Based off fg_main_mswin */
                if ((flags & KEY_REPEAT) == 0 || (fgState.KeyRepeat == GLUT_KEY_REPEAT_OFF && fgStructure.CurrentWindow->State.IgnoreKeyRepeat == GL_TRUE)) {
                    unsigned int keypress = 0;
                    unsigned char ascii = 0;

                    /* Remember the current modifiers state so user can query it from their callback */
                    fgState.Modifiers = fgPlatformGetModifiers(mod);

                    /* Process keys */
                    if ((keypress = key_special(value))) {
                        if(flags & KEY_DOWN) {
                            INVOKE_WCB(*window, Special, (keypress, window->State.MouseX, window->State.MouseY));
                        } else {
                            INVOKE_WCB(*window, SpecialUp, (keypress, window->State.MouseX, window->State.MouseY));
                        }
                    } else if((flags & KEY_SYM_VALID) && (ascii = key_ascii(value))) {
                        if(flags & KEY_DOWN) {
                            INVOKE_WCB(*window, Keyboard, (ascii, window->State.MouseX, window->State.MouseY));
                        } else {
                            INVOKE_WCB(*window, KeyboardUp, (ascii, window->State.MouseX, window->State.MouseY));
                        }
                    } else {
                        LOGW("fgPlatformProcessSingleEvent: SCREEN_EVENT_KEYBOARD. Unhandled key event");
                    }

                    fgState.Modifiers = INVALID_MODIFIERS;
                }
                break;
            }

            case SCREEN_EVENT_PROPERTY:
            case SCREEN_EVENT_IDLE:
                break;

            default:
                LOGW("fgPlatformProcessSingleEvent: unknown screen event: 0x%X", SLOG2_FA_SIGNED(eventType));
                break;
            }
        } else if (domain == navigator_get_domain()) {
            unsigned int eventType = bps_event_get_code(fgDisplay.pDisplay.event);
            switch (eventType) {

            case NAVIGATOR_WINDOW_STATE:
            {
                LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE");

                /* Covered only happens due to keyboard. When the app is minimized, the keyboard is closed.
                   When the keyboard is open, and the app is fullscreened, the keyboard is also closed.
                   If a window is covered and the app is minimized, the state will be set and the keyboard event
                   will adjust the screen size and change window status. */
                navigator_window_state_t state = navigator_event_get_window_state(fgDisplay.pDisplay.event);
                if(window->State.pWState.windowCovered == GL_FALSE)
                {
                    switch (state)
                    {
                    case NAVIGATOR_WINDOW_FULLSCREEN:
                        LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE-NAVIGATOR_WINDOW_FULLSCREEN");
                        window->State.Visible = GL_TRUE;
                        INVOKE_WCB(*window, WindowStatus, (GLUT_FULLY_RETAINED));
                        break;
                    case NAVIGATOR_WINDOW_THUMBNAIL:
                        LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE-NAVIGATOR_WINDOW_THUMBNAIL");
                        window->State.Visible = GL_TRUE;
                        INVOKE_WCB(*window, WindowStatus, (GLUT_PARTIALLY_RETAINED));
                        break;
                    case NAVIGATOR_WINDOW_INVISIBLE:
                        LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE-NAVIGATOR_WINDOW_INVISIBLE");
                        window->State.Visible = GL_FALSE;
                        INVOKE_WCB(*window, WindowStatus, (GLUT_HIDDEN));
                        break;
                    default:
                        LOGW("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE unknown: 0x%X", SLOG2_FA_SIGNED(state));
                        break;
                    }
                }
                window->State.pWState.windowState = state;
                break;
            }

            case NAVIGATOR_EXIT:
            {
                LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_EXIT");

                fgPlatformMainLoopPostWork();

                /* User closed the application for good, let's kill the window */
                SFG_Window* window = fgStructure.CurrentWindow;
                if (window != NULL) {
                    fgDestroyWindow(window);
                } else {
                    LOGW("NAVIGATOR_EXIT: No current window");
                }

                //XXX Should this be a bit more "forceful" so that it doesn't continue to loop through events?
                break;
            }

            case NAVIGATOR_SWIPE_DOWN:
                /* XXX Open app menu */
                break;

            /* Orientation is a bunch of handshakes.
               - First the app get's asked if it wants to rotate (NAVIGATOR_ORIENTATION_CHECK)
               - If the app wants to rotate, then it will be told what size it will be after rotate (NAVIGATOR_ORIENTATION_SIZE).
               - Once the OS confirms that it's ready to rotate, it tells the app to handle rotation (NAVIGATOR_ORIENTATION).
               - Once rotation is complete, the OS tells the app it's done (NAVIGATOR_ORIENTATION_DONE) */
            case NAVIGATOR_ORIENTATION_CHECK:
                LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_ORIENTATION_CHECK");

                /* Reset sizes */
                window->State.pWState.newWidth = 0;
                window->State.pWState.newHeight = 0;

#ifdef __PLAYBOOK__
                /* On rotation, the keyboard is closed. This prevents two resize calls */
                window->State.pWState.keyboardOpen = GL_FALSE;
#endif

                /* Notify that we want to rotate */
                navigator_orientation_check_response(fgDisplay.pDisplay.event, true);
                break;

            case NAVIGATOR_ORIENTATION:
                LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_ORIENTATION");

                /* NAVIGATOR_ORIENTATION occurs before NAVIGATOR_KEYBOARD_POSITION */

                /* Rotate and resize the window */
                fgPlatformRotateWindow(window, navigator_event_get_orientation_angle(fgDisplay.pDisplay.event));
                fgPlatformFlushCommands();
#ifdef __PLAYBOOK__
                /* PlayBook doesn't indicate what the new size will be, so we need to retrieve it from the window itself */
                window->State.pWState.newWidth = glutGet(GLUT_WINDOW_WIDTH);
                window->State.pWState.newHeight = glutGet(GLUT_WINDOW_HEIGHT);
#endif
                fghOnReshapeNotify(window, window->State.pWState.newWidth, window->State.pWState.newHeight, GL_FALSE);

                /* Reset sizes */
                window->State.pWState.newWidth = 0;
                window->State.pWState.newHeight = 0;

                /* Done rotating */
                navigator_done_orientation(fgDisplay.pDisplay.event);
                break;

            case NAVIGATOR_BACK:
                LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_BACK");
                INVOKE_WCB(*window, Keyboard, (ESCAPE_BUTTON_KEY, window->State.MouseX, window->State.MouseY));
                INVOKE_WCB(*window, KeyboardUp, (ESCAPE_BUTTON_KEY, window->State.MouseX, window->State.MouseY));
                break;

            case NAVIGATOR_WINDOW_ACTIVE:
                LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_ACTIVE");
                INVOKE_WCB(*window, AppStatus, (GLUT_APPSTATUS_RESUME));
                break;

            case NAVIGATOR_WINDOW_INACTIVE:
                LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_INACTIVE");
                INVOKE_WCB(*window, AppStatus, (GLUT_APPSTATUS_PAUSE));
                break;

            case NAVIGATOR_ORIENTATION_DONE:
            case NAVIGATOR_ORIENTATION_RESULT:
                LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_ORIENTATION_DONE/NAVIGATOR_ORIENTATION_RESULT");
                break;

#ifndef __PLAYBOOK__
            case NAVIGATOR_KEYBOARD_STATE:
            {
                LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_KEYBOARD_STATE");

                navigator_keyboard_state_t state = navigator_event_get_keyboard_state(fgDisplay.pDisplay.event);
                switch (state)
                {
                case NAVIGATOR_KEYBOARD_CLOSED:
                    LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_KEYBOARD_STATE-NAVIGATOR_KEYBOARD_CLOSED");
                    /* NAVIGATOR_KEYBOARD_POSITION only occurs on open, so on keyboard close we need to reset the keyboard height */
                    fgPlatformHandleKeyboardHeight(window, 0);
                    break;
                case NAVIGATOR_KEYBOARD_OPENING:
                case NAVIGATOR_KEYBOARD_OPENED:
                case NAVIGATOR_KEYBOARD_CLOSING:
                    break;
                case NAVIGATOR_KEYBOARD_UNRECOGNIZED:
                    LOGW("fgPlatformProcessSingleEvent: NAVIGATOR_KEYBOARD_STATE-NAVIGATOR_KEYBOARD_UNRECOGNIZED");
                    break;
                default:
                    LOGW("fgPlatformProcessSingleEvent: NAVIGATOR_KEYBOARD_STATE unknown: 0x%X", SLOG2_FA_SIGNED(state));
                    break;
                }
                break;
            }

            case NAVIGATOR_KEYBOARD_POSITION:
            {
                /* Occurs only when keyboard has opened or resizes */
                LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_KEYBOARD_POSITION");

                int keyboardOffset = navigator_event_get_keyboard_position(fgDisplay.pDisplay.event);
                if(keyboardOffset == BPS_FAILURE) {
                    LOGW("fgPlatformProcessSingleEvent: NAVIGATOR_KEYBOARD_POSITION: getting keyboard offset failed");
                } else {
                    /* keyboardOffset is the offset from the top of the screen to the top of the keyboard, AKA the size of the uncovered screen
                       We want the height of the keyboard. So instead of determining the orientation, getting the right display size, and subtracting;
                       we just get the keyboard height which may be slower but easier to understand and work with */
                    virtualkeyboard_get_height(&keyboardOffset);
                    fgPlatformHandleKeyboardHeight(window, keyboardOffset);
                }
                break;
            }

            case NAVIGATOR_DEVICE_LOCK_STATE:
                break;

            case NAVIGATOR_WINDOW_COVER:
            case NAVIGATOR_WINDOW_COVER_ENTER:
            case NAVIGATOR_WINDOW_COVER_EXIT:
                /* BlackBerry specific. Let app status and window status take care of everything */
                break;

            case NAVIGATOR_APP_STATE:
                /* Can do the same as NAVIGATOR_WINDOW_ACTIVE/NAVIGATOR_WINDOW_INACTIVE but
                   seems like it doesn't work when the app comes to the foreground. Might be a bug */
                break;

            case NAVIGATOR_ORIENTATION_SIZE:
                LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_ORIENTATION_SIZE");

                /* Get new window size */
                window->State.pWState.newWidth = navigator_event_get_orientation_size_width(fgDisplay.pDisplay.event);
                window->State.pWState.newHeight = navigator_event_get_orientation_size_height(fgDisplay.pDisplay.event);
                break;
#endif

            case 0: //Doesn't exist in header, but shows up when keyboard shows and resizes
                break;

            default:
                LOGW("fgPlatformProcessSingleEvent: unknown navigator event: 0x%X", SLOG2_FA_SIGNED(eventType));
                break;
            }
        }
#ifdef __PLAYBOOK__
        /* While this could be used for non-PlayBook, BlackBerry 10 will still get navigator events, so use those. They are a bit more exact. */
        else if(domain == virtualkeyboard_get_domain()) {
            unsigned int eventType = bps_event_get_code(fgDisplay.pDisplay.event);
            switch (eventType) {
            case VIRTUALKEYBOARD_EVENT_VISIBLE:
                LOGI("fgPlatformProcessSingleEvent: VIRTUALKEYBOARD_EVENT_VISIBLE");
                if(window->State.pWState.keyboardOpen != GL_TRUE) {
                    window->State.pWState.keyboardOpen = GL_TRUE;
                    fgPlatformHandleKeyboardHeight(window, window->State.pWState.keyboardHeight);
                }
                break;

            case VIRTUALKEYBOARD_EVENT_HIDDEN:
                LOGI("fgPlatformProcessSingleEvent: VIRTUALKEYBOARD_EVENT_HIDDEN");
                if(window->State.pWState.keyboardOpen != GL_FALSE) {
                    window->State.pWState.keyboardOpen = GL_FALSE;
                    fgPlatformHandleKeyboardHeight(window, 0);
                }
                break;

            case VIRTUALKEYBOARD_EVENT_INFO:
                LOGI("fgPlatformProcessSingleEvent: VIRTUALKEYBOARD_EVENT_INFO");
                window->State.pWState.keyboardHeight = virtualkeyboard_event_get_height(fgDisplay.pDisplay.event);
                if(window->State.pWState.keyboardOpen == GL_TRUE) {
                    fgPlatformHandleKeyboardHeight(window, window->State.pWState.keyboardHeight);
                }
                break;

            default:
                LOGW("fgPlatformProcessSingleEvent: unknown virtualkeyboard event: 0x%X", eventType);
                break;
            }
        }
#endif
    } while(bps_get_event(&fgDisplay.pDisplay.event, 1) == BPS_SUCCESS && fgDisplay.pDisplay.event != NULL);

    /* Reset event to reduce chances of triggering something */
    fgDisplay.pDisplay.event = NULL;
}
void handle_left_mouse(int x, int y, int height, int eventType, SFG_Window* window)
{
    bool handled = false;
    /* Virtual arrows PAD */
    /* Don't interfere with existing mouse move event */
    if (!touchscreen.in_mmotion) {
        struct vpad_state prev_vpad = touchscreen.vpad;
        touchscreen.vpad.left = touchscreen.vpad.right = touchscreen.vpad.up = touchscreen.vpad.down = false;

        if (eventType == SCREEN_EVENT_MTOUCH_TOUCH || eventType == SCREEN_EVENT_MTOUCH_MOVE) {
            if ((x > 0 && x < 100) && (y > (height - 100) && y < height))
            {
                touchscreen.vpad.left = true;
            }
            if ((x > 200 && x < 300) && (y > (height - 100) && y < height))
            {
                touchscreen.vpad.right = true;
            }
            if ((x > 100 && x < 200) && (y > (height - 100) && y < height))
            {
                touchscreen.vpad.down = true;
            }
            if ((x > 100 && x < 200) && (y > (height - 200) && y < (height - 100)))
            {
                touchscreen.vpad.up = true;
            }
        }

        if (eventType == SCREEN_EVENT_MTOUCH_TOUCH &&
                (touchscreen.vpad.left || touchscreen.vpad.right || touchscreen.vpad.down || touchscreen.vpad.up)) {
            touchscreen.vpad.on = true;
        }
        if (eventType == SCREEN_EVENT_MTOUCH_RELEASE) {
            touchscreen.vpad.on = false;
        }

        if (prev_vpad.left != touchscreen.vpad.left
                || prev_vpad.right != touchscreen.vpad.right
                || prev_vpad.up != touchscreen.vpad.up
                || prev_vpad.down != touchscreen.vpad.down
                || prev_vpad.on != touchscreen.vpad.on) {
            if (FETCH_WCB(*window, Special)) {
                if (prev_vpad.left == false && touchscreen.vpad.left == true) {
                    INVOKE_WCB(*window, Special, (GLUT_KEY_LEFT, x, y));
                }
                else if (prev_vpad.right == false && touchscreen.vpad.right == true) {
                    INVOKE_WCB(*window, Special, (GLUT_KEY_RIGHT, x, y));
                }
                else if (prev_vpad.up == false && touchscreen.vpad.up == true) {
                    INVOKE_WCB(*window, Special, (GLUT_KEY_UP, x, y));
                }
                else if (prev_vpad.down == false && touchscreen.vpad.down == true) {
                    INVOKE_WCB(*window, Special, (GLUT_KEY_DOWN, x, y));
                }
            }
            if (FETCH_WCB(*window, SpecialUp)) {
                if (prev_vpad.left == true && touchscreen.vpad.left == false) {
                    INVOKE_WCB(*window, SpecialUp, (GLUT_KEY_LEFT, x, y));
                }
                if (prev_vpad.right == true && touchscreen.vpad.right == false) {
                    INVOKE_WCB(*window, SpecialUp, (GLUT_KEY_RIGHT, x, y));
                }
                if (prev_vpad.up == true && touchscreen.vpad.up == false) {
                    INVOKE_WCB(*window, SpecialUp, (GLUT_KEY_UP, x, y));
                }
                if (prev_vpad.down == true && touchscreen.vpad.down == false) {
                    INVOKE_WCB(*window, SpecialUp, (GLUT_KEY_DOWN, x, y));
                }
            }
            handled = true;
        }
    }

    /* Normal mouse events */
    if (!handled && !touchscreen.vpad.on) {
        window->State.MouseX = x;
        window->State.MouseY = y;

        if(eventType == SCREEN_EVENT_MTOUCH_MOVE) {
            INVOKE_WCB(*window, Motion, (x, y));
        } else if(FETCH_WCB(*window, Mouse)) {
            touchscreen.in_mmotion = eventType == SCREEN_EVENT_MTOUCH_TOUCH;
            int glutTouchType = eventType == SCREEN_EVENT_MTOUCH_TOUCH ? GLUT_DOWN : GLUT_UP;
            INVOKE_WCB(*window, Mouse, (GLUT_LEFT_BUTTON, glutTouchType, x, y));
        }
    }
}
Esempio n. 9
0
/*
 * This function will interpret a keyboard keysym, and call the
 * possible callbacks accordingly.
 */
void fghKeyboardInterpretKeysym(  SFG_Window* window,
                                  uint32_t key,
                                  xkb_keysym_t sym,
                                  uint32_t state )
{
    FGCBKeyboard keyboard_cb;
    FGCBSpecial special_cb;
    char string[16];
    int special = -1;

    /* GLUT API tells us to have two separate callbacks, one for
     * the ASCII translateable keypresses, and one for all the
     * others, which need to be translated to GLUT_KEY_Xs... */
    if( state )
    {
        keyboard_cb = (FGCBKeyboard)( FETCH_WCB( *window, Keyboard ));
        special_cb  = (FGCBSpecial) ( FETCH_WCB( *window, Special  ));
    }
    else
    {
        keyboard_cb = (FGCBKeyboard)( FETCH_WCB( *window, KeyboardUp ));
        special_cb  = (FGCBSpecial) ( FETCH_WCB( *window, SpecialUp  ));
    }

    switch( sym )
    {
    case XKB_KEY_F1:        special = GLUT_KEY_F1;        break;
    case XKB_KEY_F2:        special = GLUT_KEY_F2;        break;
    case XKB_KEY_F3:        special = GLUT_KEY_F3;        break;
    case XKB_KEY_F4:        special = GLUT_KEY_F4;        break;
    case XKB_KEY_F5:        special = GLUT_KEY_F5;        break;
    case XKB_KEY_F6:        special = GLUT_KEY_F6;        break;
    case XKB_KEY_F7:        special = GLUT_KEY_F7;        break;
    case XKB_KEY_F8:        special = GLUT_KEY_F8;        break;
    case XKB_KEY_F9:        special = GLUT_KEY_F9;        break;
    case XKB_KEY_F10:       special = GLUT_KEY_F10;       break;
    case XKB_KEY_F11:       special = GLUT_KEY_F11;       break;
    case XKB_KEY_F12:       special = GLUT_KEY_F12;       break;
    case XKB_KEY_Left:      special = GLUT_KEY_LEFT;      break;
    case XKB_KEY_Right:     special = GLUT_KEY_RIGHT;     break;
    case XKB_KEY_Up:        special = GLUT_KEY_UP;        break;
    case XKB_KEY_Down:      special = GLUT_KEY_DOWN;      break;
    case XKB_KEY_Page_Up:   special = GLUT_KEY_PAGE_UP;   break;
    case XKB_KEY_Page_Down: special = GLUT_KEY_PAGE_DOWN; break;
    case XKB_KEY_Home:      special = GLUT_KEY_HOME;      break;
    case XKB_KEY_End:       special = GLUT_KEY_END;       break;
    case XKB_KEY_Insert:    special = GLUT_KEY_INSERT;    break;
    case XKB_KEY_Num_Lock:  special = GLUT_KEY_NUM_LOCK;  break;
    case XKB_KEY_Begin:     special = GLUT_KEY_BEGIN;     break;
    case XKB_KEY_Delete:    special = GLUT_KEY_DELETE;    break;
    case XKB_KEY_Shift_L:   special = GLUT_KEY_SHIFT_L;   break;
    case XKB_KEY_Shift_R:   special = GLUT_KEY_SHIFT_R;   break;
    case XKB_KEY_Control_L: special = GLUT_KEY_CTRL_L;    break;
    case XKB_KEY_Control_R: special = GLUT_KEY_CTRL_R;    break;
    case XKB_KEY_Alt_L:     special = GLUT_KEY_ALT_L;     break;
    case XKB_KEY_Alt_R:     special = GLUT_KEY_ALT_R;     break;
    }

    if( special_cb && (special != -1) )
    {
        fgSetWindow( window );
        special_cb( special, window->State.MouseX, window->State.MouseY );
    }
    else if( keyboard_cb && (special == -1) )
    {
        fgSetWindow( window );
        xkb_keysym_to_utf8( sym, string, sizeof( string ) );
        keyboard_cb( string[0], window->State.MouseX, window->State.MouseY );
    }
}
Esempio n. 10
0
File: fg_main.c Progetto: d3x0r/SACK
/*
 * Calls a window's redraw method. This is used when
 * a redraw is forced by the incoming window messages.
 */
void fghRedrawWindow ( SFG_Window *window )
{
    SFG_Window *current_window = fgStructure.CurrentWindow;

    freeglut_return_if_fail( window );

    if( window->State.NeedToInitContext ) {
        INVOKE_WCB( *window, InitContext, ());
        window->State.NeedToInitContext = GL_FALSE;
    }

    freeglut_return_if_fail( FETCH_WCB ( *window, Display ) );

    window->State.Redisplay = GL_FALSE;

    freeglut_return_if_fail( window->State.Visible );

    fgSetWindow( window );

    if( window->State.NeedToResize )
    {
        /* Set need to resize to false before calling fghReshapeWindow, otherwise
           in the case the user's reshape callback calls glutReshapeWindow,
           his request would get canceled after fghReshapeWindow gets called.
         */
        window->State.NeedToResize = GL_FALSE;