00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "aglEventHandler.h"
00019
00020 #include "aglWindow.h"
00021 #include "aglWindowEvent.h"
00022 #include "config.h"
00023 #include "configEvent.h"
00024 #include "global.h"
00025 #include "log.h"
00026 #include "pipe.h"
00027 #include "window.h"
00028
00029 #include <eq/net/global.h>
00030 #include <eq/base/fileSearch.h>
00031
00032 #ifdef EQ_USE_MAGELLAN
00033 # include <3DconnexionClient/ConnexionClientAPI.h>
00034 #endif
00035
00036 using namespace eq::base;
00037 using namespace std;
00038
00039 namespace eq
00040 {
00041 AGLEventHandler::AGLEventHandler( AGLWindowIF* window )
00042 : _window( window )
00043 , _eventHandler( 0 )
00044 , _eventDispatcher( 0 )
00045 , _lastDX( 0 )
00046 , _lastDY( 0 )
00047 {
00048 const WindowRef carbonWindow = window->getCarbonWindow();
00049 if( !carbonWindow )
00050 {
00051 EQWARN << "Can't add window without native Carbon window to AGL event "
00052 << "handler" << endl;
00053 return;
00054 }
00055
00056 Global::enterCarbon();
00057 EventHandlerUPP eventHandler = NewEventHandlerUPP(
00058 eq::AGLEventHandler::_handleEventUPP );
00059 EventTypeSpec eventType[] = {
00060 { kEventClassWindow, kEventWindowBoundsChanged },
00061 { kEventClassWindow, kEventWindowZoomed },
00062 { kEventClassWindow, kEventWindowUpdate },
00063 { kEventClassWindow, kEventWindowDrawContent },
00064 { kEventClassWindow, kEventWindowClosed },
00065 { kEventClassWindow, kEventWindowHidden },
00066 { kEventClassWindow, kEventWindowCollapsed },
00067 { kEventClassWindow, kEventWindowShown },
00068 { kEventClassWindow, kEventWindowExpanded },
00069 { kEventClassMouse, kEventMouseMoved },
00070 { kEventClassMouse, kEventMouseDragged },
00071 { kEventClassMouse, kEventMouseDown },
00072 { kEventClassMouse, kEventMouseUp },
00073 { kEventClassKeyboard, kEventRawKeyDown },
00074 { kEventClassKeyboard, kEventRawKeyUp },
00075 { kEventClassKeyboard, kEventRawKeyRepeat }
00076 };
00077
00078 InstallWindowEventHandler( carbonWindow, eventHandler,
00079 sizeof( eventType ) / sizeof( EventTypeSpec ),
00080 eventType, this, &_eventHandler );
00081
00082 const Pipe* pipe = window->getPipe();
00083 if( pipe->isThreaded( ))
00084 {
00085 EQASSERT( GetCurrentEventQueue() != GetMainEventQueue( ));
00086
00087
00088 EventHandlerUPP eventDispatcher = NewEventHandlerUPP(
00089 eq::AGLEventHandler::_dispatchEventUPP );
00090 EventQueueRef target = GetCurrentEventQueue();
00091
00092 InstallWindowEventHandler( carbonWindow, eventDispatcher,
00093 sizeof( eventType ) / sizeof( EventTypeSpec),
00094 eventType, target, &_eventDispatcher );
00095 }
00096 else
00097 _eventDispatcher = 0;
00098
00099 Global::leaveCarbon();
00100
00101 EQINFO << "Installed event handlers for carbon window " << carbonWindow
00102 << endl;
00103 }
00104
00105 AGLEventHandler::~AGLEventHandler()
00106 {
00107 Global::enterCarbon();
00108 if( _eventDispatcher )
00109 {
00110 RemoveEventHandler( _eventDispatcher );
00111 _eventDispatcher = 0;
00112 }
00113 if( _eventHandler )
00114 {
00115 RemoveEventHandler( _eventHandler );
00116 _eventHandler = 0;
00117 }
00118 Global::leaveCarbon();
00119 }
00120
00121 pascal OSStatus AGLEventHandler::_dispatchEventUPP(
00122 EventHandlerCallRef nextHandler, EventRef event, void* userData )
00123 {
00124 EventQueueRef target = static_cast< EventQueueRef >( userData );
00125
00126 if( GetCurrentEventQueue() != target )
00127 {
00128 #if 0 // some events pop up on pipe thread queues...
00129 EQASSERTINFO( GetCurrentEventQueue() == GetMainEventQueue(),
00130 "target " << target << " current " <<
00131 GetCurrentEventQueue() << " main " <<
00132 GetMainEventQueue( ));
00133 #endif
00134 PostEventToQueue( target, event, kEventPriorityStandard );
00135 }
00136 return CallNextEventHandler( nextHandler, event );
00137 }
00138
00139 pascal OSStatus AGLEventHandler::_handleEventUPP(
00140 EventHandlerCallRef nextHandler, EventRef event, void* userData )
00141 {
00142 AGLEventHandler* handler = static_cast< AGLEventHandler* >( userData );
00143 AGLWindowIF* window = handler->_window;
00144
00145 if( GetCurrentEventQueue() == GetMainEventQueue( ))
00146 {
00147 const Pipe* pipe = window->getPipe();
00148 if( !pipe->isThreaded( ))
00149
00150 handler->_handleEvent( event );
00151
00152 return CallNextEventHandler( nextHandler, event );
00153 }
00154
00155 handler->_handleEvent( event );
00156 return noErr;
00157 }
00158
00159 bool AGLEventHandler::_handleEvent( EventRef event )
00160 {
00161 switch( GetEventClass( event ))
00162 {
00163 case kEventClassWindow:
00164 return _handleWindowEvent( event );
00165 case kEventClassMouse:
00166 return _handleMouseEvent( event );
00167 case kEventClassKeyboard:
00168 return _handleKeyEvent( event );
00169 default:
00170 EQINFO << "Unknown event class " << GetEventClass( event ) << endl;
00171 return false;
00172 }
00173 }
00174
00175 bool AGLEventHandler::_handleWindowEvent( EventRef event )
00176 {
00177 AGLWindowEvent windowEvent;
00178 windowEvent.carbonEventRef = event;
00179 Window* const window = _window->getWindow();
00180
00181 Rect rect;
00182 WindowRef carbonWindow = _window->getCarbonWindow();
00183
00184 GetWindowBounds( carbonWindow, kWindowContentRgn, &rect );
00185 windowEvent.resize.x = rect.top;
00186 windowEvent.resize.y = rect.left;
00187 windowEvent.resize.h = rect.bottom - rect.top;
00188 windowEvent.resize.w = rect.right - rect.left;
00189
00190 if( window->getIAttribute( Window::IATTR_HINT_DECORATION ) != OFF )
00191 windowEvent.resize.y -= EQ_AGL_MENUBARHEIGHT;
00192
00193 switch( GetEventKind( event ))
00194 {
00195 case kEventWindowBoundsChanged:
00196 case kEventWindowZoomed:
00197 windowEvent.type = Event::WINDOW_RESIZE;
00198 break;
00199
00200 case kEventWindowUpdate:
00201 BeginUpdate( carbonWindow );
00202 EndUpdate( carbonWindow );
00203
00204 case kEventWindowDrawContent:
00205 windowEvent.type = Event::WINDOW_EXPOSE;
00206 break;
00207
00208 case kEventWindowClosed:
00209 windowEvent.type = Event::WINDOW_CLOSE;
00210 break;
00211
00212 case kEventWindowHidden:
00213 case kEventWindowCollapsed:
00214 windowEvent.type = Event::WINDOW_HIDE;
00215 break;
00216
00217 case kEventWindowShown:
00218 case kEventWindowExpanded:
00219 windowEvent.type = Event::WINDOW_SHOW;
00220 if( carbonWindow == FrontNonFloatingWindow( ))
00221 SetUserFocusWindow( carbonWindow );
00222 break;
00223
00224 default:
00225 EQINFO << "Unhandled window event " << GetEventKind( event ) <<endl;
00226 windowEvent.type = Event::UNKNOWN;
00227 break;
00228 }
00229 windowEvent.originator = window->getID();
00230
00231 EQLOG( LOG_EVENTS ) << "received event: " << windowEvent << endl;
00232 return _window->processEvent( windowEvent );
00233 }
00234
00235 bool AGLEventHandler::_handleMouseEvent( EventRef event )
00236 {
00237 HIPoint pos;
00238 AGLWindowEvent windowEvent;
00239
00240 windowEvent.carbonEventRef = event;
00241 Window* const window = _window->getWindow();
00242
00243 const bool decoration =
00244 window->getIAttribute( Window::IATTR_HINT_DECORATION ) != OFF;
00245 const int32_t menuHeight = decoration ? EQ_AGL_MENUBARHEIGHT : 0 ;
00246
00247 switch( GetEventKind( event ))
00248 {
00249 case kEventMouseMoved:
00250 case kEventMouseDragged:
00251 windowEvent.type = Event::POINTER_MOTION;
00252 windowEvent.pointerMotion.button = PTR_BUTTON_NONE;
00253
00254
00255 windowEvent.pointerMotion.buttons = _getButtonState();
00256
00257 if( windowEvent.pointerMotion.buttons == PTR_BUTTON1 )
00258 {
00259
00260 uint32_t keys = 0;
00261 GetEventParameter( event, kEventParamKeyModifiers,
00262 typeUInt32, 0, sizeof( keys ), 0, &keys );
00263 if( keys & controlKey )
00264 windowEvent.pointerMotion.buttons = PTR_BUTTON3;
00265 else if( keys & optionKey )
00266 windowEvent.pointerMotion.buttons = PTR_BUTTON2;
00267 }
00268
00269 GetEventParameter( event, kEventParamWindowMouseLocation,
00270 typeHIPoint, 0, sizeof( pos ), 0,
00271 &pos );
00272 if( pos.y < menuHeight )
00273 return false;
00274
00275 windowEvent.pointerMotion.x = static_cast< int32_t >( pos.x );
00276 windowEvent.pointerMotion.y = static_cast< int32_t >( pos.y ) -
00277 menuHeight;
00278
00279 GetEventParameter( event, kEventParamMouseDelta,
00280 typeHIPoint, 0, sizeof( pos ), 0,
00281 &pos );
00282 windowEvent.pointerMotion.dx = static_cast< int32_t >( pos.x );
00283 windowEvent.pointerMotion.dy = static_cast< int32_t >( pos.y );
00284
00285 _lastDX = windowEvent.pointerMotion.dx;
00286 _lastDY = windowEvent.pointerMotion.dy;
00287
00288 _getRenderContext( window, windowEvent );
00289 break;
00290
00291 case kEventMouseDown:
00292 windowEvent.type = Event::POINTER_BUTTON_PRESS;
00293 windowEvent.pointerMotion.buttons = _getButtonState();
00294 windowEvent.pointerButtonPress.button =
00295 _getButtonAction( event );
00296
00297 if( windowEvent.pointerMotion.buttons == PTR_BUTTON1 )
00298 {
00299
00300 uint32_t keys = 0;
00301 GetEventParameter( event, kEventParamKeyModifiers,
00302 typeUInt32, 0, sizeof( keys ), 0, &keys );
00303 if( keys & controlKey )
00304 windowEvent.pointerMotion.buttons = PTR_BUTTON3;
00305 else if( keys & optionKey )
00306 windowEvent.pointerMotion.buttons = PTR_BUTTON2;
00307 }
00308
00309 GetEventParameter( event, kEventParamWindowMouseLocation,
00310 typeHIPoint, 0, sizeof( pos ), 0,
00311 &pos );
00312 if( pos.y < menuHeight )
00313 return false;
00314
00315 windowEvent.pointerButtonPress.x =
00316 static_cast< int32_t >( pos.x );
00317 windowEvent.pointerButtonPress.y =
00318 static_cast< int32_t >( pos.y ) - menuHeight;
00319
00320 windowEvent.pointerButtonPress.dx = _lastDX;
00321 windowEvent.pointerButtonPress.dy = _lastDY;
00322 _lastDX = 0;
00323 _lastDY = 0;
00324
00325 _getRenderContext( window, windowEvent );
00326 break;
00327
00328 case kEventMouseUp:
00329 windowEvent.type = Event::POINTER_BUTTON_RELEASE;
00330 windowEvent.pointerMotion.buttons = _getButtonState();
00331 windowEvent.pointerButtonRelease.button =
00332 _getButtonAction( event );
00333
00334 if( windowEvent.pointerMotion.buttons == PTR_BUTTON1 )
00335 {
00336
00337 uint32_t keys = 0;
00338 GetEventParameter( event, kEventParamKeyModifiers,
00339 typeUInt32, 0, sizeof( keys ), 0, &keys );
00340 if( keys & controlKey )
00341 windowEvent.pointerMotion.buttons = PTR_BUTTON3;
00342 else if( keys & optionKey )
00343 windowEvent.pointerMotion.buttons = PTR_BUTTON2;
00344 }
00345
00346 GetEventParameter( event, kEventParamWindowMouseLocation,
00347 typeHIPoint, 0, sizeof( pos ), 0,
00348 &pos );
00349 if( pos.y < menuHeight )
00350 return false;
00351
00352 windowEvent.pointerButtonRelease.x =
00353 static_cast< int32_t>( pos.x );
00354 windowEvent.pointerButtonRelease.y =
00355 static_cast< int32_t>( pos.y ) - menuHeight;
00356
00357 windowEvent.pointerButtonRelease.dx = _lastDX;
00358 windowEvent.pointerButtonRelease.dy = _lastDY;
00359 _lastDX = 0;
00360 _lastDY = 0;
00361
00362 _getRenderContext( window, windowEvent );
00363 break;
00364
00365 default:
00366 EQINFO << "Unhandled mouse event " << GetEventKind( event ) << endl;
00367 windowEvent.type = Event::UNKNOWN;
00368 break;
00369 }
00370 windowEvent.originator = window->getID();
00371
00372 EQLOG( LOG_EVENTS ) << "received event: " << windowEvent << endl;
00373 return _window->processEvent( windowEvent );
00374 }
00375
00376 bool AGLEventHandler::_handleKeyEvent( EventRef event )
00377 {
00378 AGLWindowEvent windowEvent;
00379
00380 windowEvent.carbonEventRef = event;
00381 Window* const window = _window->getWindow();
00382
00383 switch( GetEventKind( event ))
00384 {
00385 case kEventRawKeyDown:
00386 case kEventRawKeyRepeat:
00387 windowEvent.type = Event::KEY_PRESS;
00388 windowEvent.keyPress.key = _getKey( event );
00389 break;
00390
00391 case kEventRawKeyUp:
00392 windowEvent.type = Event::KEY_RELEASE;
00393 windowEvent.keyPress.key = _getKey( event );
00394 break;
00395
00396 default:
00397 EQINFO << "Unhandled keyboard event " << GetEventKind( event )
00398 << endl;
00399 windowEvent.type = Event::UNKNOWN;
00400 break;
00401 }
00402 windowEvent.originator = window->getID();
00403
00404 EQLOG( LOG_EVENTS ) << "received event: " << windowEvent << endl;
00405 return _window->processEvent( windowEvent );
00406 }
00407
00408 uint32_t AGLEventHandler::_getButtonState()
00409 {
00410 const uint32 buttons = GetCurrentEventButtonState();
00411
00412
00413 return ( (buttons & 0xfffffff9u) +
00414 ((buttons & EQ_BIT3) >> 1) +
00415 ((buttons & EQ_BIT2) << 1) );
00416 }
00417
00418
00419 uint32_t AGLEventHandler::_getButtonAction( EventRef event )
00420 {
00421 EventMouseButton button;
00422 GetEventParameter( event, kEventParamMouseButton,
00423 typeMouseButton, 0, sizeof( button ), 0,
00424 &button );
00425
00426 switch( button )
00427 {
00428 case kEventMouseButtonPrimary: return PTR_BUTTON1;
00429 case kEventMouseButtonSecondary: return PTR_BUTTON3;
00430 case kEventMouseButtonTertiary: return PTR_BUTTON2;
00431 default: return PTR_BUTTON_NONE;
00432 }
00433 }
00434
00435 uint32_t AGLEventHandler::_getKey( EventRef event )
00436 {
00437 unsigned char key;
00438 GetEventParameter( event, kEventParamKeyMacCharCodes, typeChar, 0,
00439 sizeof( char ), 0, &key );
00440 switch( key )
00441 {
00442 case kEscapeCharCode: return KC_ESCAPE;
00443 case kBackspaceCharCode: return KC_BACKSPACE;
00444 case kReturnCharCode: return KC_RETURN;
00445 case kTabCharCode: return KC_TAB;
00446 case kHomeCharCode: return KC_HOME;
00447 case kLeftArrowCharCode: return KC_LEFT;
00448 case kUpArrowCharCode: return KC_UP;
00449 case kRightArrowCharCode: return KC_RIGHT;
00450 case kDownArrowCharCode: return KC_DOWN;
00451 case kPageUpCharCode: return KC_PAGE_UP;
00452 case kPageDownCharCode: return KC_PAGE_DOWN;
00453 case kEndCharCode: return KC_END;
00454 case kFunctionKeyCharCode:
00455 {
00456 uint32_t keyCode;
00457 GetEventParameter( event, kEventParamKeyCode, typeUInt32, 0,
00458 sizeof( keyCode ), 0, &keyCode );
00459
00460 switch( keyCode )
00461 {
00462 case kVK_F1: return KC_F1;
00463 case kVK_F2: return KC_F2;
00464 case kVK_F3: return KC_F3;
00465 case kVK_F4: return KC_F4;
00466 case kVK_F5: return KC_F5;
00467 case kVK_F6: return KC_F6;
00468 case kVK_F7: return KC_F7;
00469 case kVK_F8: return KC_F8;
00470 case kVK_F9: return KC_F9;
00471 case kVK_F10: return KC_F10;
00472 case kVK_F11: return KC_F11;
00473 case kVK_F12: return KC_F12;
00474 case kVK_F13: return KC_F13;
00475 case kVK_F14: return KC_F14;
00476 case kVK_F15: return KC_F15;
00477 case kVK_F16: return KC_F16;
00478 case kVK_F17: return KC_F17;
00479 case kVK_F18: return KC_F18;
00480 case kVK_F19: return KC_F19;
00481 case kVK_F20: return KC_F20;
00482 #if 0
00483 case XK_Shift_L: return KC_SHIFT_L;
00484 case XK_Shift_R: return KC_SHIFT_R;
00485 case XK_Control_L: return KC_CONTROL_L;
00486 case XK_Control_R: return KC_CONTROL_R;
00487 case XK_Alt_L: return KC_ALT_L;
00488 case XK_Alt_R: return KC_ALT_R;
00489 #endif
00490 }
00491 }
00492
00493 default:
00494
00495 if(( key >= ' ' && key <= '~' ) ||
00496 ( key >= 0xa0 ))
00497
00498 return key;
00499
00500 EQWARN << "Unrecognized key " << key << endl;
00501 return KC_VOID;
00502 }
00503 }
00504
00505
00506 #ifdef EQ_USE_MAGELLAN
00507 extern "C" OSErr InstallConnexionHandlers( ConnexionMessageHandlerProc,
00508 ConnexionAddedHandlerProc,
00509 ConnexionRemovedHandlerProc )
00510 __attribute__((weak_import));
00511
00512 namespace
00513 {
00514 static uint16_t _magellanID = 0;
00515 static Node* _magellanNode = 0;
00516
00517 void _magellanEventHandler( io_connect_t connection, natural_t messageType,
00518 void *messageArgument )
00519 {
00520 switch (messageType)
00521 {
00522 case kConnexionMsgDeviceState:
00523 {
00524 ConnexionDeviceState *state = static_cast< ConnexionDeviceState* >(
00525 messageArgument );
00526 if( state->client == _magellanID )
00527 {
00528 ConfigEvent event;
00529 event.data.originator = _magellanNode->getID();
00530 event.data.magellan.buttons = state->buttons;
00531 event.data.magellan.xAxis = state->axis[0];
00532 event.data.magellan.yAxis = state->axis[1];
00533 event.data.magellan.zAxis = state->axis[2];
00534 event.data.magellan.xRotation = state->axis[3];
00535 event.data.magellan.yRotation = state->axis[4];
00536 event.data.magellan.zRotation = state->axis[5];
00537
00538
00539 switch( state->command )
00540 {
00541 case kConnexionCmdHandleAxis:
00542 event.data.type = Event::MAGELLAN_AXIS;
00543 event.data.magellan.button = 0;
00544 break;
00545
00546 case kConnexionCmdHandleButtons:
00547 event.data.type = Event::MAGELLAN_BUTTON;
00548 event.data.magellan.button = state->value;
00549 break;
00550
00551 default:
00552 EQASSERTINFO( 0, "Unimplemented space mouse command " <<
00553 state->command );
00554 }
00555
00556 _magellanNode->getConfig()->sendEvent( event );
00557 }
00558 break;
00559 }
00560 default:
00561
00562 break;
00563 }
00564 }
00565
00566 }
00567 #endif
00568
00569 void AGLEventHandler::initMagellan( Node* node )
00570 {
00571 #ifdef EQ_USE_MAGELLAN
00572 if( _magellanNode )
00573 EQINFO << "Space Mouse already installed" << std::endl;
00574 else if( !InstallConnexionHandlers )
00575 EQWARN << "Space Mouse drivers not installed" << std::endl;
00576 else if( InstallConnexionHandlers( _magellanEventHandler, 0, 0 ) != noErr )
00577 EQWARN << "Can't install Space Mouse connexion handlers" << std::endl;
00578 else
00579 {
00580 std::string program( '\0' +
00581 base::getFilename( net::Global::getProgramName( )));
00582 program[0] = program.length() - 1;
00583
00584 _magellanID = RegisterConnexionClient( 0, (uint8_t*)program.c_str( ),
00585 kConnexionClientModeTakeOver,
00586 kConnexionMaskAll );
00587 _magellanNode = node;
00588 }
00589 #endif
00590 }
00591
00592 void AGLEventHandler::exitMagellan( Node* node )
00593 {
00594 #ifdef EQ_USE_MAGELLAN
00595 if( _magellanID && _magellanNode == node )
00596 {
00597 UnregisterConnexionClient( _magellanID );
00598 CleanupConnexionHandlers();
00599 _magellanID = 0;
00600 _magellanNode = 0;
00601 }
00602 #endif
00603 }
00604
00605 }