diff --git a/lib/client/CClient.cpp b/lib/client/CClient.cpp index 35fefe1e..f1f4ae22 100644 --- a/lib/client/CClient.cpp +++ b/lib/client/CClient.cpp @@ -181,8 +181,7 @@ CClient::enter(SInt32 xAbs, SInt32 yAbs, UInt32, KeyModifierMask mask, bool) { m_active = true; m_screen->mouseMove(xAbs, yAbs); - m_screen->enter(); - m_screen->setToggleState(mask); + m_screen->enter(mask); } bool diff --git a/lib/platform/CXWindowsKeyMapper.cpp b/lib/platform/CXWindowsKeyState.cpp similarity index 89% rename from lib/platform/CXWindowsKeyMapper.cpp rename to lib/platform/CXWindowsKeyState.cpp index 5ff68ebd..0397ce3c 100644 --- a/lib/platform/CXWindowsKeyMapper.cpp +++ b/lib/platform/CXWindowsKeyState.cpp @@ -12,9 +12,10 @@ * GNU General Public License for more details. */ -#include "CXWindowsKeyMapper.h" +#include "CXWindowsKeyState.h" #include "CXWindowsUtil.h" #include "CLog.h" +#include "CStringUtil.h" #if defined(X_DISPLAY_MISSING) # error X11 is required to build synergy #else @@ -137,73 +138,119 @@ static const KeySym g_mapE000[] = }; #endif -CXWindowsKeyMapper::CXWindowsKeyMapper() +CXWindowsKeyState::CXWindowsKeyState(Display* display) : + m_display(display) { // do nothing } -CXWindowsKeyMapper::~CXWindowsKeyMapper() +CXWindowsKeyState::~CXWindowsKeyState() { // do nothing } +KeyModifierMask +CXWindowsKeyState::mapModifiersFromX(unsigned int state) const +{ + KeyModifierMask mask = 0; + if (state & ShiftMask) + mask |= KeyModifierShift; + if (state & LockMask) + mask |= KeyModifierCapsLock; + if (state & ControlMask) + mask |= KeyModifierControl; + if (state & m_altMask) + mask |= KeyModifierAlt; + if (state & m_metaMask) + mask |= KeyModifierMeta; + if (state & m_superMask) + mask |= KeyModifierSuper; + if (state & m_modeSwitchMask) + mask |= KeyModifierModeSwitch; + if (state & m_numLockMask) + mask |= KeyModifierNumLock; + if (state & m_scrollLockMask) + mask |= KeyModifierScrollLock; + return mask; +} + +const char* +CXWindowsKeyState::getKeyName(KeyButton keycode) const +{ + KeySym keysym = XKeycodeToKeysym(m_display, keycode, 0); + char* name = XKeysymToString(keysym); + if (name != NULL) { + return name; + } + else { + static char buffer[20]; + return strcpy(buffer, + CStringUtil::print("keycode %d", keycode).c_str()); + } +} + void -CXWindowsKeyMapper::update(Display* display, IKeyState* keyState) +CXWindowsKeyState::doUpdateKeys() { // query which keys are pressed char keys[32]; - XQueryKeymap(display, keys); + XQueryKeymap(m_display, keys); // save the auto-repeat mask - XGetKeyboardControl(display, &m_keyControl); + XGetKeyboardControl(m_display, &m_keyControl); // query the pointer to get the keyboard state - Window root = DefaultRootWindow(display), window; + Window root = DefaultRootWindow(m_display), window; int xRoot, yRoot, xWindow, yWindow; unsigned int state; - if (!XQueryPointer(display, root, &root, &window, + if (!XQueryPointer(m_display, root, &root, &window, &xRoot, &yRoot, &xWindow, &yWindow, &state)) { state = 0; } // update mappings - updateKeysymMap(display, keyState); + updateKeysymMap(); updateModifiers(); // transfer to our state for (UInt32 i = 0, j = 0; i < 32; j += 8, ++i) { if ((keys[i] & 0x01) != 0) - keyState->setKeyDown(j + 0, true); + setKeyDown(j + 0, true); if ((keys[i] & 0x02) != 0) - keyState->setKeyDown(j + 1, true); + setKeyDown(j + 1, true); if ((keys[i] & 0x04) != 0) - keyState->setKeyDown(j + 2, true); + setKeyDown(j + 2, true); if ((keys[i] & 0x08) != 0) - keyState->setKeyDown(j + 3, true); + setKeyDown(j + 3, true); if ((keys[i] & 0x10) != 0) - keyState->setKeyDown(j + 4, true); + setKeyDown(j + 4, true); if ((keys[i] & 0x20) != 0) - keyState->setKeyDown(j + 5, true); + setKeyDown(j + 5, true); if ((keys[i] & 0x40) != 0) - keyState->setKeyDown(j + 6, true); + setKeyDown(j + 6, true); if ((keys[i] & 0x80) != 0) - keyState->setKeyDown(j + 7, true); + setKeyDown(j + 7, true); } // set toggle modifier states if ((state & LockMask) != 0) - keyState->setToggled(KeyModifierCapsLock); + setToggled(KeyModifierCapsLock); if ((state & m_numLockMask) != 0) - keyState->setToggled(KeyModifierNumLock); + setToggled(KeyModifierNumLock); if ((state & m_scrollLockMask) != 0) - keyState->setToggled(KeyModifierScrollLock); + setToggled(KeyModifierScrollLock); +} + +void +CXWindowsKeyState::doFakeKeyEvent(KeyButton keycode, bool press, bool) +{ + XTestFakeKeyEvent(m_display, keycode, press ? True : False, CurrentTime); + XFlush(m_display); } KeyButton -CXWindowsKeyMapper::mapKey(IKeyState::Keystrokes& keys, - const IKeyState& keyState, KeyID id, - KeyModifierMask desiredMask, - bool isAutoRepeat) const +CXWindowsKeyState::mapKey(Keystrokes& keys, KeyID id, + KeyModifierMask desiredMask, bool isAutoRepeat) const { // the system translates key events into characters depending // on the modifier key state at the time of the event. to @@ -243,7 +290,7 @@ CXWindowsKeyMapper::mapKey(IKeyState::Keystrokes& keys, if (keyIndex != m_keysymMap.end()) { // the keysym is mapped to some keycode. create the keystrokes // for this keysym. - return mapToKeystrokes(keys, keyState, keyIndex, isAutoRepeat); + return mapToKeystrokes(keys, keyIndex, isAutoRepeat); } // we can't find the keysym mapped to any keycode. this doesn't @@ -272,7 +319,7 @@ CXWindowsKeyMapper::mapKey(IKeyState::Keystrokes& keys, } // the keysym is mapped to some keycode - keycode = mapToKeystrokes(keys, keyState, keyIndex, isAutoRepeat); + keycode = mapToKeystrokes(keys, keyIndex, isAutoRepeat); if (keycode == 0) { return 0; } @@ -281,45 +328,20 @@ CXWindowsKeyMapper::mapKey(IKeyState::Keystrokes& keys, return keycode; } -KeyModifierMask -CXWindowsKeyMapper::mapModifier(unsigned int state) const -{ - KeyModifierMask mask = 0; - if (state & ShiftMask) - mask |= KeyModifierShift; - if (state & LockMask) - mask |= KeyModifierCapsLock; - if (state & ControlMask) - mask |= KeyModifierControl; - if (state & m_altMask) - mask |= KeyModifierAlt; - if (state & m_metaMask) - mask |= KeyModifierMeta; - if (state & m_superMask) - mask |= KeyModifierSuper; - if (state & m_modeSwitchMask) - mask |= KeyModifierModeSwitch; - if (state & m_numLockMask) - mask |= KeyModifierNumLock; - if (state & m_scrollLockMask) - mask |= KeyModifierScrollLock; - return mask; -} - void -CXWindowsKeyMapper::updateKeysymMap(Display* display, IKeyState* keyState) +CXWindowsKeyState::updateKeysymMap() { // there are up to 4 keysyms per keycode static const unsigned int maxKeysyms = 4; // get the number of keycodes int minKeycode, maxKeycode; - XDisplayKeycodes(display, &minKeycode, &maxKeycode); + XDisplayKeycodes(m_display, &minKeycode, &maxKeycode); const int numKeycodes = maxKeycode - minKeycode + 1; // get the keyboard mapping for all keys int keysymsPerKeycode; - KeySym* keysyms = XGetKeyboardMapping(display, + KeySym* keysyms = XGetKeyboardMapping(m_display, minKeycode, numKeycodes, &keysymsPerKeycode); @@ -364,7 +386,7 @@ CXWindowsKeyMapper::updateKeysymMap(Display* display, IKeyState* keyState) } // get modifier map from server - XModifierKeymap* modifiers = XGetModifierMapping(display); + XModifierKeymap* modifiers = XGetModifierMapping(m_display); unsigned int keysPerModifier = modifiers->max_keypermod; // clear state @@ -387,7 +409,7 @@ CXWindowsKeyMapper::updateKeysymMap(Display* display, IKeyState* keyState) for (unsigned int i = 0; i < 8; ++i) { // no keycodes for this modifier yet KeyModifierMask mask = 0; - IKeyState::KeyButtons modifierKeys; + KeyButtons modifierKeys; // add each keycode for modifier for (unsigned int j = 0; j < keysPerModifier; ++j) { @@ -429,9 +451,9 @@ CXWindowsKeyMapper::updateKeysymMap(Display* display, IKeyState* keyState) mapping.m_numLockSensitive = false; } - // tell keyState about this modifier - if (mask != 0 && keyState != NULL) { - keyState->addModifier(mask, modifierKeys); + // note this modifier + if (mask != 0) { + addModifier(mask, modifierKeys); } } @@ -485,7 +507,7 @@ CXWindowsKeyMapper::updateKeysymMap(Display* display, IKeyState* keyState) } KeyModifierMask -CXWindowsKeyMapper::mapToModifierMask(unsigned int i, KeySym keysym) +CXWindowsKeyState::mapToModifierMask(unsigned int i, KeySym keysym) { // some modifier indices (0,1,2) are dedicated to particular uses, // the rest depend on the keysyms bound. @@ -546,16 +568,16 @@ CXWindowsKeyMapper::mapToModifierMask(unsigned int i, KeySym keysym) } void -CXWindowsKeyMapper::updateModifiers() +CXWindowsKeyState::updateModifiers() { struct CModifierBitInfo { public: - KeySym CXWindowsKeyMapper::*m_keysym; + KeySym CXWindowsKeyState::*m_keysym; KeySym m_left; KeySym m_right; }; static const CModifierBitInfo s_modifierBitTable[] = { - { &CXWindowsKeyMapper::m_modeSwitchKeysym, XK_Mode_switch, NoSymbol }, + { &CXWindowsKeyState::m_modeSwitchKeysym, XK_Mode_switch, NoSymbol }, }; // choose the keysym to use for some modifiers. if a modifier has @@ -603,7 +625,7 @@ CXWindowsKeyMapper::updateModifiers() } KeySym -CXWindowsKeyMapper::keyIDToKeySym(KeyID id, KeyModifierMask mask) const +CXWindowsKeyState::keyIDToKeySym(KeyID id, KeyModifierMask mask) const { // convert id to keysym KeySym keysym = NoSymbol; @@ -718,15 +740,13 @@ CXWindowsKeyMapper::keyIDToKeySym(KeyID id, KeyModifierMask mask) const } KeyButton -CXWindowsKeyMapper::mapToKeystrokes(IKeyState::Keystrokes& keys, - const IKeyState& keyState, - KeySymIndex keyIndex, - bool isAutoRepeat) const +CXWindowsKeyState::mapToKeystrokes(Keystrokes& keys, + KeySymIndex keyIndex, bool isAutoRepeat) const { // keyIndex must be valid assert(keyIndex != m_keysymMap.end()); - KeyModifierMask currentMask = keyState.getActiveModifiers(); + KeyModifierMask currentMask = getActiveModifiers(); // get the keysym we're trying to generate and possible keycodes const KeySym keysym = keyIndex->first; @@ -798,14 +818,14 @@ CXWindowsKeyMapper::mapToKeystrokes(IKeyState::Keystrokes& keys, } // adjust the modifiers to match the desired modifiers - IKeyState::Keystrokes undo; - if (!adjustModifiers(keys, undo, keyState, desiredMask)) { + Keystrokes undo; + if (!adjustModifiers(keys, undo, desiredMask)) { LOG((CLOG_DEBUG2 "failed to adjust modifiers")); return 0; } // add the key event - IKeyState::Keystroke keystroke; + Keystroke keystroke; keystroke.m_key = keycode; if (!isAutoRepeat) { keystroke.m_press = true; @@ -830,7 +850,7 @@ CXWindowsKeyMapper::mapToKeystrokes(IKeyState::Keystrokes& keys, } unsigned int -CXWindowsKeyMapper::findBestKeyIndex(KeySymIndex keyIndex, +CXWindowsKeyState::findBestKeyIndex(KeySymIndex keyIndex, KeyModifierMask /*currentMask*/) const { // there are up to 4 keycodes per keysym to choose from. the @@ -856,7 +876,7 @@ CXWindowsKeyMapper::findBestKeyIndex(KeySymIndex keyIndex, } bool -CXWindowsKeyMapper::isShiftInverted(KeySymIndex keyIndex, +CXWindowsKeyState::isShiftInverted(KeySymIndex keyIndex, KeyModifierMask currentMask) const { // each keycode has up to 4 keysym associated with it, one each for: @@ -885,12 +905,11 @@ CXWindowsKeyMapper::isShiftInverted(KeySymIndex keyIndex, } bool -CXWindowsKeyMapper::adjustModifiers(IKeyState::Keystrokes& keys, - IKeyState::Keystrokes& undo, - const IKeyState& keyState, +CXWindowsKeyState::adjustModifiers(Keystrokes& keys, + Keystrokes& undo, KeyModifierMask desiredMask) const { - KeyModifierMask currentMask = keyState.getActiveModifiers(); + KeyModifierMask currentMask = getActiveModifiers(); // get mode switch set correctly. do this before shift because // mode switch may be sensitive to the shift modifier and will @@ -909,8 +928,7 @@ CXWindowsKeyMapper::adjustModifiers(IKeyState::Keystrokes& keys, if (wantShift != haveShift) { // add shift keystrokes LOG((CLOG_DEBUG2 "fix shift for mode switch")); - if (!keyState.mapModifier(keys, undo, - KeyModifierShift, wantShift)) { + if (!mapModifier(keys, undo, KeyModifierShift, wantShift)) { return false; } currentMask ^= KeyModifierShift; @@ -918,8 +936,7 @@ CXWindowsKeyMapper::adjustModifiers(IKeyState::Keystrokes& keys, } // add mode switch keystrokes - if (!keyState.mapModifier(keys, undo, - KeyModifierModeSwitch, wantModeSwitch)) { + if (!mapModifier(keys, undo, KeyModifierModeSwitch, wantModeSwitch)) { return false; } currentMask ^= KeyModifierModeSwitch; @@ -931,7 +948,7 @@ CXWindowsKeyMapper::adjustModifiers(IKeyState::Keystrokes& keys, if (wantShift != haveShift) { // add shift keystrokes LOG((CLOG_DEBUG2 "fix shift")); - if (!keyState.mapModifier(keys, undo, KeyModifierShift, wantShift)) { + if (!mapModifier(keys, undo, KeyModifierShift, wantShift)) { return false; } currentMask ^= KeyModifierShift; @@ -941,13 +958,13 @@ CXWindowsKeyMapper::adjustModifiers(IKeyState::Keystrokes& keys, } bool -CXWindowsKeyMapper::isNumLockSensitive(KeySym keysym) const +CXWindowsKeyState::isNumLockSensitive(KeySym keysym) const { return (IsKeypadKey(keysym) || IsPrivateKeypadKey(keysym)); } bool -CXWindowsKeyMapper::isCapsLockSensitive(KeySym keysym) const +CXWindowsKeyState::isCapsLockSensitive(KeySym keysym) const { KeySym lKey, uKey; XConvertCase(keysym, &lKey, &uKey); @@ -956,10 +973,10 @@ CXWindowsKeyMapper::isCapsLockSensitive(KeySym keysym) const // -// CXWindowsKeyMapper::KeyMapping +// CXWindowsKeyState::KeyMapping // -CXWindowsKeyMapper::KeyMapping::KeyMapping() +CXWindowsKeyState::KeyMapping::KeyMapping() { m_keycode[0] = 0; m_keycode[1] = 0; diff --git a/lib/platform/CXWindowsKeyMapper.h b/lib/platform/CXWindowsKeyState.h similarity index 68% rename from lib/platform/CXWindowsKeyMapper.h rename to lib/platform/CXWindowsKeyState.h index 0c707aa5..98458228 100644 --- a/lib/platform/CXWindowsKeyMapper.h +++ b/lib/platform/CXWindowsKeyState.h @@ -12,62 +12,55 @@ * GNU General Public License for more details. */ -#ifndef CXWINDOWSKEYMAPPER_H -#define CXWINDOWSKEYMAPPER_H +#ifndef CXWINDOWSKEYSTATE_H +#define CXWINDOWSKEYSTATE_H -#include "IKeyState.h" +#include "CKeyState.h" #include "stdmap.h" #if defined(X_DISPLAY_MISSING) # error X11 is required to build synergy #else # include +# if defined(HAVE_X11_EXTENSIONS_XTEST_H) +# include +# else +# error The XTest extension is required to build synergy +# endif #endif -//! X Windows key mapper +//! X Windows key state /*! -This class maps KeyIDs to keystrokes. +A key state for X Windows. */ -class CXWindowsKeyMapper { +class CXWindowsKeyState : public CKeyState { public: - CXWindowsKeyMapper(); - ~CXWindowsKeyMapper(); + CXWindowsKeyState(Display*); + ~CXWindowsKeyState(); - //! @name manipulators - //@{ - - //! Update key mapper - /*! - Updates the key mapper's internal tables according to the display's - current keyboard mapping and updates \c keyState. - */ - void update(Display*, IKeyState* keyState); - - //@} //! @name accessors //@{ - //! Map key press/repeat to keystrokes - /*! - Converts a press/repeat of key \c id with the modifiers as given - in \c desiredMask into the keystrokes necessary to synthesize - that key event. Returns the platform specific code of the key - being pressed, or 0 if the key cannot be mapped or \c isAutoRepeat - is true and the key does not auto-repeat. - */ - KeyButton mapKey(IKeyState::Keystrokes&, - const IKeyState& keyState, KeyID id, - KeyModifierMask desiredMask, - bool isAutoRepeat) const; - //! Convert X modifier mask to synergy mask /*! - Returns the synergy modifier mask corresponding to the given X - modifier mask. + Returns the synergy modifier mask corresponding to the X modifier + mask in \p state. */ - KeyModifierMask mapModifier(unsigned int state) const; + KeyModifierMask mapModifiersFromX(unsigned int state) const; //@} + // IKeyState overrides + virtual const char* getKeyName(KeyButton) const; + +protected: + // IKeyState overrides + virtual void doUpdateKeys(); + virtual void doFakeKeyEvent(KeyButton button, + bool press, bool isAutoRepeat); + virtual KeyButton mapKey(Keystrokes& keys, KeyID id, + KeyModifierMask desiredMask, + bool isAutoRepeat) const; + private: class KeyMapping { public: @@ -90,9 +83,8 @@ private: typedef std::map KeySymMap; typedef KeySymMap::const_iterator KeySymIndex; - // save the current keyboard mapping and note the currently - // pressed keys in \c keyState. - void updateKeysymMap(Display* display, IKeyState* keyState); + // save the current keyboard mapping and note the modifiers + void updateKeysymMap(); // note interesting modifier KeySyms void updateModifiers(); @@ -105,8 +97,7 @@ private: KeySym keyIDToKeySym(KeyID id, KeyModifierMask mask) const; // map a KeySym into the keystrokes to produce it - KeyButton mapToKeystrokes(IKeyState::Keystrokes& keys, - const IKeyState& keyState, + KeyButton mapToKeystrokes(Keystrokes& keys, KeySymIndex keyIndex, bool isAutoRepeat) const; @@ -120,9 +111,8 @@ private: // returns the keystrokes to adjust the modifiers into the desired // state the keystrokes to get back to the current state. - bool adjustModifiers(IKeyState::Keystrokes& keys, - IKeyState::Keystrokes& undo, - const IKeyState& keyState, + bool adjustModifiers(Keystrokes& keys, + Keystrokes& undo, KeyModifierMask desiredMask) const; // returns true if keysym is sensitive to the NumLock state @@ -132,6 +122,8 @@ private: bool isCapsLockSensitive(KeySym keysym) const; private: + Display* m_display; + // keysym to keycode mapping KeySymMap m_keysymMap; diff --git a/lib/platform/CXWindowsScreen.cpp b/lib/platform/CXWindowsScreen.cpp index da9a705c..2531ba8e 100644 --- a/lib/platform/CXWindowsScreen.cpp +++ b/lib/platform/CXWindowsScreen.cpp @@ -15,6 +15,7 @@ #include "CXWindowsScreen.h" #include "CXWindowsClipboard.h" #include "CXWindowsEventQueueBuffer.h" +#include "CXWindowsKeyState.h" #include "CXWindowsScreenSaver.h" #include "CXWindowsUtil.h" #include "CClipboard.h" @@ -131,7 +132,6 @@ CXWindowsScreen::CXWindowsScreen(bool isPrimary) : m_xCenter(0), m_yCenter(0), m_xCursor(0), m_yCursor(0), m_keyState(NULL), - m_keyMapper(), m_im(NULL), m_ic(NULL), m_lastKeycode(0), @@ -154,6 +154,7 @@ CXWindowsScreen::CXWindowsScreen(bool isPrimary) : m_window = openWindow(); m_screensaver = new CXWindowsScreenSaver(m_display, m_window, getEventTarget()); + m_keyState = new CXWindowsKeyState(m_display); LOG((CLOG_DEBUG "screen shape: %d,%d %dx%d %s", m_x, m_y, m_w, m_h, m_xinerama ? "(xinerama)" : "")); LOG((CLOG_DEBUG "window is 0x%08x", m_window)); } @@ -201,7 +202,9 @@ CXWindowsScreen::~CXWindowsScreen() for (ClipboardID id = 0; id < kClipboardEnd; ++id) { delete m_clipboard[id]; } + delete m_keyState; delete m_screensaver; + m_keyState = NULL; m_screensaver = NULL; if (m_display != NULL) { // FIXME -- is it safe to clean up the IC and IM without a display? @@ -219,12 +222,6 @@ CXWindowsScreen::~CXWindowsScreen() s_screen = NULL; } -void -CXWindowsScreen::setKeyState(IKeyState* keyState) -{ - m_keyState = keyState; -} - void CXWindowsScreen::enable() { @@ -319,7 +316,6 @@ CXWindowsScreen::leave() } // raise and show the window - // FIXME -- take focus? XMapRaised(m_display, m_window); // grab the mouse and keyboard, if primary and possible @@ -328,6 +324,9 @@ CXWindowsScreen::leave() return false; } + // take focus + XSetInputFocus(m_display, m_window, RevertToPointerRoot, CurrentTime); + // now warp the mouse. we warp after showing the window so we're // guaranteed to get the mouse leave event and to prevent the // keyboard focus from changing under point-to-focus policies. @@ -428,14 +427,6 @@ CXWindowsScreen::setOptions(const COptionsList& options) } } -void -CXWindowsScreen::updateKeys() -{ - // update keyboard and mouse button mappings - m_keyMapper.update(m_display, m_keyState); - updateButtons(); -} - void CXWindowsScreen::setSequenceNumber(UInt32 seqNum) { @@ -547,21 +538,6 @@ CXWindowsScreen::isAnyMouseButtonDown() const return false; } -KeyModifierMask -CXWindowsScreen::getActiveModifiers() const -{ - // query the pointer to get the modifier state - Window root, window; - int xRoot, yRoot, xWindow, yWindow; - unsigned int state; - if (XQueryPointer(m_display, m_root, &root, &window, - &xRoot, &yRoot, &xWindow, &yWindow, &state)) { - return m_keyMapper.mapModifier(state); - } - - return 0; -} - void CXWindowsScreen::getCursorCenter(SInt32& x, SInt32& y) const { @@ -569,28 +545,6 @@ CXWindowsScreen::getCursorCenter(SInt32& x, SInt32& y) const y = m_yCenter; } -const char* -CXWindowsScreen::getKeyName(KeyButton keycode) const -{ - KeySym keysym = XKeycodeToKeysym(m_display, keycode, 0); - char* name = XKeysymToString(keysym); - if (name != NULL) { - return name; - } - else { - static char buffer[20]; - return strcpy(buffer, - CStringUtil::print("keycode %d", keycode).c_str()); - } -} - -void -CXWindowsScreen::fakeKeyEvent(KeyButton keycode, bool press) const -{ - XTestFakeKeyEvent(m_display, keycode, press ? True : False, CurrentTime); - XFlush(m_display); -} - bool CXWindowsScreen::fakeCtrlAltDel() const { @@ -645,15 +599,6 @@ CXWindowsScreen::fakeMouseWheel(SInt32 delta) const XFlush(m_display); } -KeyButton -CXWindowsScreen::mapKey(IKeyState::Keystrokes& keys, - const IKeyState& keyState, KeyID id, - KeyModifierMask desiredMask, - bool isAutoRepeat) const -{ - return m_keyMapper.mapKey(keys, keyState, id, desiredMask, isAutoRepeat); -} - Display* CXWindowsScreen::openDisplay() const { @@ -788,6 +733,7 @@ CXWindowsScreen::openIM() // open the input methods XIM im = XOpenIM(m_display, NULL, NULL, NULL); if (im == NULL) { + LOG((CLOG_INFO "no support for IM")); return; } @@ -811,7 +757,7 @@ CXWindowsScreen::openIM() } XFree(styles); if (style == 0) { - LOG((CLOG_WARN "no supported IM styles")); + LOG((CLOG_INFO "no supported IM styles")); XCloseIM(im); return; } @@ -859,6 +805,12 @@ CXWindowsScreen::sendClipboardEvent(CEvent::Type type, ClipboardID id) sendEvent(type, info); } +IKeyState* +CXWindowsScreen::getKeyState() const +{ + return m_keyState; +} + Bool CXWindowsScreen::findKeyEvent(Display*, XEvent* xevent, XPointer arg) { @@ -1063,7 +1015,7 @@ void CXWindowsScreen::onKeyPress(XKeyEvent& xkey) { LOG((CLOG_DEBUG1 "event: KeyPress code=%d, state=0x%04x", xkey.keycode, xkey.state)); - const KeyModifierMask mask = m_keyMapper.mapModifier(xkey.state); + const KeyModifierMask mask = m_keyState->mapModifiersFromX(xkey.state); KeyID key = mapKeyFromX(&xkey); if (key != kKeyNone) { // check for ctrl+alt+del emulation @@ -1083,19 +1035,15 @@ CXWindowsScreen::onKeyPress(XKeyEvent& xkey) } // handle key - sendEvent(getKeyDownEvent(), CKeyInfo::alloc(key, mask, keycode, 1)); - KeyModifierMask keyMask = m_keyState->getMaskForKey(keycode); - if (m_keyState->isHalfDuplex(keyMask)) { - sendEvent(getKeyUpEvent(), - CKeyInfo::alloc(key, mask | keyMask, keycode, 1)); - } + m_keyState->sendKeyEvent(getEventTarget(), + true, false, key, mask, 1, keycode); } } void CXWindowsScreen::onKeyRelease(XKeyEvent& xkey, bool isRepeat) { - const KeyModifierMask mask = m_keyMapper.mapModifier(xkey.state); + const KeyModifierMask mask = m_keyState->mapModifiersFromX(xkey.state); KeyID key = mapKeyFromX(&xkey); if (key != kKeyNone) { // check for ctrl+alt+del emulation @@ -1112,12 +1060,8 @@ CXWindowsScreen::onKeyRelease(XKeyEvent& xkey, bool isRepeat) if (!isRepeat) { // no press event follows so it's a plain release LOG((CLOG_DEBUG1 "event: KeyRelease code=%d, state=0x%04x", keycode, xkey.state)); - KeyModifierMask keyMask = m_keyState->getMaskForKey(keycode); - if (m_keyState->isHalfDuplex(keyMask)) { - sendEvent(getKeyDownEvent(), - CKeyInfo::alloc(key, mask, keycode, 1)); - } - sendEvent(getKeyUpEvent(), CKeyInfo::alloc(key, mask, keycode, 1)); + m_keyState->sendKeyEvent(getEventTarget(), + false, false, key, mask, 1, keycode); } else { // found a press event following so it's a repeat. @@ -1125,8 +1069,8 @@ CXWindowsScreen::onKeyRelease(XKeyEvent& xkey, bool isRepeat) // repeats but we'll just send a repeat of 1. // note that we discard the press event. LOG((CLOG_DEBUG1 "event: repeat code=%d, state=0x%04x", keycode, xkey.state)); - sendEvent(getKeyRepeatEvent(), - CKeyInfo::alloc(key, mask, keycode, 1)); + m_keyState->sendKeyEvent(getEventTarget(), + false, true, key, mask, 1, keycode); } } } diff --git a/lib/platform/CXWindowsScreen.h b/lib/platform/CXWindowsScreen.h index 7298190f..41b42a75 100644 --- a/lib/platform/CXWindowsScreen.h +++ b/lib/platform/CXWindowsScreen.h @@ -15,8 +15,7 @@ #ifndef CXWINDOWSSCREEN_H #define CXWINDOWSSCREEN_H -#include "IPlatformScreen.h" -#include "CXWindowsKeyMapper.h" +#include "CPlatformScreen.h" #include "stdvector.h" #if defined(X_DISPLAY_MISSING) # error X11 is required to build synergy @@ -25,10 +24,11 @@ #endif class CXWindowsClipboard; +class CXWindowsKeyState; class CXWindowsScreenSaver; //! Implementation of IPlatformScreen for X11 -class CXWindowsScreen : public IPlatformScreen { +class CXWindowsScreen : public CPlatformScreen { public: CXWindowsScreen(bool isPrimary); virtual ~CXWindowsScreen(); @@ -38,23 +38,6 @@ public: //@} - // IPlatformScreen overrides - virtual void setKeyState(IKeyState*); - virtual void enable(); - virtual void disable(); - virtual void enter(); - virtual bool leave(); - virtual bool setClipboard(ClipboardID, const IClipboard*); - virtual void checkClipboards(); - virtual void openScreensaver(bool notify); - virtual void closeScreensaver(); - virtual void screensaver(bool activate); - virtual void resetOptions(); - virtual void setOptions(const COptionsList& options); - virtual void updateKeys(); - virtual void setSequenceNumber(UInt32); - virtual bool isPrimary() const; - // IScreen overrides virtual void* getEventTarget() const; virtual bool getClipboard(ClipboardID id, IClipboard*) const; @@ -67,29 +50,40 @@ public: virtual void warpCursor(SInt32 x, SInt32 y); virtual SInt32 getJumpZoneSize() const; virtual bool isAnyMouseButtonDown() const; - virtual KeyModifierMask getActiveModifiers() const; virtual void getCursorCenter(SInt32& x, SInt32& y) const; - virtual const char* getKeyName(KeyButton) const; // ISecondaryScreen overrides - virtual void fakeKeyEvent(KeyButton id, bool press) const; virtual bool fakeCtrlAltDel() const; virtual void fakeMouseButton(ButtonID id, bool press) const; virtual void fakeMouseMove(SInt32 x, SInt32 y) const; virtual void fakeMouseWheel(SInt32 delta) const; - virtual KeyButton mapKey(IKeyState::Keystrokes&, - const IKeyState& keyState, KeyID id, - KeyModifierMask desiredMask, - bool isAutoRepeat) const; + + // IPlatformScreen overrides + virtual void enable(); + virtual void disable(); + virtual void enter(); + virtual bool leave(); + virtual bool setClipboard(ClipboardID, const IClipboard*); + virtual void checkClipboards(); + virtual void openScreensaver(bool notify); + virtual void closeScreensaver(); + virtual void screensaver(bool activate); + virtual void resetOptions(); + virtual void setOptions(const COptionsList& options); + virtual void setSequenceNumber(UInt32); + virtual bool isPrimary() const; + +protected: + // IPlatformScreen overrides + virtual void handleSystemEvent(const CEvent&, void*); + virtual void updateButtons(); + virtual IKeyState* getKeyState() const; private: // event sending void sendEvent(CEvent::Type, void* = NULL); void sendClipboardEvent(CEvent::Type, ClipboardID); - // event handling - void handleSystemEvent(const CEvent&, void*); - // create the transparent cursor Cursor createBlankCursor() const; @@ -138,8 +132,6 @@ private: void warpCursorNoFlush(SInt32 x, SInt32 y); - void updateButtons(); - static Bool findKeyEvent(Display*, XEvent* xevent, XPointer arg); private: @@ -162,8 +154,7 @@ private: SInt32 m_xCursor, m_yCursor; // keyboard stuff - IKeyState* m_keyState; - CXWindowsKeyMapper m_keyMapper; + CXWindowsKeyState* m_keyState; // input method stuff XIM m_im; diff --git a/lib/platform/Makefile.am b/lib/platform/Makefile.am index daef7e63..9245adee 100644 --- a/lib/platform/Makefile.am +++ b/lib/platform/Makefile.am @@ -54,7 +54,7 @@ libplatform_a_SOURCES = \ CXWindowsClipboardUCS2Converter.cpp \ CXWindowsClipboardUTF8Converter.cpp \ CXWindowsEventQueueBuffer.cpp \ - CXWindowsKeyMapper.cpp \ + CXWindowsKeyState.cpp \ CXWindowsScreen.cpp \ CXWindowsScreenSaver.cpp \ CXWindowsUtil.cpp \ @@ -63,7 +63,7 @@ libplatform_a_SOURCES = \ CXWindowsClipboardUCS2Converter.h \ CXWindowsClipboardUTF8Converter.h \ CXWindowsEventQueueBuffer.h \ - CXWindowsKeyMapper.h \ + CXWindowsKeyState.h \ CXWindowsScreen.h \ CXWindowsScreenSaver.h \ CXWindowsUtil.h \ diff --git a/lib/server/CPrimaryClient.cpp b/lib/server/CPrimaryClient.cpp index 9da849bd..a8e21c3c 100644 --- a/lib/server/CPrimaryClient.cpp +++ b/lib/server/CPrimaryClient.cpp @@ -105,13 +105,13 @@ CPrimaryClient::disable() void CPrimaryClient::enter(SInt32 xAbs, SInt32 yAbs, - UInt32 seqNum, KeyModifierMask, bool screensaver) + UInt32 seqNum, KeyModifierMask mask, bool screensaver) { m_screen->setSequenceNumber(seqNum); if (!screensaver) { m_screen->warpCursor(xAbs, yAbs); } - m_screen->enter(); + m_screen->enter(mask); } bool diff --git a/lib/synergy/CKeyState.cpp b/lib/synergy/CKeyState.cpp new file mode 100644 index 00000000..9cd80de5 --- /dev/null +++ b/lib/synergy/CKeyState.cpp @@ -0,0 +1,532 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2004 Chris Schoeneman + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file COPYING that should have accompanied this file. + * + * This package 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 + * GNU General Public License for more details. + */ + +#include "CKeyState.h" +#include "IEventQueue.h" +#include "CLog.h" +#include + +// +// CKeyState +// + +CKeyState::CKeyState() : + m_halfDuplex(0), + m_mask(0) +{ + memset(&m_keys, 0, sizeof(m_keys)); + memset(&m_serverKeyMap, 0, sizeof(m_serverKeyMap)); + memset(&m_keyToMask, 0, sizeof(m_keyToMask)); +} + +CKeyState::~CKeyState() +{ + // do nothing +} + +void +CKeyState::setKeyDown(KeyButton button, bool down) +{ + button &= kButtonMask; + if (button != 0) { + if (down) { + m_keys[button] |= kDown; + } + else { + m_keys[button] &= ~kDown; + } + } +} + +void +CKeyState::setToggled(KeyModifierMask modifier) +{ + if (isToggle(modifier)) { + const KeyButtons& buttons = m_maskToKeys[getIndexForModifier(modifier)]; + for (KeyButtons::const_iterator j = buttons.begin(); + j != buttons.end(); ++j) { + m_keys[(*j) & kButtonMask] |= kToggled; + } + } +} + +void +CKeyState::sendKeyEvent( + void* target, bool press, bool isAutoRepeat, + KeyID key, KeyModifierMask mask, + SInt32 count, KeyButton button) +{ + if (isHalfDuplex(m_keyToMask[button])) { + if (isAutoRepeat) { + // ignore auto-repeat on half-duplex keys + } + else { + EVENTQUEUE->addEvent(CEvent(getKeyDownEvent(), target, + CKeyInfo::alloc(key, mask, button, 1))); + EVENTQUEUE->addEvent(CEvent(getKeyUpEvent(), target, + CKeyInfo::alloc(key, mask, button, 1))); + } + } + else { + if (isAutoRepeat) { + EVENTQUEUE->addEvent(CEvent(getKeyRepeatEvent(), target, + CKeyInfo::alloc(key, mask, button, count))); + } + else if (press) { + EVENTQUEUE->addEvent(CEvent(getKeyDownEvent(), target, + CKeyInfo::alloc(key, mask, button, 1))); + } + else { + EVENTQUEUE->addEvent(CEvent(getKeyUpEvent(), target, + CKeyInfo::alloc(key, mask, button, 1))); + } + } +} + +void +CKeyState::updateKeys() +{ + static const KeyModifierMask s_masks[] = { + KeyModifierShift, + KeyModifierControl, + KeyModifierAlt, + KeyModifierMeta, + KeyModifierSuper, + KeyModifierModeSwitch, + KeyModifierCapsLock, + KeyModifierNumLock, + KeyModifierScrollLock + }; + + // reset our state + memset(&m_keys, 0, sizeof(m_keys)); + memset(&m_serverKeyMap, 0, sizeof(m_serverKeyMap)); + memset(&m_keyToMask, 0, sizeof(m_keyToMask)); + for (UInt32 i = 0; i < sizeof(m_maskToKeys)/sizeof(m_maskToKeys[0]); ++i) { + m_maskToKeys[i].clear(); + } + + // let subclass set the state + doUpdateKeys(); + + // figure out the active modifiers + m_mask = 0; + for (UInt32 i = 0; i < sizeof(s_masks) / sizeof(s_masks[0]); ++i) { + if (isModifierActive(s_masks[i])) { + m_mask |= s_masks[i]; + } + } + LOG((CLOG_DEBUG2 "modifiers on update: 0x%04x", m_mask)); +} + +void +CKeyState::setHalfDuplexMask(KeyModifierMask mask) +{ + m_halfDuplex = mask & (KeyModifierCapsLock | + KeyModifierNumLock | + KeyModifierScrollLock); +} + +void +CKeyState::fakeKeyDown(KeyID id, KeyModifierMask mask, KeyButton button) +{ + // get the sequence of keys to simulate key press and the final + // modifier state. + Keystrokes keys; + KeyButton localID = (mapKey(keys, id, mask, false) & kButtonMask); + if (keys.empty()) { + // do nothing if there are no associated keys + LOG((CLOG_DEBUG2 "cannot map key 0x%08x", id)); + return; + } + + // generate key events + fakeKeyEvents(keys, 1); + + // note that key is down + updateKeyState(button & kButtonMask, localID, true); +} + +void +CKeyState::fakeKeyRepeat( + KeyID id, KeyModifierMask mask, + SInt32 count, KeyButton button) +{ + button &= kButtonMask; + + // if we haven't seen this button go down then ignore it + KeyButton oldLocalID = m_serverKeyMap[button]; + if (oldLocalID == 0) { + return; + } + + // get the sequence of keys to simulate key repeat and the final + // modifier state. + Keystrokes keys; + KeyButton localID = (mapKey(keys, id, mask, true) & kButtonMask); + if (localID == 0) { + LOG((CLOG_DEBUG2 "cannot map key 0x%08x", id)); + return; + } + if (keys.empty()) { + // do nothing if there are no associated keys + return; + } + + // if the keycode for the auto-repeat is not the same as for the + // initial press then mark the initial key as released and the new + // key as pressed. this can happen when we auto-repeat after a + // dead key. for example, a dead accent followed by 'a' will + // generate an 'a with accent' followed by a repeating 'a'. the + // keycodes for the two keysyms might be different. + if (localID != oldLocalID) { + // replace key up with previous key id but leave key down + // alone so it uses the new keycode. + for (Keystrokes::iterator index = keys.begin(); + index != keys.end(); ++index) { + if (index->m_key == localID) { + index->m_key = oldLocalID; + break; + } + } + + // note that old key is now up + m_keys[oldLocalID] &= ~kDown; + + // map server key to new key + m_serverKeyMap[button] = localID; + + // note that new key is now down + m_keys[localID] |= kDown; + } + + // generate key events + fakeKeyEvents(keys, count); +} + +void +CKeyState::fakeKeyUp(KeyButton button) +{ + // if we haven't seen this button go down then ignore it + KeyButton localID = m_serverKeyMap[button & kButtonMask]; + if (localID == 0) { + return; + } + + // get the sequence of keys to simulate key release + Keystrokes keys; + Keystroke keystroke; + keystroke.m_key = localID; + keystroke.m_press = false; + keystroke.m_repeat = false; + keys.push_back(keystroke); + + // generate key events + fakeKeyEvents(keys, 1); + + // note that key is now up + updateKeyState(button, localID, false); +} + +void +CKeyState::fakeToggle(KeyModifierMask modifier) +{ + const KeyButtons& buttons = m_maskToKeys[getIndexForModifier(modifier)]; + if (buttons.empty() || !isToggle(modifier)) { + return; + } + KeyButton button = buttons[0]; + + // get the sequence of keys to simulate key toggle + Keystrokes keys; + Keystroke keystroke; + keystroke.m_key = button; + keystroke.m_press = true; + keystroke.m_repeat = false; + keys.push_back(keystroke); + keystroke.m_press = false; + keys.push_back(keystroke); + + // generate key events + fakeKeyEvents(keys, 1); + + // note the toggle + m_keys[button] ^= kToggled; + m_mask ^= modifier; +} + +bool +CKeyState::isKeyDown(KeyButton button) const +{ + return ((m_keys[button & kButtonMask] & kDown) != 0); +} + +KeyModifierMask +CKeyState::getActiveModifiers() const +{ + return m_mask; +} + +void +CKeyState::addModifier(KeyModifierMask modifier, const KeyButtons& buttons) +{ + // the mask must not be zero + assert(modifier != 0); + + // the mask must have exactly one high bit + assert((modifier & (modifier - 1)) == 0); + + for (KeyButtons::const_iterator j = buttons.begin(); + j != buttons.end(); ++j) { + KeyButton button = static_cast(((*j) & kButtonMask)); + if (button != 0) { + m_keyToMask[button] = modifier; + } + } + + // index keys by mask + m_maskToKeys[getIndexForModifier(modifier)] = buttons; +} + +bool +CKeyState::mapModifier(Keystrokes& keys, Keystrokes& undo, + KeyModifierMask mask, bool desireActive) const +{ + // look up modifier + const KeyButtons& buttons = m_maskToKeys[getIndexForModifier(mask)]; + if (buttons.empty()) { + return false; + } + + // ignore if already in desired state + if (isModifierActive(mask) == desireActive) { + return true; + } + + // initialize keystroke + Keystroke keystroke; + keystroke.m_repeat = false; + + // handle toggles + if (isToggle(mask)) { + keystroke.m_key = buttons[0]; + keystroke.m_press = true; + keys.push_back(keystroke); + keystroke.m_press = false; + keys.push_back(keystroke); + keystroke.m_press = false; + undo.push_back(keystroke); + keystroke.m_press = true; + undo.push_back(keystroke); + } + + else if (desireActive) { + // press + keystroke.m_key = buttons[0]; + keystroke.m_press = true; + keys.push_back(keystroke); + keystroke.m_press = false; + undo.push_back(keystroke); + } + + else { + // releasing a modifier is quite different from pressing one. + // when we release a modifier we have to release every keycode that + // is assigned to the modifier since the modifier is active if any + // one of them is down. when we press a modifier we just have to + // press one of those keycodes. + for (KeyButtons::const_iterator j = buttons.begin(); + j != buttons.end(); ++j) { + if (isKeyDown(*j)) { + keystroke.m_key = *j; + keystroke.m_press = false; + keys.push_back(keystroke); + keystroke.m_press = true; + undo.push_back(keystroke); + } + } + } + + return true; +} + +bool +CKeyState::isToggle(KeyModifierMask mask) const +{ + return (mask == KeyModifierCapsLock || + mask == KeyModifierNumLock || + mask == KeyModifierScrollLock); +} + +bool +CKeyState::isHalfDuplex(KeyModifierMask mask) const +{ + return ((mask & m_halfDuplex) != 0); +} + +bool +CKeyState::isModifierActive(KeyModifierMask mask) const +{ + const KeyButtons& buttons = m_maskToKeys[getIndexForModifier(mask)]; + KeyButtons::const_iterator j = buttons.begin(); + if (isToggle(mask)) { + // modifier is a toggle + if ((m_keys[*j] & kToggled) != 0) { + return true; + } + } + else { + // modifier is not a toggle + for (; j != buttons.end(); ++j) { + if ((m_keys[*j] & kDown) != 0) { + return true; + } + } + } + return false; +} + +UInt32 +CKeyState::getIndexForModifier(KeyModifierMask mask) const +{ + switch (mask) { + case KeyModifierShift: + return 0; + + case KeyModifierControl: + return 1; + + case KeyModifierAlt: + return 2; + + case KeyModifierMeta: + return 3; + + case KeyModifierSuper: + return 4; + + case KeyModifierModeSwitch: + return 5; + + case KeyModifierCapsLock: + return 6; + + case KeyModifierNumLock: + return 7; + + case KeyModifierScrollLock: + return 8; + + default: + assert(0 && "invalid modifier mask"); + return 0; + } +} + +void +CKeyState::fakeKeyEvents(const Keystrokes& keys, UInt32 count) +{ + // do nothing if no keys or no repeats + if (count == 0 || keys.empty()) { + return; + } + + // generate key events + LOG((CLOG_DEBUG2 "keystrokes:")); + for (Keystrokes::const_iterator k = keys.begin(); k != keys.end(); ) { + if (k->m_repeat) { + // repeat from here up to but not including the next key + // with m_repeat == false count times. + Keystrokes::const_iterator start = k; + while (count-- > 0) { + // send repeating events + for (k = start; k != keys.end() && k->m_repeat; ++k) { + fakeKeyEvent(k->m_key, k->m_press, true); + } + } + + // note -- k is now on the first non-repeat key after the + // repeat keys, exactly where we'd like to continue from. + } + else { + // send event + fakeKeyEvent(k->m_key, k->m_press, false); + + // next key + ++k; + } + } +} + +void +CKeyState::fakeKeyEvent(KeyButton button, bool press, bool isAutoRepeat) +{ + // half-duplex keys are special. we ignore releases and convert + // a press when the toggle is active to a release. + KeyModifierMask mask = m_keyToMask[button]; + if (isHalfDuplex(mask)) { + if (isAutoRepeat || !press) { + return; + } + if (isModifierActive(mask)) { + press = false; + } + } + + // send key event + LOG((CLOG_DEBUG2 " %d %s%s", button, press ? "down" : "up", isAutoRepeat ? " repeat" : "")); + doFakeKeyEvent(button, press, isAutoRepeat); +} + +void +CKeyState::updateKeyState(KeyButton serverID, KeyButton localID, bool press) +{ + // ignore bogus keys + if (serverID == 0 || localID == 0) { + return; + } + + // update key state. state doesn't change when auto-repeating. + if (press) { + m_serverKeyMap[serverID] = localID; + m_keys[localID] |= kDown; + } + else { + m_serverKeyMap[serverID] = 0; + m_keys[localID] &= ~kDown; + } + + // update modifier state + KeyModifierMask mask = m_keyToMask[localID]; + if (mask != 0) { + if (isToggle(mask)) { + m_keys[localID] ^= kToggled; + m_mask ^= mask; + + // never report half-duplex keys as down + if (isHalfDuplex(mask)) { + m_keys[localID] &= ~kDown; + } + } + else { + if (press) { + m_mask |= mask; + } + else if (!isModifierActive(mask)) { + m_mask &= ~mask; + } + } + LOG((CLOG_DEBUG2 "new mask: 0x%04x", m_mask)); + } +} diff --git a/lib/synergy/CKeyState.h b/lib/synergy/CKeyState.h new file mode 100644 index 00000000..a53cba3f --- /dev/null +++ b/lib/synergy/CKeyState.h @@ -0,0 +1,185 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2004 Chris Schoeneman + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file COPYING that should have accompanied this file. + * + * This package 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 + * GNU General Public License for more details. + */ + +#ifndef CKEYSTATE_H +#define CKEYSTATE_H + +#include "IKeyState.h" +#include "stdvector.h" + +//! Core key state +/*! +This class provides key state services. Subclasses must implement a few +platform specific methods. +*/ +class CKeyState : public IKeyState { +public: + CKeyState(); + virtual ~CKeyState(); + + //! @name manipulators + //@{ + + //! Mark key as being down + /*! + Sets the state of \p button to down or up. + */ + void setKeyDown(KeyButton button, bool down); + + //! Mark modifier as being toggled on + /*! + Sets the state of the keys for the given (single) \p modifier to be + toggled on. + */ + void setToggled(KeyModifierMask modifier); + + //! Post a key event + /*! + Posts a key event. This may adjust the event or post additional + events in some circumstances. + */ + void sendKeyEvent(void* target, + bool press, bool isAutoRepeat, + KeyID key, KeyModifierMask mask, + SInt32 count, KeyButton button); + + //@} + //! @name accessors + //@{ + + //@} + + // IKeyState overrides + virtual void updateKeys(); + virtual void setHalfDuplexMask(KeyModifierMask); + virtual void fakeKeyDown(KeyID id, KeyModifierMask mask, + KeyButton button); + virtual void fakeKeyRepeat(KeyID id, KeyModifierMask mask, + SInt32 count, KeyButton button); + virtual void fakeKeyUp(KeyButton button); + virtual void fakeToggle(KeyModifierMask modifier); + virtual bool isKeyDown(KeyButton) const; + virtual KeyModifierMask + getActiveModifiers() const; + virtual const char* getKeyName(KeyButton) const = 0; + +protected: + class Keystroke { + public: + KeyButton m_key; + bool m_press; + bool m_repeat; + }; + typedef std::vector Keystrokes; + typedef std::vector KeyButtons; + + //! @name protocted manipulators + //@{ + + //! Add keys for modifier + /*! + Sets the buttons that are mapped to the given (single) \p modifier. For + example, if buttons 5 and 23 were mapped to KeyModifierShift (perhaps + as left and right shift keys) then the mask would be KeyModifierShift + and \c buttons would contain 5 and 23. A modifier with no keys is + ignored. Buttons that are zero are ignored. + */ + void addModifier(KeyModifierMask modifier, + const KeyButtons& buttons); + + //! Get key events to change modifier state + /*! + Retrieves the key events necessary to activate (\c desireActive is true) + or deactivate (\c desireActive is false) the modifier given by \c mask + by pushing them onto the back of \c keys. \c mask must specify exactly + one modifier. \c undo receives the key events necessary to restore the + modifier's previous state. They're pushed onto \c undo in the reverse + order they should be executed. Returns true if the modifier can be + adjusted, false otherwise. + */ + bool mapModifier(Keystrokes& keys, Keystrokes& undo, + KeyModifierMask mask, bool desireActive) const; + + //! Update the key state + /*! + Update the key state to reflect the physical keyboard state and + current keyboard mapping. This must call \c setKeyDown, \c setToggled, + and \c addModifier to set the current state. + */ + virtual void doUpdateKeys() = 0; + + //! Fake a key event + /*! + Synthesize a key event for \p button. If \p press is true then + synthesize a key press and, if false, a key release. If + \p isAutoRepeat is true then the event is an auto-repeat. + */ + virtual void doFakeKeyEvent(KeyButton button, + bool press, bool isAutoRepeat) = 0; + + //! Map key press/repeat to keystrokes + /*! + Converts a press/repeat of key \p id with the modifiers as given + in \p desiredMask into the keystrokes necessary to synthesize + that key event. Returns the platform specific code of the key + being pressed, or 0 if the key cannot be mapped or \p isAutoRepeat + is true and the key does not auto-repeat. + */ + virtual KeyButton mapKey(Keystrokes& keys, KeyID id, + KeyModifierMask desiredMask, + bool isAutoRepeat) const = 0; + + //@} + +private: + bool isHalfDuplex(KeyModifierMask) const; + bool isToggle(KeyModifierMask) const; + bool isModifierActive(KeyModifierMask) const; + UInt32 getIndexForModifier(KeyModifierMask) const; + void fakeKeyEvents(const Keystrokes&, UInt32 count); + void fakeKeyEvent(KeyButton, bool press, bool isAutoRepeat); + void updateKeyState(KeyButton serverID, + KeyButton localID, bool press); + +private: + enum { + kNumModifiers = 9, + kButtonMask = kNumButtons - 1 + }; + typedef UInt8 KeyState; + enum EKeyState { + kDown = 0x01, //!< Key is down + kToggled = 0x02 //!< Key is toggled on + }; + + // modifiers that are half-duplex + KeyModifierMask m_halfDuplex; + + // current modifier state + KeyModifierMask m_mask; + + // current keyboard state + KeyState m_keys[kNumButtons]; + + // map from server button ID to local button ID for pressed keys + KeyButton m_serverKeyMap[kNumButtons]; + + // map button to the modifier mask it represents + KeyModifierMask m_keyToMask[kNumButtons]; + + // map modifier to buttons with that modifier + KeyButtons m_maskToKeys[kNumModifiers]; +}; + +#endif diff --git a/lib/synergy/CPlatformScreen.cpp b/lib/synergy/CPlatformScreen.cpp new file mode 100644 index 00000000..95e0fe77 --- /dev/null +++ b/lib/synergy/CPlatformScreen.cpp @@ -0,0 +1,82 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2004 Chris Schoeneman + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file COPYING that should have accompanied this file. + * + * This package 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 + * GNU General Public License for more details. + */ + +#include "CPlatformScreen.h" + +CPlatformScreen::CPlatformScreen() +{ + // do nothing +} + +CPlatformScreen::~CPlatformScreen() +{ + // do nothing +} + +void +CPlatformScreen::updateKeys() +{ + getKeyState()->updateKeys(); + updateButtons(); +} + +void +CPlatformScreen::setHalfDuplexMask(KeyModifierMask mask) +{ + getKeyState()->setHalfDuplexMask(mask); +} + +void +CPlatformScreen::fakeKeyDown(KeyID id, KeyModifierMask mask, + KeyButton button) +{ + getKeyState()->fakeKeyDown(id, mask, button); +} + +void +CPlatformScreen::fakeKeyRepeat(KeyID id, KeyModifierMask mask, + SInt32 count, KeyButton button) +{ + getKeyState()->fakeKeyRepeat(id, mask, count, button); +} + +void +CPlatformScreen::fakeKeyUp(KeyButton button) +{ + getKeyState()->fakeKeyUp(button); +} + +void +CPlatformScreen::fakeToggle(KeyModifierMask modifier) +{ + getKeyState()->fakeToggle(modifier); +} + +bool +CPlatformScreen::isKeyDown(KeyButton button) const +{ + return getKeyState()->isKeyDown(button); +} + +KeyModifierMask +CPlatformScreen::getActiveModifiers() const +{ + return getKeyState()->getActiveModifiers(); +} + +const char* +CPlatformScreen::getKeyName(KeyButton button) const +{ + return getKeyState()->getKeyName(button); +} diff --git a/lib/synergy/CPlatformScreen.h b/lib/synergy/CPlatformScreen.h new file mode 100644 index 00000000..68071fbb --- /dev/null +++ b/lib/synergy/CPlatformScreen.h @@ -0,0 +1,99 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2004 Chris Schoeneman + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file COPYING that should have accompanied this file. + * + * This package 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 + * GNU General Public License for more details. + */ + +#ifndef CPLATFORMSCREEN_H +#define CPLATFORMSCREEN_H + +#include "IPlatformScreen.h" + +//! Base screen implementation +/*! +This screen implementation is the superclass of all other screen +implementations. It implements a handful of methods and requires +subclasses to implement the rest. +*/ +class CPlatformScreen : public IPlatformScreen { +public: + CPlatformScreen(); + virtual ~CPlatformScreen(); + + // IScreen overrides + virtual void* getEventTarget() const = 0; + virtual bool getClipboard(ClipboardID id, IClipboard*) const = 0; + virtual void getShape(SInt32& x, SInt32& y, + SInt32& width, SInt32& height) const = 0; + virtual void getCursorPos(SInt32& x, SInt32& y) const = 0; + + // IPrimaryScreen overrides + virtual void reconfigure(UInt32 activeSides) = 0; + virtual void warpCursor(SInt32 x, SInt32 y) = 0; + virtual SInt32 getJumpZoneSize() const = 0; + virtual bool isAnyMouseButtonDown() const = 0; + virtual void getCursorCenter(SInt32& x, SInt32& y) const = 0; + + // ISecondaryScreen overrides + virtual bool fakeCtrlAltDel() const = 0; + virtual void fakeMouseButton(ButtonID id, bool press) const = 0; + virtual void fakeMouseMove(SInt32 x, SInt32 y) const = 0; + virtual void fakeMouseWheel(SInt32 delta) const = 0; + + // IKeyState overrides + virtual void updateKeys(); + virtual void setHalfDuplexMask(KeyModifierMask); + virtual void fakeKeyDown(KeyID id, KeyModifierMask mask, + KeyButton button); + virtual void fakeKeyRepeat(KeyID id, KeyModifierMask mask, + SInt32 count, KeyButton button); + virtual void fakeKeyUp(KeyButton button); + virtual void fakeToggle(KeyModifierMask modifier); + virtual bool isKeyDown(KeyButton) const; + virtual KeyModifierMask + getActiveModifiers() const; + virtual const char* getKeyName(KeyButton) const; + + // IPlatformScreen overrides + virtual void enable() = 0; + virtual void disable() = 0; + virtual void enter() = 0; + virtual bool leave() = 0; + virtual bool setClipboard(ClipboardID, const IClipboard*) = 0; + virtual void checkClipboards() = 0; + virtual void openScreensaver(bool notify) = 0; + virtual void closeScreensaver() = 0; + virtual void screensaver(bool activate) = 0; + virtual void resetOptions() = 0; + virtual void setOptions(const COptionsList& options) = 0; + virtual void setSequenceNumber(UInt32) = 0; + virtual bool isPrimary() const = 0; + +protected: + //! Update mouse buttons + /*! + Subclasses must implement this method to update their internal mouse + button mapping and, if desired, state tracking. + */ + virtual void updateButtons() = 0; + + //! Get the key state + /*! + Subclasses must implement this method to return the platform specific + key state object that each subclass must have. + */ + virtual IKeyState* getKeyState() const = 0; + + // IPlatformScreen overrides + virtual void handleSystemEvent(const CEvent& event, void*) = 0; +}; + +#endif diff --git a/lib/synergy/CScreen.cpp b/lib/synergy/CScreen.cpp index ada14d8f..9c4594da 100644 --- a/lib/synergy/CScreen.cpp +++ b/lib/synergy/CScreen.cpp @@ -32,9 +32,6 @@ CScreen::CScreen(IPlatformScreen* platformScreen) : { assert(m_screen != NULL); - // open screen - m_screen->setKeyState(this); - // reset options resetOptions(); @@ -78,7 +75,7 @@ CScreen::disable() leave(); } else if (m_isPrimary && !m_entered) { - enter(); + enter(0); } m_screen->disable(); if (m_isPrimary) { @@ -93,7 +90,7 @@ CScreen::disable() } void -CScreen::enter() +CScreen::enter(KeyModifierMask toggleMask) { assert(m_entered == false); LOG((CLOG_INFO "entering screen")); @@ -105,7 +102,7 @@ CScreen::enter() enterPrimary(); } else { - enterSecondary(); + enterSecondary(toggleMask); } m_screen->enter(); } @@ -186,22 +183,7 @@ CScreen::keyDown(KeyID id, KeyModifierMask mask, KeyButton button) return; } } - - // get the sequence of keys to simulate key press and the final - // modifier state. - Keystrokes keys; - KeyButton key = m_screen->mapKey(keys, *this, id, mask, false); - if (keys.empty()) { - // do nothing if there are no associated keys - LOG((CLOG_DEBUG2 "cannot map key 0x%08x", id)); - return; - } - - // generate key events - doKeystrokes(keys, 1); - - // note that key is down - updateKeyState(button, key, true); + m_screen->fakeKeyDown(id, mask, button); } void @@ -209,86 +191,14 @@ CScreen::keyRepeat(KeyID id, KeyModifierMask mask, SInt32 count, KeyButton button) { assert(!m_isPrimary); - - // if we haven't seen this button go down then ignore it - ServerKeyMap::iterator index = m_serverKeyMap.find(button); - if (index == m_serverKeyMap.end()) { - return; - } - - // get the sequence of keys to simulate key repeat and the final - // modifier state. - Keystrokes keys; - KeyButton key = m_screen->mapKey(keys, *this, id, mask, true); - if (key == 0) { - LOG((CLOG_DEBUG2 "cannot map key 0x%08x", id)); - return; - } - if (keys.empty()) { - // do nothing if there are no associated keys - return; - } - - // if the keycode for the auto-repeat is not the same as for the - // initial press then mark the initial key as released and the new - // key as pressed. this can happen when we auto-repeat after a - // dead key. for example, a dead accent followed by 'a' will - // generate an 'a with accent' followed by a repeating 'a'. the - // keycodes for the two keysyms might be different. - key &= 0x1ffu; - if (key != index->second) { - // replace key up with previous key id but leave key down - // alone so it uses the new keycode and store that keycode - // in the server key map. - for (Keystrokes::iterator index2 = keys.begin(); - index2 != keys.end(); ++index2) { - if ((index2->m_key & 0x1ffu) == key) { - index2->m_key = index->second; - break; - } - } - - // note that old key is now up - m_keys[index->second] &= ~kDown; - m_fakeKeys[index->second] &= ~kDown; - - // map server key to new key - index->second = key; - - // note that new key is now down - m_keys[index->second] |= kDown; - m_fakeKeys[index->second] |= kDown; - } - - // generate key events - doKeystrokes(keys, count); + m_screen->fakeKeyRepeat(id, mask, count, button); } void CScreen::keyUp(KeyID, KeyModifierMask, KeyButton button) { assert(!m_isPrimary); - - // if we haven't seen this button go down then ignore it - ServerKeyMap::iterator index = m_serverKeyMap.find(button); - if (index == m_serverKeyMap.end()) { - return; - } - KeyButton key = index->second; - - // get the sequence of keys to simulate key release - Keystrokes keys; - Keystroke keystroke; - keystroke.m_key = key; - keystroke.m_press = false; - keystroke.m_repeat = false; - keys.push_back(keystroke); - - // generate key events - doKeystrokes(keys, 1); - - // note that key is now up - updateKeyState(button, key, false); + m_screen->fakeKeyUp(button); } void @@ -323,8 +233,7 @@ void CScreen::resetOptions() { // reset options - m_numLockHalfDuplex = false; - m_capsLockHalfDuplex = false; + m_halfDuplex = 0; // if screen saver synchronization was off then turn it on since // that's the default option state. @@ -350,12 +259,24 @@ CScreen::setOptions(const COptionsList& options) LOG((CLOG_DEBUG1 "screen saver synchronization %s", m_screenSaverSync ? "on" : "off")); } else if (options[i] == kOptionHalfDuplexCapsLock) { - m_capsLockHalfDuplex = (options[i + 1] != 0); - LOG((CLOG_DEBUG1 "half-duplex caps-lock %s", m_capsLockHalfDuplex ? "on" : "off")); + if (options[i + 1] != 0) { + m_halfDuplex |= KeyModifierCapsLock; + } + else { + m_halfDuplex &= ~KeyModifierCapsLock; + } + m_screen->setHalfDuplexMask(m_halfDuplex); + LOG((CLOG_DEBUG1 "half-duplex caps-lock %s", ((m_halfDuplex & KeyModifierCapsLock) != 0) ? "on" : "off")); } else if (options[i] == kOptionHalfDuplexNumLock) { - m_numLockHalfDuplex = (options[i + 1] != 0); - LOG((CLOG_DEBUG1 "half-duplex num-lock %s", m_numLockHalfDuplex ? "on" : "off")); + if (options[i + 1] != 0) { + m_halfDuplex |= KeyModifierNumLock; + } + else { + m_halfDuplex &= ~KeyModifierNumLock; + } + m_screen->setHalfDuplexMask(m_halfDuplex); + LOG((CLOG_DEBUG1 "half-duplex num-lock %s", ((m_halfDuplex & KeyModifierNumLock) != 0) ? "on" : "off")); } } @@ -401,7 +322,7 @@ CScreen::isLockedToScreen() const // be necessary but we don't seem to get some key release // events sometimes. this is an emergency backup so the // client doesn't get stuck on the screen. - const_cast(this)->updateKeys(); + m_screen->updateKeys(); KeyButton key2 = isAnyKeyDown(); if (key2 != 0) { LOG((CLOG_DEBUG "locked by %s", m_screen->getKeyName(key2))); @@ -433,6 +354,12 @@ CScreen::getCursorCenter(SInt32& x, SInt32& y) const m_screen->getCursorCenter(x, y); } +KeyModifierMask +CScreen::getActiveModifiers() const +{ + return m_screen->getActiveModifiers(); +} + void* CScreen::getEventTarget() const { @@ -457,253 +384,6 @@ CScreen::getCursorPos(SInt32& x, SInt32& y) const m_screen->getCursorPos(x, y); } -void -CScreen::updateKeys() -{ - // clear key state - memset(m_keys, 0, sizeof(m_keys)); - memset(m_fakeKeys, 0, sizeof(m_fakeKeys)); - m_maskToKeys.clear(); - m_keyToMask.clear(); - - // let subclass set m_keys - m_screen->updateKeys(); - - // figure out active modifier mask - m_mask = getModifierMask(); - LOG((CLOG_DEBUG2 "modifiers on update: 0x%04x", m_mask)); -} - -void -CScreen::releaseKeys() -{ - // release keys that we've synthesized a press for and only those - // keys. we don't want to synthesize a release on a key the user - // is still physically pressing. - for (KeyButton i = 1; i < sizeof(m_keys) / sizeof(m_keys[0]); ++i) { - if ((m_fakeKeys[i] & kDown) != 0) { - fakeKeyEvent(i, false, false); - m_keys[i] &= ~kDown; - m_fakeKeys[i] &= ~kDown; - } - } -} - -void -CScreen::setKeyDown(KeyButton key, bool down) -{ - if (!isHalfDuplex(getMaskForKey(key))) { - if (down) { - m_keys[key & 0x1ffu] |= kDown; - } - else { - m_keys[key & 0x1ffu] &= ~kDown; - } - } -} - -void -CScreen::setToggled(KeyModifierMask mask) -{ - if (!isToggle(mask)) { - return; - } - MaskToKeys::const_iterator i = m_maskToKeys.find(mask); - if (i == m_maskToKeys.end()) { - return; - } - for (KeyButtons::const_iterator j = i->second.begin(); - j != i->second.end(); ++j) { - m_keys[(*j) & 0x1ffu] |= kToggled; - } -} - -void -CScreen::addModifier(KeyModifierMask mask, KeyButtons& keys) -{ - // the modifier must have associated keys - if (keys.empty()) { - return; - } - - // the mask must not be zero - assert(mask != 0); - - // the mask must have exactly one high bit - assert((mask & (mask - 1)) == 0); - - // index mask by keycodes - for (KeyButtons::iterator j = keys.begin(); j != keys.end(); ++j) { - // key must be valid - if (((*j) & 0x1ffu) != 0) { - m_keyToMask[static_cast((*j) & 0x1ffu)] = mask; - } - } - - // index keys by mask - m_maskToKeys[mask].swap(keys); -} - -void -CScreen::setToggleState(KeyModifierMask mask) -{ - // toggle modifiers that don't match the desired state - KeyModifierMask different = (m_mask ^ mask); - if ((different & KeyModifierCapsLock) != 0) { - toggleKey(KeyModifierCapsLock); - } - if ((different & KeyModifierNumLock) != 0) { - toggleKey(KeyModifierNumLock); - } - if ((different & KeyModifierScrollLock) != 0) { - toggleKey(KeyModifierScrollLock); - } -} - -KeyButton -CScreen::isAnyKeyDown() const -{ - for (UInt32 i = 1; i < sizeof(m_keys) / sizeof(m_keys[0]); ++i) { - if ((m_keys[i] & kDown) != 0) { - return static_cast(i); - } - } - return 0; -} - -bool -CScreen::isKeyDown(KeyButton key) const -{ - key &= 0x1ffu; - return (key != 0 && ((m_keys[key] & kDown) != 0)); -} - -bool -CScreen::isToggle(KeyModifierMask mask) const -{ - static const KeyModifierMask s_toggleMask = - KeyModifierCapsLock | KeyModifierNumLock | KeyModifierScrollLock; - return ((mask & s_toggleMask) != 0); -} - -bool -CScreen::isHalfDuplex(KeyModifierMask mask) const -{ - return ((mask == KeyModifierCapsLock && m_capsLockHalfDuplex) || - (mask == KeyModifierNumLock && m_numLockHalfDuplex)); -} - -bool -CScreen::isModifierActive(KeyModifierMask mask) const -{ - MaskToKeys::const_iterator i = m_maskToKeys.find(mask); - if (i == m_maskToKeys.end()) { - return false; - } - - KeyButtons::const_iterator j = i->second.begin(); - if (isToggle(mask)) { - // modifier is a toggle - if (isKeyToggled(*j)) { - return true; - } - } - else { - // modifier is not a toggle - for (; j != i->second.end(); ++j) { - if (isKeyDown(*j)) { - return true; - } - } - } - return false; -} - -KeyModifierMask -CScreen::getActiveModifiers() const -{ - if (m_isPrimary) { - return m_screen->getActiveModifiers(); - } - else { - return m_mask; - } -} - -bool -CScreen::mapModifier(Keystrokes& keys, Keystrokes& undo, - KeyModifierMask mask, bool desireActive) const -{ - // look up modifier - MaskToKeys::const_iterator i = m_maskToKeys.find(mask); - if (i == m_maskToKeys.end()) { - return false; - } - - // ignore if already in desired state - if (isModifierActive(mask) == desireActive) { - return true; - } - - // initialize keystroke - Keystroke keystroke; - keystroke.m_repeat = false; - - // handle toggles - if (isToggle(mask)) { - keystroke.m_key = i->second.front(); - keystroke.m_press = true; - keys.push_back(keystroke); - keystroke.m_press = false; - keys.push_back(keystroke); - keystroke.m_press = false; - undo.push_back(keystroke); - keystroke.m_press = true; - undo.push_back(keystroke); - } - - else if (desireActive) { - // press - keystroke.m_key = i->second.front(); - keystroke.m_press = true; - keys.push_back(keystroke); - keystroke.m_press = false; - undo.push_back(keystroke); - } - - else { - // releasing a modifier is quite different from pressing one. - // when we release a modifier we have to release every keycode that - // is assigned to the modifier since the modifier is active if any - // one of them is down. when we press a modifier we just have to - // press one of those keycodes. - for (KeyButtons::const_iterator j = i->second.begin(); - j != i->second.end(); ++j) { - if (isKeyDown(*j)) { - keystroke.m_key = *j; - keystroke.m_press = false; - keys.push_back(keystroke); - keystroke.m_press = true; - undo.push_back(keystroke); - } - } - } - - return true; -} - -KeyModifierMask -CScreen::getMaskForKey(KeyButton key) const -{ - KeyToMask::const_iterator i = m_keyToMask.find(key); - if (i == m_keyToMask.end()) { - return 0; - } - else { - return i->second; - } -} - void CScreen::enablePrimary() { @@ -749,13 +429,16 @@ CScreen::enterPrimary() } void -CScreen::enterSecondary() +CScreen::enterSecondary(KeyModifierMask toggleMask) { // update our keyboard state to reflect the local state - updateKeys(); + m_screen->updateKeys(); // remember toggle key state. we'll restore this when we leave. - m_toggleKeys = m_mask; + m_toggleKeys = getActiveModifiers(); + + // restore toggle key state + setToggleState(toggleMask); } void @@ -774,170 +457,42 @@ CScreen::leaveSecondary() setToggleState(m_toggleKeys); } -KeyModifierMask -CScreen::getModifierMask() const -{ - KeyModifierMask mask = 0; - if (isModifierActive(KeyModifierShift)) { - mask |= KeyModifierShift; - } - if (isModifierActive(KeyModifierControl)) { - mask |= KeyModifierControl; - } - if (isModifierActive(KeyModifierAlt)) { - mask |= KeyModifierAlt; - } - if (isModifierActive(KeyModifierMeta)) { - mask |= KeyModifierMeta; - } - if (isModifierActive(KeyModifierSuper)) { - mask |= KeyModifierSuper; - } - if (isModifierActive(KeyModifierModeSwitch)) { - mask |= KeyModifierModeSwitch; - } - if (isModifierActive(KeyModifierNumLock)) { - mask |= KeyModifierNumLock; - } - if (isModifierActive(KeyModifierCapsLock)) { - mask |= KeyModifierCapsLock; - } - if (isModifierActive(KeyModifierScrollLock)) { - mask |= KeyModifierScrollLock; - } - return mask; -} - void -CScreen::doKeystrokes(const Keystrokes& keys, SInt32 count) +CScreen::releaseKeys() { - // do nothing if no keys or no repeats - if (count < 1 || keys.empty()) { - return; - } - - // generate key events - LOG((CLOG_DEBUG2 "keystrokes:")); - for (Keystrokes::const_iterator k = keys.begin(); k != keys.end(); ) { - if (k->m_repeat) { - // repeat from here up to but not including the next key - // with m_repeat == false count times. - Keystrokes::const_iterator start = k; - for (; count > 0; --count) { - // send repeating events - for (k = start; k != keys.end() && k->m_repeat; ++k) { - fakeKeyEvent(k->m_key, k->m_press, true); - } - } - - // note -- k is now on the first non-repeat key after the - // repeat keys, exactly where we'd like to continue from. - } - else { - // send event - fakeKeyEvent(k->m_key, k->m_press, false); - - // next key - ++k; + // release keys that we've synthesized a press for and only those + // keys. we don't want to synthesize a release on a key the user + // is still physically pressing. + for (KeyButton i = 1; i < IKeyState::kNumButtons; ++i) { + if (m_screen->isKeyDown(i)) { + m_screen->fakeKeyUp(i); } } } void -CScreen::fakeKeyEvent(KeyButton key, bool press, bool repeat) const +CScreen::setToggleState(KeyModifierMask mask) { - // half-duplex keys are special. we ignore releases and convert - // a press when the toggle is active to a release. - KeyModifierMask mask = getMaskForKey(key); - if (isHalfDuplex(mask)) { - if (repeat || !press) { - return; - } - if (isModifierActive(mask)) { - press = false; - } + // toggle modifiers that don't match the desired state + KeyModifierMask different = (m_screen->getActiveModifiers() ^ mask); + if ((different & KeyModifierCapsLock) != 0) { + m_screen->fakeToggle(KeyModifierCapsLock); } - - // send key event - LOG((CLOG_DEBUG2 " %d %s%s", key, press ? "down" : "up", repeat ? " repeat" : "")); - m_screen->fakeKeyEvent(key, press); -} - -void -CScreen::updateKeyState(KeyButton button, KeyButton key, bool press) -{ - // ignore bogus keys - key &= 0x1ffu; - if (button == 0 || key == 0) { - return; + if ((different & KeyModifierNumLock) != 0) { + m_screen->fakeToggle(KeyModifierNumLock); } - - // update shadow state. shadow state doesn't change on auto-repeat. - if (press) { - // key is now down - m_serverKeyMap[button] = key; - m_keys[key] |= kDown; - m_fakeKeys[key] |= kDown; - } - else { - // key is now up - m_serverKeyMap.erase(button); - m_keys[key] &= ~kDown; - m_fakeKeys[key] &= ~kDown; - } - KeyModifierMask mask = getMaskForKey(key); - if (mask != 0) { - // key is a modifier - if (isToggle(mask)) { - // key is a toggle modifier - if (press) { - m_keys[key] ^= kToggled; - m_mask ^= mask; - - // if key is half duplex then don't report it as down - if (isHalfDuplex(mask)) { - m_keys[key] &= ~kDown; - m_fakeKeys[key] &= ~kDown; - } - } - } - else { - // key is a normal modifier - if (press) { - m_mask |= mask; - } - else if (!isModifierActive(mask)) { - // no key for modifier is down anymore - m_mask &= ~mask; - } - } - LOG((CLOG_DEBUG2 "new mask: 0x%04x", m_mask)); + if ((different & KeyModifierScrollLock) != 0) { + m_screen->fakeToggle(KeyModifierScrollLock); } } -void -CScreen::toggleKey(KeyModifierMask mask) +KeyButton +CScreen::isAnyKeyDown() const { - // get the system key ID for this toggle key ID - MaskToKeys::const_iterator i = m_maskToKeys.find(mask); - if (i == m_maskToKeys.end()) { - return; + for (KeyButton i = 1; i < IKeyState::kNumButtons; ++i) { + if (m_screen->isKeyDown(i)) { + return i; + } } - KeyButton key = i->second.front(); - - // toggle the key - fakeKeyEvent(key, true, false); - fakeKeyEvent(key, false, false); - - // toggle shadow state - m_mask ^= mask; - key &= 0x1ffu; - m_keys[key] ^= kToggled; -} - -bool -CScreen::isKeyToggled(KeyButton key) const -{ - key &= 0x1ffu; - return (key != 0 && ((m_keys[key] & kToggled) != 0)); + return 0; } diff --git a/lib/synergy/CScreen.h b/lib/synergy/CScreen.h index ce2e43d3..ae605d9b 100644 --- a/lib/synergy/CScreen.h +++ b/lib/synergy/CScreen.h @@ -15,12 +15,11 @@ #ifndef CSCREEN_H #define CSCREEN_H -#include "IKeyState.h" #include "IScreen.h" #include "ClipboardTypes.h" +#include "KeyTypes.h" #include "MouseTypes.h" #include "OptionTypes.h" -#include "stdmap.h" class IClipboard; class IPlatformScreen; @@ -30,7 +29,7 @@ class IPlatformScreen; This is a platform independent screen. It can work as either a primary or secondary screen. */ -class CScreen : public IScreen, public IKeyState { +class CScreen : public IScreen { public: CScreen(IPlatformScreen* platformScreen); virtual ~CScreen(); @@ -55,9 +54,10 @@ public: //! Enter screen /*! - Called when the user navigates to this screen. + Called when the user navigates to this screen. \p toggleMask has the + toggle keys that should be turned on on the secondary screen. */ - void enter(); + void enter(KeyModifierMask toggleMask); //! Leave screen /*! @@ -208,6 +208,12 @@ public: */ void getCursorCenter(SInt32& x, SInt32& y) const; + //! Get the active modifiers + /*! + Returns the modifiers that are currently active. + */ + KeyModifierMask getActiveModifiers() const; + //@} // IScreen overrides @@ -217,25 +223,6 @@ public: SInt32& width, SInt32& height) const; virtual void getCursorPos(SInt32& x, SInt32& y) const; - // IKeyState overrides - virtual void updateKeys(); - virtual void releaseKeys(); - virtual void setKeyDown(KeyButton key, bool); - virtual void setToggled(KeyModifierMask); - virtual void addModifier(KeyModifierMask, KeyButtons&); - virtual void setToggleState(KeyModifierMask); - virtual KeyButton isAnyKeyDown() const; - virtual bool isKeyDown(KeyButton) const; - virtual bool isToggle(KeyModifierMask) const; - virtual bool isHalfDuplex(KeyModifierMask) const; - virtual bool isModifierActive(KeyModifierMask) const; - virtual KeyModifierMask - getActiveModifiers() const; - virtual bool mapModifier(Keystrokes& keys, Keystrokes& undo, - KeyModifierMask mask, bool desireActive) const; - virtual KeyModifierMask - getMaskForKey(KeyButton) const; - protected: void enablePrimary(); void enableSecondary(); @@ -243,35 +230,16 @@ protected: void disableSecondary(); void enterPrimary(); - void enterSecondary(); + void enterSecondary(KeyModifierMask toggleMask); void leavePrimary(); void leaveSecondary(); private: - // Get the modifier mask for the current key state - KeyModifierMask getModifierMask() const; - - // Send fake keystrokes - void doKeystrokes(const Keystrokes&, SInt32 count); - - // Send a fake key event - void fakeKeyEvent(KeyButton, bool press, bool repeat) const; - - // Update the shadow state for a key - void updateKeyState(KeyButton button, - KeyButton key, bool press); - - // Toggle a modifier - void toggleKey(KeyModifierMask); - - // Test if a modifier is toggled - bool isKeyToggled(KeyButton) const; + void releaseKeys(); + void setToggleState(KeyModifierMask); + KeyButton isAnyKeyDown() const; private: - typedef std::map ServerKeyMap; - typedef std::map MaskToKeys; - typedef std::map KeyToMask; - // our platform dependent screen IPlatformScreen* m_screen; @@ -289,26 +257,7 @@ private: // note toggle keys that toggles on up/down (false) or on // transition (true) - bool m_numLockHalfDuplex; - bool m_capsLockHalfDuplex; - - // keyboard state - - // map server key buttons to local system keys - ServerKeyMap m_serverKeyMap; - - // system key states as set by us or the user - KeyState m_keys[512]; - - // system key states as set by us - KeyState m_fakeKeys[512]; - - // modifier info - MaskToKeys m_maskToKeys; - KeyToMask m_keyToMask; - - // current active modifiers - KeyModifierMask m_mask; + KeyModifierMask m_halfDuplex; // the toggle key state when this screen was last entered KeyModifierMask m_toggleKeys; diff --git a/lib/synergy/IKeyState.cpp b/lib/synergy/IKeyState.cpp new file mode 100644 index 00000000..bcc1ea2a --- /dev/null +++ b/lib/synergy/IKeyState.cpp @@ -0,0 +1,61 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2004 Chris Schoeneman + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file COPYING that should have accompanied this file. + * + * This package 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 + * GNU General Public License for more details. + */ + +#include "IKeyState.h" + +// +// IKeyState +// + +CEvent::Type IKeyState::s_keyDownEvent = CEvent::kUnknown; +CEvent::Type IKeyState::s_keyUpEvent = CEvent::kUnknown; +CEvent::Type IKeyState::s_keyRepeatEvent = CEvent::kUnknown; + +CEvent::Type +IKeyState::getKeyDownEvent() +{ + return CEvent::registerTypeOnce(s_keyDownEvent, + "IKeyState::keyDown"); +} + +CEvent::Type +IKeyState::getKeyUpEvent() +{ + return CEvent::registerTypeOnce(s_keyUpEvent, + "IKeyState::keyUp"); +} + +CEvent::Type +IKeyState::getKeyRepeatEvent() +{ + return CEvent::registerTypeOnce(s_keyRepeatEvent, + "IKeyState::keyRepeat"); +} + + +// +// IKeyState::CKeyInfo +// + +IKeyState::CKeyInfo* +IKeyState::CKeyInfo::alloc(KeyID id, + KeyModifierMask mask, KeyButton button, SInt32 count) +{ + CKeyInfo* info = (CKeyInfo*)malloc(sizeof(CKeyInfo)); + info->m_key = id; + info->m_mask = mask; + info->m_button = button; + info->m_count = count; + return info; +} diff --git a/lib/synergy/IKeyState.h b/lib/synergy/IKeyState.h index d54d29f1..7d0b8f63 100644 --- a/lib/synergy/IKeyState.h +++ b/lib/synergy/IKeyState.h @@ -17,20 +17,30 @@ #include "IInterface.h" #include "KeyTypes.h" -#include "CString.h" -#include "stdvector.h" +#include "CEvent.h" +//! Key state interface +/*! +This interface provides access to set and query the keyboard state and +to synthesize key events. +*/ class IKeyState : public IInterface { public: - class Keystroke { - public: - KeyButton m_key; - bool m_press; - bool m_repeat; + enum { + kNumButtons = 0x200 }; - typedef std::vector Keystrokes; - typedef std::vector KeyButtons; + //! Key event data + class CKeyInfo { + public: + static CKeyInfo* alloc(KeyID, KeyModifierMask, KeyButton, SInt32 count); + + public: + KeyID m_key; + KeyModifierMask m_mask; + KeyButton m_button; + SInt32 m_count; + }; //! @name manipulators //@{ @@ -42,79 +52,52 @@ public: */ virtual void updateKeys() = 0; - //! Release fake pressed keys + //! Set half-duplex mask /*! - Send fake key events to release keys that aren't physically pressed - but are logically pressed. + Sets which modifier toggle keys are half-duplex. A half-duplex + toggle key doesn't report a key release when toggled on and + doesn't report a key press when toggled off. */ - virtual void releaseKeys() = 0; + virtual void setHalfDuplexMask(KeyModifierMask) = 0; - //! Mark key as being down + //! Fake a key press /*! - Sets the state of \c key to down or up. + Synthesizes a key press event and updates the key state. */ - virtual void setKeyDown(KeyButton key, bool down) = 0; + virtual void fakeKeyDown(KeyID id, KeyModifierMask mask, + KeyButton button) = 0; - //! Mark modifier as being toggled on + //! Fake a key repeat /*! - Sets the state of the keys for the given (single) modifier to be - toggled on. + Synthesizes a key repeat event and updates the key state. */ - virtual void setToggled(KeyModifierMask) = 0; + virtual void fakeKeyRepeat(KeyID id, KeyModifierMask mask, + SInt32 count, KeyButton button) = 0; - //! Add keys for modifier + //! Fake a key release /*! - Sets the keys that are mapped to the given (single) modifier. For - example, if buttons 5 and 23 were mapped to KeyModifierShift (perhaps - as left and right shift keys) then the mask would be KeyModifierShift - and \c keys would contain 5 and 23. A modifier with no keys is - ignored. Keys that are zero are ignored. \c keys may be modified - by the call. + Synthesizes a key release event and updates the key state. */ - virtual void addModifier(KeyModifierMask, KeyButtons& keys) = 0; + virtual void fakeKeyUp(KeyButton button) = 0; - //! Set toggle key state + //! Fake a modifier toggle /*! - Update the local toggle key state to match the given state. + Synthesizes key press/release events to toggle the given \p modifier + and updates the key state. */ - virtual void setToggleState(KeyModifierMask) = 0; + virtual void fakeToggle(KeyModifierMask modifier) = 0; //@} //! @name accessors //@{ - //! Test if any key is down - /*! - If any key is down then returns one of those keys. Otherwise returns 0. - */ - virtual KeyButton isAnyKeyDown() const = 0; - //! Test if key is pressed /*! Returns true iff the given key is down. Half-duplex toggles - should always return false. + always return false. */ virtual bool isKeyDown(KeyButton) const = 0; - //! Test if modifier is a toggle - /*! - Returns true iff the given (single) modifier is a toggle. - */ - virtual bool isToggle(KeyModifierMask) const = 0; - - //! Test if modifier is half-duplex - /*! - Returns true iff the given (single) modifier is a half-duplex - toggle key. - */ - virtual bool isHalfDuplex(KeyModifierMask) const = 0; - - //! Test if modifier is active - /*! - Returns true iff the given (single) modifier is currently active. - */ - virtual bool isModifierActive(KeyModifierMask) const = 0; - //! Get the active modifiers /*! Returns the modifiers that are currently active. @@ -122,35 +105,25 @@ public: virtual KeyModifierMask getActiveModifiers() const = 0; - //! Get key events to change modifier state + //! Get name of key /*! - Retrieves the key events necessary to activate (\c desireActive is true) - or deactivate (\c desireActive is false) the modifier given by \c mask - by pushing them onto the back of \c keys. \c mask must specify exactly - one modifier. \c undo receives the key events necessary to restore the - modifier's previous state. They're pushed onto \c undo in the reverse - order they should be executed. Returns true if the modifier can be - adjusted, false otherwise. + Return a string describing the given key. */ - virtual bool mapModifier(Keystrokes& keys, Keystrokes& undo, - KeyModifierMask mask, bool desireActive) const = 0; + virtual const char* getKeyName(KeyButton) const = 0; - //! Get modifier mask for key - /*! - Returns the modifier mask for \c key. If \c key is not a modifier - key then returns 0. - */ - virtual KeyModifierMask - getMaskForKey(KeyButton) const = 0; + //! Get key down event type. Event data is CKeyInfo*, count == 1. + static CEvent::Type getKeyDownEvent(); + //! Get key up event type. Event data is CKeyInfo*, count == 1. + static CEvent::Type getKeyUpEvent(); + //! Get key repeat event type. Event data is CKeyInfo*. + static CEvent::Type getKeyRepeatEvent(); //@} -protected: - typedef UInt8 KeyState; - enum EKeyState { - kDown = 0x01, //!< Key is down - kToggled = 0x80 //!< Key is toggled on - }; +private: + static CEvent::Type s_keyDownEvent; + static CEvent::Type s_keyUpEvent; + static CEvent::Type s_keyRepeatEvent; }; #endif diff --git a/lib/synergy/IPlatformScreen.h b/lib/synergy/IPlatformScreen.h index 379ef03d..b97f3453 100644 --- a/lib/synergy/IPlatformScreen.h +++ b/lib/synergy/IPlatformScreen.h @@ -18,11 +18,11 @@ #include "IScreen.h" #include "IPrimaryScreen.h" #include "ISecondaryScreen.h" +#include "IKeyState.h" #include "ClipboardTypes.h" #include "OptionTypes.h" class IClipboard; -class IKeyState; //! Screen interface /*! @@ -31,18 +31,12 @@ screen implementations that are used by both primary and secondary screens. */ class IPlatformScreen : public IScreen, - public IPrimaryScreen, public ISecondaryScreen { + public IPrimaryScreen, public ISecondaryScreen, + public IKeyState { public: //! @name manipulators //@{ - //! Set the key state - /*! - Sets the key state object. This object tracks keyboard state and - the screen is expected to keep it up to date. - */ - virtual void setKeyState(IKeyState*) = 0; - //! Enable screen /*! Enable the screen, preparing it to report system and user events. @@ -124,13 +118,6 @@ public: */ virtual void setOptions(const COptionsList& options) = 0; - //! Get keyboard state - /*! - Put the current keyboard state into the IKeyState passed to - \c setKeyState(). - */ - virtual void updateKeys() = 0; - //! Set clipboard sequence number /*! Sets the sequence number to use in subsequent clipboard events. @@ -161,20 +148,27 @@ public: virtual void warpCursor(SInt32 x, SInt32 y) = 0; virtual SInt32 getJumpZoneSize() const = 0; virtual bool isAnyMouseButtonDown() const = 0; - virtual KeyModifierMask getActiveModifiers() const = 0; virtual void getCursorCenter(SInt32& x, SInt32& y) const = 0; - virtual const char* getKeyName(KeyButton) const = 0; // ISecondaryScreen overrides - virtual void fakeKeyEvent(KeyButton id, bool press) const = 0; virtual bool fakeCtrlAltDel() const = 0; virtual void fakeMouseButton(ButtonID id, bool press) const = 0; virtual void fakeMouseMove(SInt32 x, SInt32 y) const = 0; virtual void fakeMouseWheel(SInt32 delta) const = 0; - virtual KeyButton mapKey(IKeyState::Keystrokes&, - const IKeyState& keyState, KeyID id, - KeyModifierMask desiredMask, - bool isAutoRepeat) const = 0; + + // IKeyState overrides + virtual void updateKeys() = 0; + virtual void setHalfDuplexMask(KeyModifierMask) = 0; + virtual void fakeKeyDown(KeyID id, KeyModifierMask mask, + KeyButton button) = 0; + virtual void fakeKeyRepeat(KeyID id, KeyModifierMask mask, + SInt32 count, KeyButton button) = 0; + virtual void fakeKeyUp(KeyButton button) = 0; + virtual void fakeToggle(KeyModifierMask modifier) = 0; + virtual bool isKeyDown(KeyButton) const = 0; + virtual KeyModifierMask + getActiveModifiers() const = 0; + virtual const char* getKeyName(KeyButton) const = 0; protected: //! Handle system event @@ -193,10 +187,10 @@ protected: A primary screen has further responsibilities. It should post the events in \c IPrimaryScreen as appropriate. It should also - call \c setKeyDown() on the \c IKeyState passed to \c setKeyState() - whenever a key is pressed or released (but not for key repeats). - And it should call \c updateKeys() on the \c IKeyState if necessary - when the keyboard mapping changes. + call \c setKeyDown() on its \c CKeyState whenever a key is pressed + or released (but not for key repeats). And it should call + \c updateKeys() on its \c CKeyState if necessary when the keyboard + mapping changes. The target of all events should be the value returned by \c getEventTarget(). diff --git a/lib/synergy/IPrimaryScreen.cpp b/lib/synergy/IPrimaryScreen.cpp index 9a201001..62d3c4b9 100644 --- a/lib/synergy/IPrimaryScreen.cpp +++ b/lib/synergy/IPrimaryScreen.cpp @@ -18,9 +18,6 @@ // IPrimaryScreen // -CEvent::Type IPrimaryScreen::s_keyDownEvent = CEvent::kUnknown; -CEvent::Type IPrimaryScreen::s_keyUpEvent = CEvent::kUnknown; -CEvent::Type IPrimaryScreen::s_keyRepeatEvent = CEvent::kUnknown; CEvent::Type IPrimaryScreen::s_buttonDownEvent = CEvent::kUnknown; CEvent::Type IPrimaryScreen::s_buttonUpEvent = CEvent::kUnknown; CEvent::Type IPrimaryScreen::s_motionPrimaryEvent = CEvent::kUnknown; @@ -29,27 +26,6 @@ CEvent::Type IPrimaryScreen::s_wheelEvent = CEvent::kUnknown; CEvent::Type IPrimaryScreen::s_ssActivatedEvent = CEvent::kUnknown; CEvent::Type IPrimaryScreen::s_ssDeactivatedEvent = CEvent::kUnknown; -CEvent::Type -IPrimaryScreen::getKeyDownEvent() -{ - return CEvent::registerTypeOnce(s_keyDownEvent, - "IPrimaryScreen::keyDown"); -} - -CEvent::Type -IPrimaryScreen::getKeyUpEvent() -{ - return CEvent::registerTypeOnce(s_keyUpEvent, - "IPrimaryScreen::keyUp"); -} - -CEvent::Type -IPrimaryScreen::getKeyRepeatEvent() -{ - return CEvent::registerTypeOnce(s_keyRepeatEvent, - "IPrimaryScreen::keyRepeat"); -} - CEvent::Type IPrimaryScreen::getButtonDownEvent() { @@ -100,23 +76,6 @@ IPrimaryScreen::getScreensaverDeactivatedEvent() } -// -// IPrimaryScreen::CKeyInfo -// - -IPrimaryScreen::CKeyInfo* -IPrimaryScreen::CKeyInfo::alloc(KeyID id, - KeyModifierMask mask, KeyButton button, SInt32 count) -{ - CKeyInfo* info = (CKeyInfo*)malloc(sizeof(CKeyInfo)); - info->m_key = id; - info->m_mask = mask; - info->m_button = button; - info->m_count = count; - return info; -} - - // // IPrimaryScreen::CButtonInfo // diff --git a/lib/synergy/IPrimaryScreen.h b/lib/synergy/IPrimaryScreen.h index 9b88caf8..6718a17b 100644 --- a/lib/synergy/IPrimaryScreen.h +++ b/lib/synergy/IPrimaryScreen.h @@ -16,9 +16,8 @@ #define IPRIMARYSCREEN_H #include "IInterface.h" -#include "IKeyState.h" -#include "CEvent.h" #include "MouseTypes.h" +#include "CEvent.h" //! Primary screen interface /*! @@ -27,17 +26,6 @@ primary screen implementations. */ class IPrimaryScreen : public IInterface { public: - //! Key event data - class CKeyInfo { - public: - static CKeyInfo* alloc(KeyID, KeyModifierMask, KeyButton, SInt32 count); - - public: - KeyID m_key; - KeyModifierMask m_mask; - KeyButton m_button; - SInt32 m_count; - }; //! Button event data class CButtonInfo { public: @@ -103,14 +91,6 @@ public: */ virtual bool isAnyMouseButtonDown() const = 0; - //! Get current modifier key state - /*! - Returns the current modifier key state. Ideally, "current" means - up to the lat processed event but it can mean the current physical - modifier key state. - */ - virtual KeyModifierMask getActiveModifiers() const = 0; - //! Get cursor center position /*! Return the cursor center position which is where we park the @@ -119,18 +99,6 @@ public: */ virtual void getCursorCenter(SInt32& x, SInt32& y) const = 0; - //! Get name of key - /*! - Return a string describing the given key. - */ - virtual const char* getKeyName(KeyButton) const = 0; - - //! Get key down event type. Event data is CKeyInfo*, count == 1. - static CEvent::Type getKeyDownEvent(); - //! Get key up event type. Event data is CKeyInfo*, count == 1. - static CEvent::Type getKeyUpEvent(); - //! Get key repeat event type. Event data is CKeyInfo*. - static CEvent::Type getKeyRepeatEvent(); //! Get button down event type. Event data is CButtonInfo*. static CEvent::Type getButtonDownEvent(); //! Get button up event type. Event data is CButtonInfo*. @@ -156,9 +124,6 @@ public: //@} private: - static CEvent::Type s_keyDownEvent; - static CEvent::Type s_keyUpEvent; - static CEvent::Type s_keyRepeatEvent; static CEvent::Type s_buttonDownEvent; static CEvent::Type s_buttonUpEvent; static CEvent::Type s_motionPrimaryEvent; diff --git a/lib/synergy/ISecondaryScreen.h b/lib/synergy/ISecondaryScreen.h index 0a556d59..65ac7708 100644 --- a/lib/synergy/ISecondaryScreen.h +++ b/lib/synergy/ISecondaryScreen.h @@ -16,7 +16,6 @@ #define ISECONDARYSCREEN_H #include "IInterface.h" -#include "IKeyState.h" #include "MouseTypes.h" //! Secondary screen interface @@ -29,12 +28,6 @@ public: //! @name accessors //@{ - //! Fake key press/release - /*! - Synthesize a press or release of key \c id. - */ - virtual void fakeKeyEvent(KeyButton id, bool press) const = 0; - //! Fake ctrl+alt+del /*! Synthesize a press of ctrl+alt+del. Return true if processing is @@ -60,22 +53,6 @@ public: */ virtual void fakeMouseWheel(SInt32 delta) const = 0; - //! Map key press/repeat to keystrokes - /*! - Convert a press/repeat of key \c id with the modifiers as given - in \c desiredMask into the keystrokes necessary to synthesize - that key event. This may expand into multiple keys due to modifiers - that don't match the current modifier state from \c keyState, or to - needing to compose a character using dead key, or to other reasons. - Return the platform specific code of the key being pressed. If \c id - cannot be mapped or if \c isAutoRepeat is true and the key does not - auto-repeat then return 0. - */ - virtual KeyButton mapKey(IKeyState::Keystrokes&, - const IKeyState& keyState, KeyID id, - KeyModifierMask desiredMask, - bool isAutoRepeat) const = 0; - //@} }; diff --git a/lib/synergy/Makefile.am b/lib/synergy/Makefile.am index 60a304ca..27fe0c63 100644 --- a/lib/synergy/Makefile.am +++ b/lib/synergy/Makefile.am @@ -26,16 +26,21 @@ MAINTAINERCLEANFILES = \ noinst_LIBRARIES = libsynergy.a libsynergy_a_SOURCES = \ CClipboard.cpp \ + CKeyState.cpp \ CPacketStreamFilter.cpp \ + CPlatformScreen.cpp \ CProtocolUtil.cpp \ CScreen.cpp \ IClipboard.cpp \ + IKeyState.cpp \ IPrimaryScreen.cpp \ IScreen.cpp \ XScreen.cpp \ XSynergy.cpp \ CClipboard.h \ + CKeyState.h \ CPacketStreamFilter.h \ + CPlatformScreen.h \ CProtocolUtil.h \ CScreen.h \ ClipboardTypes.h \