From 8d99fd25113c696fed96e2b34a6f503f084cda2e Mon Sep 17 00:00:00 2001 From: crs Date: Sun, 21 Mar 2004 20:01:41 +0000 Subject: [PATCH] Checkpoint. Converted X11 to new keyboard state tracking design. This new design is simpler. For keyboard support, clients need only implement 4 virtual methods on a class derived from CKeyState and one trivial method in the class derived from CPlatformScreen, which is now the superclass of platform screens instead of IPlatformScreen. Keyboard methods have been removed from IPlatformScreen, IPrimaryScreen and ISecondaryScreen. Also, all keyboard state tracking is now in exactly one place (the CKeyState subclass) rather than in CScreen, the platform screen, and the key mapper. Still need to convert Win32. --- lib/client/CClient.cpp | 3 +- ...owsKeyMapper.cpp => CXWindowsKeyState.cpp} | 191 +++--- ...WindowsKeyMapper.h => CXWindowsKeyState.h} | 78 ++- lib/platform/CXWindowsScreen.cpp | 102 +--- lib/platform/CXWindowsScreen.h | 59 +- lib/platform/Makefile.am | 4 +- lib/server/CPrimaryClient.cpp | 4 +- lib/synergy/CKeyState.cpp | 532 +++++++++++++++++ lib/synergy/CKeyState.h | 185 ++++++ lib/synergy/CPlatformScreen.cpp | 82 +++ lib/synergy/CPlatformScreen.h | 99 +++ lib/synergy/CScreen.cpp | 563 ++---------------- lib/synergy/CScreen.h | 83 +-- lib/synergy/IKeyState.cpp | 61 ++ lib/synergy/IKeyState.h | 133 ++--- lib/synergy/IPlatformScreen.h | 48 +- lib/synergy/IPrimaryScreen.cpp | 41 -- lib/synergy/IPrimaryScreen.h | 37 +- lib/synergy/ISecondaryScreen.h | 23 - lib/synergy/Makefile.am | 5 + 20 files changed, 1306 insertions(+), 1027 deletions(-) rename lib/platform/{CXWindowsKeyMapper.cpp => CXWindowsKeyState.cpp} (89%) rename lib/platform/{CXWindowsKeyMapper.h => CXWindowsKeyState.h} (68%) create mode 100644 lib/synergy/CKeyState.cpp create mode 100644 lib/synergy/CKeyState.h create mode 100644 lib/synergy/CPlatformScreen.cpp create mode 100644 lib/synergy/CPlatformScreen.h create mode 100644 lib/synergy/IKeyState.cpp 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 \