/* -*-c++-*- Producer - Copyright (C) 2001-2004 Don Burns * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include #include #ifndef WIN32 #include #include #include #endif #ifdef _X11_IMPLEMENTATION #define explicit c_explicit #include #undef explicit #endif #include #include #include #include #include #include #define TIMER_ID 555 namespace Producer { class KeyboardMouseImplementationBase : public Referenced { public : KeyboardMouseImplementationBase(RenderSurface *rs): _rs(rs), _inputArea(NULL), _cb(NULL), _canceled(false) { _rs->setUseDefaultEsc(false); } KeyboardMouseImplementationBase(InputArea *inputArea): _rs(NULL), _inputArea(inputArea), _cb(NULL), _canceled(false) {} float mx() { return _mx; } float my() { return _my; } unsigned int mbutton() { return _mbutton; } virtual bool update(KeyboardMouseCallback &, bool ) = 0; virtual void startTimer() = 0; void setCallback(KeyboardMouseCallback *cb) { _cb = cb; } virtual void setAutoRepeatMode( bool ) {} virtual bool getAutoRepeatMode() {return true;} virtual void cancel() { _canceled = true; } virtual void positionPointer( float x, float y ) { if( _inputArea != NULL ) { float minL = FLT_MAX; int bestInputRectangle = 0; for(unsigned int i=0;i<_inputArea->getNumRenderSurfaces();++i) { RenderSurface::InputRectangle ir = _inputArea->getRenderSurface(i)->getInputRectangle(); float dx = (x-(ir.left()+ir.width()*0.5f)); float dy = (y-(ir.bottom()+ir.height()*0.5f)); float dl = sqrt(dx*dx+dy*dy); if (dlgetRenderSurface(bestInputRectangle); RenderSurface::InputRectangle ir = rs->getInputRectangle(); int wx, wy; unsigned int w, h; rs->getWindowRectangle( wx, wy, w, h ); int ix = int( (float)(w-1)*(x - ir.left())/ir.width() + 0.5f ); int iy = int( (float)(h-1)*(y - ir.bottom())/ir.height() + 0.5f ); rs->positionPointer(ix, iy ); } else { RenderSurface::InputRectangle ir = _rs->getInputRectangle(); unsigned int ww = _rs->getWindowWidth(); unsigned int wh = _rs->getWindowHeight(); int ix = int(((x - ir.left())/ir.width()) * float(ww-1)+ 0.5f ); int iy = int(((y - ir.bottom())/ir.height()) * float(wh-1)+ 0.5f ); _rs->positionPointer(ix, iy ); } } bool isCanceled() { return _canceled; } virtual void init() = 0; virtual void fini() = 0; protected: virtual ~KeyboardMouseImplementationBase() {} RenderSurface *_rs; InputArea *_inputArea; KeyboardMouseCallback *_cb; float _mx, _my; unsigned int _mbutton; void transformMouseMotion( Window win, int wx, int wy) { if( _inputArea ) { _inputArea->transformMouseMotion( win, wx, wy, _mx, _my); } else { #if defined(_OSX_AGL_IMPLEMENTATION) || defined(_OSX_CGL_IMPLEMENTATION) int positionLeft = 0; int positionTop = 0; int windowWidth = _rs->getWindowWidth(); int windowHeight = _rs->getWindowHeight(); if (win == NULL) { if (!_rs->isFullScreen()) { // mouse pointer can't be in this window. // so don't update _mx, _my. return; } // for full screen render surfaces get the bounds of the complete screen // and check to see if mouse pointer is within this. Display* display = _rs->getDisplay(); CGRect theBounds = CGDisplayBounds(*display); if (wx >= theBounds.origin.x && wy >= theBounds.origin.y && wx <= (theBounds.origin.x + theBounds.size.width) && wy <= (theBounds.origin.y + theBounds.size.height)) { positionLeft = static_cast(theBounds.origin.x); positionTop = static_cast(theBounds.origin.y); windowWidth = static_cast(theBounds.size.width); windowHeight = static_cast(theBounds.size.height); } else { // mouse pointer can't be in this window // so don't update _mx, _my. return; } } else { Rect theBounds; GetWindowBounds (win, kWindowContentRgn, &theBounds); positionLeft = theBounds.left; positionTop = theBounds.top; windowWidth = theBounds.right-theBounds.left; windowHeight = theBounds.bottom-theBounds.top; } #else int positionLeft = 0; int positionTop = 0; int windowWidth = _rs->getWindowWidth(); int windowHeight = _rs->getWindowHeight(); #endif RenderSurface::InputRectangle ir = _rs->getInputRectangle(); _mx = ir.left() + (float(wx-positionLeft)/float(windowWidth))*ir.width(); _my = ir.bottom() + (float(windowHeight-(wy-positionTop+1))/float(windowHeight-1))*ir.height(); } } bool _canceled; }; } #ifdef _X11_IMPLEMENTATION #include #include #include namespace Producer { class KeyboardMouseImplementation : public KeyboardMouseImplementationBase { public: KeyboardMouseImplementation(InputArea *ia):KeyboardMouseImplementationBase(ia) { init(); } KeyboardMouseImplementation(RenderSurface *rs):KeyboardMouseImplementationBase(rs) { init(); } bool update( KeyboardMouseCallback &cb, bool block=false) { if( block ) { do{ process_event(cb); }while( XPending(dpy)); } else { while( XPending(dpy)) process_event(cb); } cb.idle(); return true; } void startTimer() { struct sigaction act; sigset_t ss; sigemptyset(&ss); act.sa_handler = 0L; act.sa_sigaction = s_trap; act.sa_mask = ss; act.sa_flags = SA_SIGINFO; sigaction( SIGALRM, &act, 0L ); struct itimerval itv; itv.it_interval.tv_sec = 0; itv.it_interval.tv_usec = 10000; itv.it_value = itv.it_interval; setitimer(ITIMER_REAL, &itv, (struct itimerval *)0 ); } virtual void setAutoRepeatMode( bool flag ) { int supported; if( flag == false ) XkbSetDetectableAutoRepeat( dpy, true, &supported ); else XkbSetDetectableAutoRepeat( dpy, false, &supported ); if( supported == 0 ) { std::cerr << "KeyboardMouse::setAutoRepeateMode("<getRenderSurface(0); std::string hostname = _rs->getHostName(); if( hostname.empty() ) sprintf( dpyname, ":%d.%d", _rs->getDisplayNum(), _rs->getScreenNum() ); else sprintf( dpyname, "%s:%d.%d", hostname.c_str(), _rs->getDisplayNum(), _rs->getScreenNum() ); if((dpy = XOpenDisplay(dpyname)) == NULL) { std::cerr << "KeyboardMouse() unable to open display " << XDisplayName("") << std::endl; return; } _inputMask = StructureNotifyMask | KeyPressMask | KeyReleaseMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask ; //ButtonMotionMask | ButtonPressMask | ButtonReleaseMask ; if( _inputArea != NULL ) { for( unsigned int i = 0; i < _inputArea->getNumWindows(); i++ ) { Window win = _inputArea->getWindow(i); XSelectInput( dpy, win, _inputMask ); } } else { Window win = _rs->getWindow(); XSelectInput( dpy, win, _inputMask ); } _mbutton = 0; //XGetKeyboardControl( dpy, &_originalKBState ); //_changeKBStateMask = 0L; // Possible inconsistency if global mode is set to off. // Assumption here is that autoRepeatMode is true if we will // be testing at the client level for repeated keys. _autoRepeatMode = true; } virtual void fini() { // Force a KeyPress event here to kick the thread out of select/XNextEvent if( _rs->isRealized() ) { // Need a local, temporary connection to the server char dpyname[128]; std::string hostname = _rs->getHostName(); if( hostname.empty() ) sprintf( dpyname, ":%d.%d", _rs->getDisplayNum(), _rs->getScreenNum() ); else sprintf( dpyname, "%s:%d.%d", hostname.c_str(), _rs->getDisplayNum(), _rs->getScreenNum() ); Display *dpy = XOpenDisplay(dpyname); if( dpy ) { XEvent ev; ev.xkey.keycode = 9; // 9 = ESC if( _inputArea != NULL ) { for( unsigned int i = 0; i < _inputArea->getNumRenderSurfaces(); i++ ) { RenderSurface *rs = _inputArea->getRenderSurface(i); ev.type = KeyPress; XSendEvent( dpy, _inputArea->getRenderSurface(i)->getWindow(), True, KeyPressMask, &ev ); ev.type = KeyRelease; XSendEvent( dpy, _inputArea->getRenderSurface(i)->getWindow(), True, KeyPressMask, &ev ); } } else { ev.type = KeyPress; XSendEvent( dpy, _rs->getWindow(), True, KeyPressMask, &ev ); ev.type = KeyRelease; XSendEvent( dpy, _rs->getWindow(), True, KeyPressMask, &ev ); } XFlush(dpy);XSync(dpy,0); XCloseDisplay(dpy); } } } protected: virtual ~KeyboardMouseImplementation() {} private: Display *dpy; long _inputMask; bool _autoRepeatMode; class KeymapState { public: KeymapState() { memset( _keys,0, sizeof(_keys)); } KeymapState(char keys[32]) { memcpy( _keys, keys, sizeof( _keys )); } KeymapState( const KeymapState &ks ) { memcpy( _keys, ks._keys, sizeof( _keys )); } void operator = (char keys[32]) { memcpy( _keys, keys, sizeof( _keys )); } bool operator == (char keys[32]) { unsigned int *lhs = (unsigned int *)&_keys[0]; unsigned int *rhs = (unsigned int *)&keys[0]; return (lhs[0] == rhs[0] && lhs[1] == rhs[1] && lhs[2] == rhs[2] && lhs[3] == rhs[3] && lhs[4] == rhs[4] && lhs[5] == rhs[5] && lhs[6] == rhs[6] && lhs[7] == rhs[7] ); } private: char _keys[32]; }; KeymapState _keymapState; void process_event( KeyboardMouseCallback &cb) { XEvent ev; XNextEvent( dpy, &ev ); switch( ev.type ) { case DestroyNotify: cb.shutdown(); break; case ConfigureNotify: break; case MotionNotify : { int wx, wy; Window win = 0L; if( ev.xmotion.same_screen ) { wx = ev.xmotion.x; wy = ev.xmotion.y; win = ev.xmotion.window; } else { Window root; int rx, ry; unsigned int buttons; Window parent = 0L; for( int i= 0; i < ScreenCount(dpy); i++ ) { if( XQueryPointer( dpy, RootWindow(dpy, i), &root, &win, &rx, &ry, &wx, &wy, &buttons) ) { parent = win; win = XmuClientWindow( dpy, parent ); break; } } XWindowAttributes watt; XGetWindowAttributes(dpy,parent,&watt); wx -= watt.x; wy -= watt.y; } transformMouseMotion(win, wx, wy ); if( _mbutton ) cb.mouseMotion(_mx, _my); else cb.passiveMouseMotion(_mx, _my); } break; case ButtonPress : if( ev.xbutton.button == Button4 ) cb.mouseScroll(KeyboardMouseCallback::ScrollUp); else if( ev.xbutton.button == Button5) cb.mouseScroll(KeyboardMouseCallback::ScrollDown); else { transformMouseMotion( ev.xmotion.window, ev.xbutton.x, ev.xmotion.y ); cb.buttonPress( _mx, _my, ev.xbutton.button ); _mbutton |= (1<<(ev.xbutton.button-1)); } break; case ButtonRelease : if( ev.xbutton.button != Button4 && ev.xbutton.button != Button5 ) { transformMouseMotion( ev.xmotion.window, ev.xbutton.x, ev.xmotion.y); cb.buttonRelease( _mx, _my, ev.xbutton.button ); _mbutton &= ~(1<<(ev.xbutton.button-1)); } break; case KeyPress: { // Check for auto repeated keys and autoRepeat flag; if( _autoRepeatMode == false ) { char keys[32]; XQueryKeymap( dpy, keys ); if( _keymapState == keys ) // We have an autorepeat. break; _keymapState = keys; } KeyCharacter keychar = Keyboard::getSingleton()->xkeyEventToKeyChar(dpy, ev.xkey); if( keychar != KeyChar_Unknown ) { if( keychar & 0xFF00 ) cb.specialKeyPress(keychar); else cb.keyPress(keychar); } } break; case KeyRelease: { if( _autoRepeatMode == false ) { char keys[32]; XQueryKeymap( dpy, keys ); _keymapState = keys; } KeyCharacter keychar = Keyboard::getSingleton()->xkeyEventToKeyChar(dpy, ev.xkey); if( keychar != KeyChar_Unknown ) { if( keychar & 0xFF00 ) cb.specialKeyRelease(keychar); else cb.keyRelease(keychar); } } break; } } static void s_trap( int, siginfo_t *, void *) {} }; } #endif #ifdef _WIN32_IMPLEMENTATION namespace Producer { class KeyboardMouseImplementation : public KeyboardMouseImplementationBase { public: KeyboardMouseImplementation(InputArea *ia):KeyboardMouseImplementationBase(ia) { init(); } KeyboardMouseImplementation(RenderSurface *rs):KeyboardMouseImplementationBase(rs) { init(); } bool update( KeyboardMouseCallback &cb, bool block=false) { if( block ) { //Wait until at least one event queue has an event or cancel signal is set DWORD waitResult = WaitForMultipleObjects(signals.size(),&signals.front(),FALSE,INFINITE); //Check if cancel event was signaled if(waitResult - WAIT_OBJECT_0 == signals.size()-1) return true; } std::vector< Producer::ref_ptr >::iterator p; for( p = qs.begin(); p != qs.end(); p++ ) { EventQueue *q = (*p).get(); while( ! q->empty() ) { Event *ev = q->front().get(); if(!cb.handle(*ev)) //Allow callback to handle raw event { switch( ev->type() ) { case Event::WindowConfig : { WindowConfigEvent *wc = dynamic_cast(ev); if( wc != NULL ) { // NOt using these now... } } break; case Event::KeyPress : { KeyPressEvent *kp = dynamic_cast(ev); if( kp != NULL ) { KeyCharacter kchar = KeyCharacter(kp->key()); if( kchar & 0xFF00 ) cb.specialKeyPress( kchar ); else cb.keyPress( kchar ); } } break; case Event::KeyRelease : { KeyReleaseEvent *kr = dynamic_cast(ev); if( kr != NULL ) { KeyCharacter kchar = KeyCharacter(kr->key()); if( kchar & 0xFF00 ) cb.specialKeyRelease(kchar); else cb.keyRelease(kchar); } } break; case Event::ButtonPress : { ButtonPressEvent *bp = dynamic_cast(ev); transformMouseMotion( bp->window(), bp->mx(), bp->my() ); _mbutton |= (1<<(bp->button()-1)); if( bp != NULL ) cb.buttonPress( _mx, _my, bp->button() ); } break; case Event::ButtonRelease : { ButtonReleaseEvent *br = dynamic_cast(ev); if( br != NULL ) { transformMouseMotion( br->window(), br->mx(), br->my() ); _mbutton &= ~(1<<(br->button()-1)); cb.buttonRelease( _mx, _my, br->button() ); } } break; case Event::MouseScroll: { MouseScrollEvent *mse = dynamic_cast(ev); if( mse != NULL ) { cb.mouseScroll(mse->scrollingMotion() ); } } break; case Event::MouseMotion : { MouseMotionEvent *mm = dynamic_cast(ev); transformMouseMotion( mm->window(), mm->mx(), mm->my() ); if( mm != NULL ) { if( _mbutton ) cb.mouseMotion(_mx, _my); else cb.passiveMouseMotion(_mx, _my); } } break; case Event::Timer : // Nothing to do, really. break; case Event::Shutdown: cb.shutdown(); break; case Event::DoubleButtonPress : { DoubleButtonPressEvent *bp = dynamic_cast(ev); transformMouseMotion( bp->window(), bp->mx(), bp->my() ); _mbutton |= (1<<(bp->button()-1)); if( bp != NULL ) cb.doubleButtonPress( _mx, _my, bp->button() ); } break; case Event::ButtonMotion : break; } } q->pop_front(); } cb.idle(); } return true; } virtual void startTimer() { ::SetTimer(_rs->getWindow(),TIMER_ID, 10, NULL ); } virtual void init() { unsigned int mask = Event::KeyPressMask | Event::KeyReleaseMask | Event::ButtonPressMask | Event::ButtonReleaseMask | Event::ButtonMotionMask | Event::DoubleButtonPressMask | Event::MouseMotionMask| Event::MouseScrollMask | Event::WindowConfigMask| Event::ShutdownMask; if( _inputArea != NULL ) { for( unsigned int i = 0; i < _inputArea->getNumRenderSurfaces(); i++ ) { RenderSurface *rs = _inputArea->getRenderSurface(i); EventQueue *q = rs->selectInput(mask); qs.push_back(q); signals.push_back(q->getSignal()); } } else { EventQueue *q = _rs->selectInput(mask); qs.push_back(q); signals.push_back(q->getSignal()); } cancelSignal = CreateEvent(NULL,TRUE,FALSE,NULL); signals.push_back(cancelSignal); _mbutton = 0; } virtual void cancel() { SetEvent(cancelSignal); KeyboardMouseImplementationBase::cancel(); } void fini() { cancel(); } protected: virtual ~KeyboardMouseImplementation() { CloseHandle(cancelSignal); } private: std::vector< Producer::ref_ptr > qs; std::vector< HANDLE > signals; HANDLE cancelSignal; }; } #endif #if defined(_OSX_AGL_IMPLEMENTATION) || defined(_OSX_CGL_IMPLEMENTATION) namespace Producer { class KeyboardMouseImplementation : public KeyboardMouseImplementationBase { public: KeyboardMouseImplementation(InputArea *ia):KeyboardMouseImplementationBase(ia) { init(); } KeyboardMouseImplementation(RenderSurface *rs):KeyboardMouseImplementationBase(rs) { init(); } virtual ~KeyboardMouseImplementation() {} bool handleMouseEvent(KeyboardMouseCallback &cb, EventRef theEvent) { // mouse down event Point wheresMyMouse; GetEventParameter (theEvent, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(wheresMyMouse), NULL, &wheresMyMouse); WindowRef win; int fwres = FindWindow(wheresMyMouse, &win); if (fwres == inDrag) { return false; } else { EventMouseButton mouseButton; GetEventParameter (theEvent, kEventParamMouseButton, typeMouseButton, NULL, sizeof(mouseButton), NULL, &mouseButton); // swap right and middle buttons so that middle button is 2, right button is 3. if (mouseButton==3) mouseButton = 2; else if (mouseButton==2) mouseButton = 3; // check tablet pointer device and map it to a musebutton TabletProximityRec theTabletRecord; // The Tablet Proximity Record // Extract the Tablet Proximity reccord from the event. if(noErr == GetEventParameter(theEvent, kEventParamTabletProximityRec, typeTabletProximityRec, NULL, sizeof(TabletProximityRec), NULL, (void *)&theTabletRecord)) { KeyboardMouseCallback::TabletPointerType pointerType; switch(theTabletRecord.pointerType) { case 1: // pen pointerType = KeyboardMouseCallback::Pen; break; case 2: // puck pointerType = KeyboardMouseCallback::Puck; break; case 3: //eraser pointerType = KeyboardMouseCallback::Eraser; break; default: pointerType = KeyboardMouseCallback::Unknown; break; } cb.penProximity(pointerType, (theTabletRecord.enterProximity != 0)); } switch(GetEventKind(theEvent)) { case kEventMouseDown: if (mouseButton==1) _actual_button1Pressed = true; if (mouseButton==2) _actual_button2Pressed = true; if (mouseButton==3) _actual_button3Pressed = true; updateMouseButtonState(cb); break; case kEventMouseUp: if (mouseButton==1) _actual_button1Pressed = false; if (mouseButton==2) _actual_button2Pressed = false; if (mouseButton==3) _actual_button3Pressed = false; updateMouseButtonState(cb); break; case kEventMouseDragged: { // get pressure from the pen, only when mouse/pen is dragged TabletPointRec theTabletRecord; if(noErr == GetEventParameter(theEvent, kEventParamTabletPointRec, typeTabletPointRec, NULL, sizeof(TabletPointRec), NULL, (void *)&theTabletRecord)) { cb.penPressure(theTabletRecord.pressure / 65535.0f); } } break; case kEventMouseMoved: break; // mouse with scroll-wheels case kEventMouseWheelMoved: { EventMouseWheelAxis axis; SInt32 delta; if (noErr == GetEventParameter( theEvent, kEventParamMouseWheelAxis, typeMouseWheelAxis, NULL, sizeof(axis), NULL, &axis )) { if (noErr == GetEventParameter( theEvent, kEventParamMouseWheelDelta, typeLongInteger, NULL, sizeof(delta), NULL, &delta )) { switch (axis) { case kEventMouseWheelAxisX: cb.mouseScroll( (delta > 0) ? KeyboardMouseCallback::ScrollRight : KeyboardMouseCallback::ScrollLeft); break; case kEventMouseWheelAxisY: cb.mouseScroll( (delta < 0) ? KeyboardMouseCallback::ScrollDown : KeyboardMouseCallback::ScrollUp); break; } } } } break; // new trackpads and mighty mouse, (not officially documented, see http://developer.apple.com/qa/qa2005/qa1453.html ) case 11: { enum { kEventParamMouseWheelSmoothVerticalDelta = 'saxy', // typeSInt32 kEventParamMouseWheelSmoothHorizontalDelta = 'saxx', // typeSInt32 }; SInt32 scroll_delta_x = 0; SInt32 scroll_delta_y = 0; OSErr err = noErr; err = GetEventParameter( theEvent, kEventParamMouseWheelSmoothVerticalDelta, typeLongInteger, NULL, sizeof(scroll_delta_y), NULL, &scroll_delta_y ); err = GetEventParameter( theEvent, kEventParamMouseWheelSmoothHorizontalDelta, typeLongInteger, NULL, sizeof(scroll_delta_x), NULL, &scroll_delta_x ); if ((scroll_delta_x != 0) || (scroll_delta_y != 0)) { cb.mouseScroll2D( scroll_delta_x, scroll_delta_y); } } break; default: return false; } updateMouseButtonState(cb); if( _ox != wheresMyMouse.h || _oy != wheresMyMouse.v ) { _ox = wheresMyMouse.h; _oy = wheresMyMouse.v; transformMouseMotion(win, _ox, _oy); if( _mbutton ) cb.mouseMotion(_mx, _my); else cb.passiveMouseMotion(_mx, _my); } return true; } } bool handleKeyboardEvent(KeyboardMouseCallback &cb, EventRef theEvent) { OSStatus status; UInt32 modifierKeys; GetEventParameter (theEvent,kEventParamKeyModifiers,typeUInt32, NULL,sizeof(modifierKeys), NULL,&modifierKeys); UInt32 dataSize; /* jbw check return status so that we don't allocate a huge array */ status = GetEventParameter( theEvent, kEventParamKeyUnicodes, typeUnicodeText, NULL, 0, &dataSize, NULL ); if (status != noErr) return false; if (dataSize<=1) return false; UniChar* uniChars = new UniChar[dataSize+1]; GetEventParameter( theEvent, kEventParamKeyUnicodes, typeUnicodeText, NULL, dataSize, NULL, (void*)uniChars ); KeyCharacter keychar = Keyboard::getSingleton()->akeyEventToKeyChar(static_cast(uniChars[0])); switch(GetEventKind(theEvent)) { case kEventRawKeyDown: { if( keychar & 0xFF00 ) cb.specialKeyPress(keychar); else cb.keyPress(keychar); break; } case kEventRawKeyRepeat: { if( keychar & 0xFF00 ) cb.specialKeyPress(keychar); else cb.keyPress(keychar); break; } case kEventRawKeyUp: { if( keychar & 0xFF00 ) cb.specialKeyRelease(keychar); else cb.keyRelease(keychar); break; } case kEventRawKeyModifiersChanged: updateMouseButtonState(cb); break; case kEventHotKeyPressed: break; case kEventHotKeyReleased: break; default: break; } delete[] uniChars; return true; } bool update( KeyboardMouseCallback &cb, bool block=false) { EventRef theEvent; EventTargetRef theTarget = GetEventDispatcherTarget(); while (ReceiveNextEvent(0, NULL, 0,true, &theEvent)== noErr) { switch(GetEventClass(theEvent)) { case kEventClassTablet: case kEventClassMouse: if (!handleMouseEvent(cb, theEvent)) {} SendEventToEventTarget (theEvent, theTarget); break; case kEventClassKeyboard: handleKeyboardEvent(cb, theEvent); break; default: SendEventToEventTarget (theEvent, theTarget); break; } ReleaseEvent(theEvent); } return true; } virtual void startTimer() {} virtual void init() { _actual_button1Pressed = false; _actual_button2Pressed = false; _actual_button3Pressed = false; _computed_button1Pressed = false; _computed_button2Pressed = false; _computed_button3Pressed = false; _previous_button1Pressed = false; _previous_button2Pressed = false; _previous_button3Pressed = false; } virtual void fini() { } void updateMouseButtonState(KeyboardMouseCallback &cb) { _computed_button2Pressed = _actual_button2Pressed; _computed_button3Pressed = _actual_button3Pressed; if (_actual_button1Pressed) { UInt32 modKey = GetCurrentKeyModifiers(); if (modKey & 0x100) { _computed_button3Pressed = true; _computed_button1Pressed = false; } else if (modKey & 0x800) { _computed_button2Pressed = true; _computed_button1Pressed = false; } else { _computed_button1Pressed = true; } } else { _computed_button1Pressed = false; } if (_previous_button1Pressed != _computed_button1Pressed) { if (_computed_button1Pressed) cb.buttonPress(_mx,_my, 1); else cb.buttonRelease(_mx,_my, 1); _previous_button1Pressed = _computed_button1Pressed; } if (_previous_button2Pressed != _computed_button2Pressed) { if (_computed_button2Pressed) cb.buttonPress(_mx,_my, 2); else cb.buttonRelease(_mx,_my, 2); _previous_button2Pressed = _computed_button2Pressed; } if (_previous_button3Pressed != _computed_button3Pressed) { if (_computed_button3Pressed) cb.buttonPress(_mx,_my, 3); else cb.buttonRelease(_mx,_my, 3); _previous_button3Pressed = _computed_button3Pressed; } } private: short _ox, _oy; bool _actual_button1Pressed; bool _actual_button2Pressed; bool _actual_button3Pressed; bool _computed_button1Pressed; bool _computed_button2Pressed; bool _computed_button3Pressed; bool _previous_button1Pressed; bool _previous_button2Pressed; bool _previous_button3Pressed; }; } #endif using namespace Producer; KeyboardMouse::KeyboardMouse(Producer::RenderSurface *rs) : _implementation(NULL), _initialized(false) { _rs = rs; //std::cout << "Constructing Threaded KeyboardMouse "<cancel(); _implementation->fini(); } } //cancel(); while (isRunning()) { //std::cout << "waiting for keyboard mouse to cancel"<isRealized() == false ) _inputArea->waitForRealize(); _implementation = new KeyboardMouseImplementation(_inputArea.get() ); } else { _rs->waitForRealize(); if( _rs->isRealized() == false ) return false; _implementation = new KeyboardMouseImplementation(_rs.get() ); } _initialized = true; return _initialized; } void KeyboardMouse::update(KeyboardMouseCallback &cb, bool block) { if( !_initialized && !init() ) return; _implementation->update(cb, block); } void KeyboardMouse::setCallback( KeyboardMouseCallback *cb ) { _cb = cb; } void KeyboardMouse::positionPointer( float x, float y ) { if( !_initialized && !init() ) return; _implementation->positionPointer( x, y ); } bool KeyboardMouse::computePixelCoords(float x, float y, RenderSurface* rs, float& pixel_x, float& pixel_y) { if( _inputArea != NULL ) { // first locate which InputRectange is appropriate for specified RenderSurface. unsigned int i; for(i=0;i<_inputArea->getNumRenderSurfaces();++i) { if (_inputArea->getRenderSurface(i)==rs) break; } // the RenderSurface isn't in the InputArea list.. therefore cannot make mouse coords to it. if (i==_inputArea->getNumRenderSurfaces()) return false; // we have a valid InputRectangle RenderSurface::InputRectangle ir = _inputArea->getRenderSurface(i)->getInputRectangle(); // clip out coords which arn't in this InputRectangle. if (x(ir.left()+ir.width())) return false; if (y(ir.bottom()+ir.height())) return false; float rx = (x-ir.left())/ir.width(); float ry = (y-ir.bottom())/ir.height(); int wx, wy; unsigned int w, h; rs->getWindowRectangle( wx, wy, w, h ); pixel_x = (float)wx + ((float)w)* rx; pixel_y = (float)wy + ((float)h)* ry; return true; } else { // clip out coords that arn't on RenderSurface. if (x<-1.0f) return false; if (x>1.0f) return false; if (y<-1.0f) return false; if (y>1.0f) return false; float rx = (x+1.0f)*0.5f; float ry = (y+1.0f)*0.5f; int wx, wy; unsigned int w, h; _rs->getWindowRectangle( wx, wy, w, h ); pixel_x = (float)wx + ((float)w)* rx; pixel_y = (float)wy + ((float)h)* ry; return true; } } void KeyboardMouse::setAutoRepeatMode( bool flag ) { if( !_initialized && !init() ) return; _implementation->setAutoRepeatMode(flag); } bool KeyboardMouse::getAutoRepeatMode() { if( !_initialized && !init() ) return false; return _implementation->getAutoRepeatMode(); } void KeyboardMouse::run() { if( _cb == NULL ) { std::cerr << "KeyboardMouse: internal thread cannot start because\n" "no callback has been specified. Please specify a \n" "callback with KeyboardMouse::setCallback() first.\n"; return; } if( !_initialized ) { if( !init() ) { std::cerr << "KeyboardMouse::run() - Internal error!" << std::endl; return; } } _implementation->setCallback( _cb.get() ); while( !_implementation->isCanceled() ) { _implementation->update(*_cb,true); testCancel(); } }