wglEventHandler.cpp

00001 
00002 /* Copyright (c) 2007-2008, Stefan Eilemann <eile@equalizergraphics.com> 
00003  *
00004  * This library is free software; you can redistribute it and/or modify it under
00005  * the terms of the GNU Lesser General Public License version 2.1 as published
00006  * by the Free Software Foundation.
00007  *  
00008  * This library is distributed in the hope that it will be useful, but WITHOUT
00009  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00010  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
00011  * details.
00012  * 
00013  * You should have received a copy of the GNU Lesser General Public License
00014  * along with this library; if not, write to the Free Software Foundation, Inc.,
00015  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00016  */
00017 
00018 #include <eq/base/base.h>      // first get windows.h
00019 #include <pthread.h>           // then get pthreads
00020 #include <eq/base/perThread.h> // then get perThread to have template code
00021 
00022 #include "wglEventHandler.h"
00023 
00024 #include "log.h"
00025 #include "event.h"
00026 #include "window.h"
00027 #include "wglWindow.h"
00028 
00029 #include <eq/base/debug.h>
00030 #include <eq/base/executionListener.h>
00031 
00032 #include <algorithm>
00033 #include <windowsx.h>
00034 
00035 using namespace eq::base;
00036 using namespace std;
00037 using namespace stde;
00038 
00039 namespace eq
00040 {
00041 
00042 // Win32 defines to indentify special keys
00043 #define SCANCODE_MASK     0xff0000
00044 #define SCANCODE_SHIFT_L  0x2a0000
00045 #define SCANCODE_SHIFT_R  0x360000
00046 #define RIGHT_ALT_OR_CTRL 0x1000000
00047 
00048 #ifndef MK_XBUTTON1
00049 #  define MK_XBUTTON1  0x20
00050 #endif
00051 #ifndef MK_XBUTTON2
00052 #  define MK_XBUTTON2  0x40
00053 #endif
00054 #ifndef GET_XBUTTON_WPARAM
00055 #  define GET_XBUTTON_WPARAM(wParam) (HIWORD(wParam))
00056 #endif
00057 #ifndef GET_KEYSTATE_WPARAM
00058 #  define GET_KEYSTATE_WPARAM(wParam) (LOWORD(wParam))
00059 #endif
00060 
00061 
00062 namespace
00063 {
00064 class HandlerMap
00065 #ifdef WIN32_VC
00066     : public hash_map< HWND, WGLEventHandler* >
00067 #else // Cygwin does not want to instantiate a hash with key=HWND
00068     : public hash_map< void*, WGLEventHandler* >
00069 #endif
00070 {
00071 public:
00072     virtual ~HandlerMap() {}
00073 
00074     void notifyPerThreadDelete() 
00075         {
00076             if( !empty( ))
00077                 EQWARN << size() 
00078                        << " WGL event handlers registered during thread exit"
00079                        << endl;
00080             delete this;
00081         }
00082 };
00083 
00084 static PerThread< HandlerMap > _handlers;
00085 
00086 
00087 
00088 static void registerHandler( HWND hWnd, WGLEventHandler* handler )
00089 {
00090     if( _handlers == 0 )
00091         _handlers = new HandlerMap;
00092 
00093     HandlerMap* map = _handlers.get();
00094     EQASSERT( map->find( hWnd ) == map->end( ));
00095 
00096     (*map)[hWnd] = handler;
00097 }
00098 
00099 static void deregisterHandler( HWND hWnd )
00100 {
00101     HandlerMap* map = _handlers.get();
00102     EQASSERT( map )
00103     EQASSERT( map->find( hWnd ) != map->end( ));
00104 
00105     map->erase( hWnd );
00106 }
00107 
00108 static WGLEventHandler* getEventHandler( HWND hWnd )
00109 {
00110     HandlerMap* map = _handlers.get();
00111     if( !map || map->find( hWnd ) == map->end( ))
00112         return 0;
00113 
00114     return (*map)[hWnd];
00115 }
00116 }
00117 
00118 WGLEventHandler::WGLEventHandler( WGLWindowIF* window )
00119         : _window( window ),
00120           _buttonState( PTR_BUTTON_NONE )
00121 {
00122     _hWnd = window->getWGLWindowHandle();
00123 
00124     if( !_hWnd )
00125     {
00126         EQWARN << "Window has no window handle" << endl;
00127         return;
00128     }
00129 
00130     registerHandler( _hWnd, this );
00131     _prevWndProc = (WNDPROC)SetWindowLongPtr( _hWnd, GWLP_WNDPROC, 
00132                                               (LONG_PTR)wndProc );
00133     if( _prevWndProc == wndProc ) // avoid recursion
00134         _prevWndProc = DefWindowProc;
00135 }
00136 
00137 WGLEventHandler::~WGLEventHandler()
00138 {
00139     SetWindowLongPtr( _hWnd, GWLP_WNDPROC, (LONG_PTR)_prevWndProc );
00140     deregisterHandler( _hWnd );
00141 }
00142 
00143 LRESULT CALLBACK WGLEventHandler::wndProc( HWND hWnd, UINT uMsg, WPARAM wParam, 
00144                                            LPARAM lParam )
00145 {
00146     WGLEventHandler* handler = getEventHandler( hWnd );
00147     if( !handler )
00148     {
00149         EQERROR << "Message arrived for unregistered window" << endl;
00150         return DefWindowProc( hWnd, uMsg, wParam, lParam );
00151     }
00152 
00153     return handler->_wndProc( hWnd, uMsg, wParam, lParam );
00154 }
00155 
00156 void WGLEventHandler::_syncButtonState( WPARAM wParam )
00157 {
00158     uint32_t buttons = PTR_BUTTON_NONE;
00159     if( wParam & MK_LBUTTON )  buttons |= PTR_BUTTON1;
00160     if( wParam & MK_MBUTTON )  buttons |= PTR_BUTTON2;
00161     if( wParam & MK_RBUTTON )  buttons |= PTR_BUTTON3;
00162     if( wParam & MK_XBUTTON1 ) buttons |= PTR_BUTTON4;
00163     if( wParam & MK_XBUTTON2 ) buttons |= PTR_BUTTON5;
00164 
00165 #ifndef NDEBUG
00166     if( _buttonState != buttons )
00167 
00168         EQWARN << "WM_MOUSEMOVE reports button state " << buttons
00169                << ", but internal state is " << _buttonState << endl;
00170 #endif
00171 
00172     _buttonState = buttons;
00173 }
00174 
00175 namespace
00176 {
00177 void _getWindowSize( HWND hWnd, ResizeEvent& event )
00178 {
00179     RECT rect;
00180     GetClientRect( hWnd, &rect );
00181     event.w = rect.right - rect.left;
00182     event.h = rect.bottom - rect.top; 
00183 
00184     // Get window coordinates, the rect data is relative
00185     // to window parent, but we report pvp relative to screen.
00186     POINT point;
00187     point.x = rect.left;
00188     point.y = rect.top;
00189     ClientToScreen( hWnd, &point );
00190     event.x = point.x;
00191     event.y = point.y;
00192 }
00193 }
00194 LRESULT CALLBACK WGLEventHandler::_wndProc( HWND hWnd, UINT uMsg, WPARAM wParam,
00195                                             LPARAM lParam )
00196 {
00197     WGLWindowEvent event;
00198     event.uMsg   = uMsg;
00199     event.wParam = wParam;
00200     event.lParam = lParam;
00201 
00202     Window* const window = _window->getWindow();
00203 
00204     LONG result = 0;
00205     switch( uMsg )
00206     {
00207         case WM_SHOWWINDOW:
00208             if( wParam == TRUE )
00209                 event.type = Event::WINDOW_SHOW;
00210             else
00211                 event.type = Event::WINDOW_HIDE;
00212 
00213             _getWindowSize( hWnd, event.resize );
00214             break;
00215 
00216         case WM_CREATE:
00217         case WM_SIZE:
00218         case WM_MOVE:
00219         case WM_WINDOWPOSCHANGED:
00220         {
00221             _getWindowSize( hWnd, event.resize );
00222             const bool hasArea = (event.resize.w >0 && event.resize.h > 0);
00223             const PixelViewport& pvp = window->getPixelViewport();
00224 
00225             // No show/hide events on Win32?: Emulate.
00226             if( !hasArea && pvp.hasArea( ))
00227                 event.type = Event::WINDOW_HIDE;
00228             else if( hasArea && !pvp.hasArea( ))
00229                 event.type = Event::WINDOW_SHOW;
00230             else
00231                 event.type = Event::WINDOW_RESIZE;
00232             break;
00233         }
00234 
00235         case WM_CLOSE:
00236         case WM_DESTROY:
00237             event.type = Event::WINDOW_CLOSE;
00238             break;
00239 
00240         case WM_PAINT:
00241         {
00242             if( GetUpdateRect( hWnd, 0, false ) == 0 ) // No 'expose'
00243                 return DefWindowProc( hWnd, uMsg, wParam, lParam );
00244 
00245             event.type = Event::WINDOW_EXPOSE;
00246             break;
00247         }
00248 
00249         case WM_MOUSEMOVE:
00250         {
00251             _syncButtonState( wParam );
00252 
00253             event.type = Event::POINTER_MOTION;
00254             event.pointerMotion.x = GET_X_LPARAM( lParam );
00255             event.pointerMotion.y = GET_Y_LPARAM( lParam );
00256             event.pointerMotion.buttons = _buttonState;
00257 
00258             _computePointerDelta( window, event );
00259             _getRenderContext( window, event );
00260             break;
00261         }
00262 
00263         case WM_LBUTTONDOWN:
00264             _buttonState |= PTR_BUTTON1;
00265             event.type = Event::POINTER_BUTTON_PRESS;
00266             event.pointerButtonPress.x       = GET_X_LPARAM( lParam );
00267             event.pointerButtonPress.y       = GET_Y_LPARAM( lParam );
00268             event.pointerButtonPress.buttons = _buttonState;
00269             event.pointerButtonPress.button  = PTR_BUTTON1;
00270 
00271             _computePointerDelta( window, event );
00272             _getRenderContext( window, event );
00273             break;
00274 
00275         case WM_MBUTTONDOWN:
00276             _buttonState |= PTR_BUTTON2;
00277             event.type = Event::POINTER_BUTTON_PRESS;
00278             event.pointerButtonPress.x       = GET_X_LPARAM( lParam );
00279             event.pointerButtonPress.y       = GET_Y_LPARAM( lParam );
00280             event.pointerButtonPress.buttons = _buttonState;
00281             event.pointerButtonPress.button  = PTR_BUTTON2;
00282 
00283             _computePointerDelta( window, event );
00284             _getRenderContext( window, event );
00285             break;
00286 
00287         case WM_RBUTTONDOWN:
00288             _buttonState |= PTR_BUTTON3;
00289             event.type = Event::POINTER_BUTTON_PRESS;
00290             event.pointerButtonPress.x       = GET_X_LPARAM( lParam );
00291             event.pointerButtonPress.y       = GET_Y_LPARAM( lParam );
00292             event.pointerButtonPress.buttons = _buttonState;
00293             event.pointerButtonPress.button  = PTR_BUTTON3;
00294 
00295             _computePointerDelta( window, event );
00296             _getRenderContext( window, event );
00297             break;
00298 
00299         case WM_XBUTTONDOWN:
00300             event.type = Event::POINTER_BUTTON_PRESS;
00301             event.pointerButtonPress.x       = GET_X_LPARAM( lParam );
00302             event.pointerButtonPress.y       = GET_Y_LPARAM( lParam );
00303 
00304             if( GET_XBUTTON_WPARAM( wParam ) & XBUTTON1 )
00305                 event.pointerButtonRelease.button = PTR_BUTTON4;
00306             else
00307                 event.pointerButtonRelease.button = PTR_BUTTON5;
00308 
00309             _buttonState |= event.pointerButtonPress.button;
00310             _syncButtonState( GET_KEYSTATE_WPARAM( wParam ));
00311             event.pointerButtonPress.buttons = _buttonState;
00312 
00313             _computePointerDelta( window, event );
00314             _getRenderContext( window, event );
00315             result = TRUE;
00316             break;
00317 
00318         case WM_LBUTTONUP:
00319             _buttonState &= ~PTR_BUTTON1;
00320             event.type = Event::POINTER_BUTTON_RELEASE;
00321             event.pointerButtonRelease.x       = GET_X_LPARAM( lParam );
00322             event.pointerButtonRelease.y       = GET_Y_LPARAM( lParam );
00323             event.pointerButtonRelease.buttons = _buttonState;
00324             event.pointerButtonRelease.button  = PTR_BUTTON1;
00325 
00326             _computePointerDelta( window, event );
00327             _getRenderContext( window, event );
00328             break;
00329 
00330         case WM_MBUTTONUP:
00331             _buttonState &= ~PTR_BUTTON2;
00332             event.type = Event::POINTER_BUTTON_RELEASE;
00333             event.pointerButtonRelease.x       = GET_X_LPARAM( lParam );
00334             event.pointerButtonRelease.y       = GET_Y_LPARAM( lParam );
00335             event.pointerButtonRelease.buttons = _buttonState;
00336             event.pointerButtonRelease.button  = PTR_BUTTON2;
00337 
00338             _computePointerDelta( window, event );
00339             _getRenderContext( window, event );
00340             break;
00341 
00342         case WM_RBUTTONUP:
00343             _buttonState &= ~PTR_BUTTON3;
00344             event.type = Event::POINTER_BUTTON_RELEASE;
00345             event.pointerButtonRelease.x       = GET_X_LPARAM( lParam );
00346             event.pointerButtonRelease.y       = GET_Y_LPARAM( lParam );
00347             event.pointerButtonRelease.buttons = _buttonState;
00348             event.pointerButtonRelease.button  = PTR_BUTTON3;
00349 
00350             _computePointerDelta( window, event );
00351             _getRenderContext( window, event );
00352             break;
00353 
00354         case WM_XBUTTONUP:
00355             event.type = Event::POINTER_BUTTON_RELEASE;
00356             event.pointerButtonRelease.x       = GET_X_LPARAM( lParam );
00357             event.pointerButtonRelease.y       = GET_Y_LPARAM( lParam );
00358 
00359             if( GET_XBUTTON_WPARAM( wParam ) & XBUTTON1 )
00360                 event.pointerButtonRelease.button = PTR_BUTTON4;
00361             else
00362                 event.pointerButtonRelease.button = PTR_BUTTON5;
00363 
00364             _buttonState &= ~event.pointerButtonRelease.button;
00365             _syncButtonState( GET_KEYSTATE_WPARAM( wParam ));
00366             event.pointerButtonRelease.buttons =_buttonState;
00367 
00368             _computePointerDelta( window, event );
00369             _getRenderContext( window, event );
00370             result = TRUE;
00371             break;
00372 
00373         case WM_SYSKEYDOWN:
00374         case WM_KEYDOWN:
00375             event.type = Event::KEY_PRESS;
00376             event.keyPress.key = _getKey( lParam, wParam );
00377             break;
00378 
00379         case WM_SYSKEYUP:
00380         case WM_KEYUP:
00381             event.type = Event::KEY_RELEASE;
00382             event.keyRelease.key = _getKey( lParam, wParam );
00383             break;
00384 
00385         case WM_SYSCOMMAND:
00386             switch( wParam )
00387             {
00388                 case SC_MONITORPOWER:
00389                 case SC_SCREENSAVE:
00390                     if( lParam >= 0 ) // request off
00391                     {
00392                         event.type = Event::WINDOW_SCREENSAVER;
00393                         break;
00394                     }
00395                     // else no break; fall through
00396                 default:
00397                     event.type = Event::UNKNOWN;
00398                     EQVERB << "Unhandled system command 0x" << hex << wParam 
00399                            << dec << endl;
00400                     break;
00401             }
00402             break;
00403 
00404         default:
00405             event.type = Event::UNKNOWN;
00406             EQVERB << "Unhandled message 0x" << hex << uMsg << dec << endl;
00407             break;
00408     }
00409 
00410     event.originator = window->getID();
00411 
00412     EQLOG( LOG_EVENTS ) << "received event: " << event << endl;
00413 
00414     if( _window->processEvent( event ))
00415         return result;
00416 
00417     return CallWindowProc( _prevWndProc, hWnd, uMsg, wParam, lParam );
00418 }
00419 
00420 uint32_t WGLEventHandler::_getKey( LPARAM lParam, WPARAM wParam )
00421 {
00422     switch( wParam )
00423     {
00424         case VK_ESCAPE:    return KC_ESCAPE;    
00425         case VK_BACK:      return KC_BACKSPACE; 
00426         case VK_RETURN:    return KC_RETURN;    
00427         case VK_TAB:       return KC_TAB;       
00428         case VK_HOME:      return KC_HOME;       
00429         case VK_LEFT:      return KC_LEFT;       
00430         case VK_UP:        return KC_UP;         
00431         case VK_RIGHT:     return KC_RIGHT;      
00432         case VK_DOWN:      return KC_DOWN;       
00433         case VK_PRIOR:     return KC_PAGE_UP;    
00434         case VK_NEXT:      return KC_PAGE_DOWN;  
00435         case VK_END:       return KC_END;        
00436         case VK_F1:        return KC_F1;         
00437         case VK_F2:        return KC_F2;         
00438         case VK_F3:        return KC_F3;         
00439         case VK_F4:        return KC_F4;         
00440         case VK_F5:        return KC_F5;         
00441         case VK_F6:        return KC_F6;         
00442         case VK_F7:        return KC_F7;         
00443         case VK_F8:        return KC_F8;         
00444         case VK_F9:        return KC_F9;         
00445         case VK_F10:       return KC_F10;        
00446         case VK_F11:       return KC_F11;        
00447         case VK_F12:       return KC_F12;        
00448         case VK_F13:       return KC_F13;        
00449         case VK_F14:       return KC_F14;        
00450         case VK_F15:       return KC_F15;        
00451         case VK_F16:       return KC_F16;        
00452         case VK_F17:       return KC_F17;        
00453         case VK_F18:       return KC_F18;        
00454         case VK_F19:       return KC_F19;        
00455         case VK_F20:       return KC_F20;        
00456         case VK_F21:       return KC_F21;        
00457         case VK_F22:       return KC_F22;        
00458         case VK_F23:       return KC_F23;        
00459         case VK_F24:       return KC_F24;  
00460         case VK_SHIFT:
00461             switch( lParam & SCANCODE_MASK )
00462             {
00463                 case SCANCODE_SHIFT_L: return KC_SHIFT_L;
00464                 case SCANCODE_SHIFT_R: return KC_SHIFT_R;
00465             }
00466             break;
00467 
00468         case VK_CONTROL:
00469             if( lParam & RIGHT_ALT_OR_CTRL )
00470                 return KC_CONTROL_R;
00471             return KC_CONTROL_L;
00472 
00473         case VK_MENU:
00474             if( lParam & RIGHT_ALT_OR_CTRL )
00475                 return KC_ALT_R;
00476             return KC_ALT_L;
00477 
00478         default: 
00479             // 'Useful' Latin1 characters
00480             if( wParam >= ' ' && wParam <= '~' )
00481                 return wParam;
00482             break;
00483     }
00484     EQWARN << "Unrecognized virtual key code " << wParam << endl;
00485     return KC_VOID;
00486 }
00487 }
Generated on Mon Aug 10 18:58:41 2009 for Equalizer 0.9 by  doxygen 1.5.8