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.
This commit is contained in:
parent
19559d4b4e
commit
8d99fd2511
|
@ -181,8 +181,7 @@ CClient::enter(SInt32 xAbs, SInt32 yAbs, UInt32, KeyModifierMask mask, bool)
|
||||||
{
|
{
|
||||||
m_active = true;
|
m_active = true;
|
||||||
m_screen->mouseMove(xAbs, yAbs);
|
m_screen->mouseMove(xAbs, yAbs);
|
||||||
m_screen->enter();
|
m_screen->enter(mask);
|
||||||
m_screen->setToggleState(mask);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
|
@ -12,9 +12,10 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "CXWindowsKeyMapper.h"
|
#include "CXWindowsKeyState.h"
|
||||||
#include "CXWindowsUtil.h"
|
#include "CXWindowsUtil.h"
|
||||||
#include "CLog.h"
|
#include "CLog.h"
|
||||||
|
#include "CStringUtil.h"
|
||||||
#if defined(X_DISPLAY_MISSING)
|
#if defined(X_DISPLAY_MISSING)
|
||||||
# error X11 is required to build synergy
|
# error X11 is required to build synergy
|
||||||
#else
|
#else
|
||||||
|
@ -137,73 +138,119 @@ static const KeySym g_mapE000[] =
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
CXWindowsKeyMapper::CXWindowsKeyMapper()
|
CXWindowsKeyState::CXWindowsKeyState(Display* display) :
|
||||||
|
m_display(display)
|
||||||
{
|
{
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
CXWindowsKeyMapper::~CXWindowsKeyMapper()
|
CXWindowsKeyState::~CXWindowsKeyState()
|
||||||
{
|
{
|
||||||
// do nothing
|
// 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
|
void
|
||||||
CXWindowsKeyMapper::update(Display* display, IKeyState* keyState)
|
CXWindowsKeyState::doUpdateKeys()
|
||||||
{
|
{
|
||||||
// query which keys are pressed
|
// query which keys are pressed
|
||||||
char keys[32];
|
char keys[32];
|
||||||
XQueryKeymap(display, keys);
|
XQueryKeymap(m_display, keys);
|
||||||
|
|
||||||
// save the auto-repeat mask
|
// save the auto-repeat mask
|
||||||
XGetKeyboardControl(display, &m_keyControl);
|
XGetKeyboardControl(m_display, &m_keyControl);
|
||||||
|
|
||||||
// query the pointer to get the keyboard state
|
// query the pointer to get the keyboard state
|
||||||
Window root = DefaultRootWindow(display), window;
|
Window root = DefaultRootWindow(m_display), window;
|
||||||
int xRoot, yRoot, xWindow, yWindow;
|
int xRoot, yRoot, xWindow, yWindow;
|
||||||
unsigned int state;
|
unsigned int state;
|
||||||
if (!XQueryPointer(display, root, &root, &window,
|
if (!XQueryPointer(m_display, root, &root, &window,
|
||||||
&xRoot, &yRoot, &xWindow, &yWindow, &state)) {
|
&xRoot, &yRoot, &xWindow, &yWindow, &state)) {
|
||||||
state = 0;
|
state = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// update mappings
|
// update mappings
|
||||||
updateKeysymMap(display, keyState);
|
updateKeysymMap();
|
||||||
updateModifiers();
|
updateModifiers();
|
||||||
|
|
||||||
// transfer to our state
|
// transfer to our state
|
||||||
for (UInt32 i = 0, j = 0; i < 32; j += 8, ++i) {
|
for (UInt32 i = 0, j = 0; i < 32; j += 8, ++i) {
|
||||||
if ((keys[i] & 0x01) != 0)
|
if ((keys[i] & 0x01) != 0)
|
||||||
keyState->setKeyDown(j + 0, true);
|
setKeyDown(j + 0, true);
|
||||||
if ((keys[i] & 0x02) != 0)
|
if ((keys[i] & 0x02) != 0)
|
||||||
keyState->setKeyDown(j + 1, true);
|
setKeyDown(j + 1, true);
|
||||||
if ((keys[i] & 0x04) != 0)
|
if ((keys[i] & 0x04) != 0)
|
||||||
keyState->setKeyDown(j + 2, true);
|
setKeyDown(j + 2, true);
|
||||||
if ((keys[i] & 0x08) != 0)
|
if ((keys[i] & 0x08) != 0)
|
||||||
keyState->setKeyDown(j + 3, true);
|
setKeyDown(j + 3, true);
|
||||||
if ((keys[i] & 0x10) != 0)
|
if ((keys[i] & 0x10) != 0)
|
||||||
keyState->setKeyDown(j + 4, true);
|
setKeyDown(j + 4, true);
|
||||||
if ((keys[i] & 0x20) != 0)
|
if ((keys[i] & 0x20) != 0)
|
||||||
keyState->setKeyDown(j + 5, true);
|
setKeyDown(j + 5, true);
|
||||||
if ((keys[i] & 0x40) != 0)
|
if ((keys[i] & 0x40) != 0)
|
||||||
keyState->setKeyDown(j + 6, true);
|
setKeyDown(j + 6, true);
|
||||||
if ((keys[i] & 0x80) != 0)
|
if ((keys[i] & 0x80) != 0)
|
||||||
keyState->setKeyDown(j + 7, true);
|
setKeyDown(j + 7, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set toggle modifier states
|
// set toggle modifier states
|
||||||
if ((state & LockMask) != 0)
|
if ((state & LockMask) != 0)
|
||||||
keyState->setToggled(KeyModifierCapsLock);
|
setToggled(KeyModifierCapsLock);
|
||||||
if ((state & m_numLockMask) != 0)
|
if ((state & m_numLockMask) != 0)
|
||||||
keyState->setToggled(KeyModifierNumLock);
|
setToggled(KeyModifierNumLock);
|
||||||
if ((state & m_scrollLockMask) != 0)
|
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
|
KeyButton
|
||||||
CXWindowsKeyMapper::mapKey(IKeyState::Keystrokes& keys,
|
CXWindowsKeyState::mapKey(Keystrokes& keys, KeyID id,
|
||||||
const IKeyState& keyState, KeyID id,
|
KeyModifierMask desiredMask, bool isAutoRepeat) const
|
||||||
KeyModifierMask desiredMask,
|
|
||||||
bool isAutoRepeat) const
|
|
||||||
{
|
{
|
||||||
// the system translates key events into characters depending
|
// the system translates key events into characters depending
|
||||||
// on the modifier key state at the time of the event. to
|
// 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()) {
|
if (keyIndex != m_keysymMap.end()) {
|
||||||
// the keysym is mapped to some keycode. create the keystrokes
|
// the keysym is mapped to some keycode. create the keystrokes
|
||||||
// for this keysym.
|
// 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
|
// 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
|
// the keysym is mapped to some keycode
|
||||||
keycode = mapToKeystrokes(keys, keyState, keyIndex, isAutoRepeat);
|
keycode = mapToKeystrokes(keys, keyIndex, isAutoRepeat);
|
||||||
if (keycode == 0) {
|
if (keycode == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -281,45 +328,20 @@ CXWindowsKeyMapper::mapKey(IKeyState::Keystrokes& keys,
|
||||||
return keycode;
|
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
|
void
|
||||||
CXWindowsKeyMapper::updateKeysymMap(Display* display, IKeyState* keyState)
|
CXWindowsKeyState::updateKeysymMap()
|
||||||
{
|
{
|
||||||
// there are up to 4 keysyms per keycode
|
// there are up to 4 keysyms per keycode
|
||||||
static const unsigned int maxKeysyms = 4;
|
static const unsigned int maxKeysyms = 4;
|
||||||
|
|
||||||
// get the number of keycodes
|
// get the number of keycodes
|
||||||
int minKeycode, maxKeycode;
|
int minKeycode, maxKeycode;
|
||||||
XDisplayKeycodes(display, &minKeycode, &maxKeycode);
|
XDisplayKeycodes(m_display, &minKeycode, &maxKeycode);
|
||||||
const int numKeycodes = maxKeycode - minKeycode + 1;
|
const int numKeycodes = maxKeycode - minKeycode + 1;
|
||||||
|
|
||||||
// get the keyboard mapping for all keys
|
// get the keyboard mapping for all keys
|
||||||
int keysymsPerKeycode;
|
int keysymsPerKeycode;
|
||||||
KeySym* keysyms = XGetKeyboardMapping(display,
|
KeySym* keysyms = XGetKeyboardMapping(m_display,
|
||||||
minKeycode, numKeycodes,
|
minKeycode, numKeycodes,
|
||||||
&keysymsPerKeycode);
|
&keysymsPerKeycode);
|
||||||
|
|
||||||
|
@ -364,7 +386,7 @@ CXWindowsKeyMapper::updateKeysymMap(Display* display, IKeyState* keyState)
|
||||||
}
|
}
|
||||||
|
|
||||||
// get modifier map from server
|
// get modifier map from server
|
||||||
XModifierKeymap* modifiers = XGetModifierMapping(display);
|
XModifierKeymap* modifiers = XGetModifierMapping(m_display);
|
||||||
unsigned int keysPerModifier = modifiers->max_keypermod;
|
unsigned int keysPerModifier = modifiers->max_keypermod;
|
||||||
|
|
||||||
// clear state
|
// clear state
|
||||||
|
@ -387,7 +409,7 @@ CXWindowsKeyMapper::updateKeysymMap(Display* display, IKeyState* keyState)
|
||||||
for (unsigned int i = 0; i < 8; ++i) {
|
for (unsigned int i = 0; i < 8; ++i) {
|
||||||
// no keycodes for this modifier yet
|
// no keycodes for this modifier yet
|
||||||
KeyModifierMask mask = 0;
|
KeyModifierMask mask = 0;
|
||||||
IKeyState::KeyButtons modifierKeys;
|
KeyButtons modifierKeys;
|
||||||
|
|
||||||
// add each keycode for modifier
|
// add each keycode for modifier
|
||||||
for (unsigned int j = 0; j < keysPerModifier; ++j) {
|
for (unsigned int j = 0; j < keysPerModifier; ++j) {
|
||||||
|
@ -429,9 +451,9 @@ CXWindowsKeyMapper::updateKeysymMap(Display* display, IKeyState* keyState)
|
||||||
mapping.m_numLockSensitive = false;
|
mapping.m_numLockSensitive = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// tell keyState about this modifier
|
// note this modifier
|
||||||
if (mask != 0 && keyState != NULL) {
|
if (mask != 0) {
|
||||||
keyState->addModifier(mask, modifierKeys);
|
addModifier(mask, modifierKeys);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -485,7 +507,7 @@ CXWindowsKeyMapper::updateKeysymMap(Display* display, IKeyState* keyState)
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyModifierMask
|
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,
|
// some modifier indices (0,1,2) are dedicated to particular uses,
|
||||||
// the rest depend on the keysyms bound.
|
// the rest depend on the keysyms bound.
|
||||||
|
@ -546,16 +568,16 @@ CXWindowsKeyMapper::mapToModifierMask(unsigned int i, KeySym keysym)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CXWindowsKeyMapper::updateModifiers()
|
CXWindowsKeyState::updateModifiers()
|
||||||
{
|
{
|
||||||
struct CModifierBitInfo {
|
struct CModifierBitInfo {
|
||||||
public:
|
public:
|
||||||
KeySym CXWindowsKeyMapper::*m_keysym;
|
KeySym CXWindowsKeyState::*m_keysym;
|
||||||
KeySym m_left;
|
KeySym m_left;
|
||||||
KeySym m_right;
|
KeySym m_right;
|
||||||
};
|
};
|
||||||
static const CModifierBitInfo s_modifierBitTable[] = {
|
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
|
// choose the keysym to use for some modifiers. if a modifier has
|
||||||
|
@ -603,7 +625,7 @@ CXWindowsKeyMapper::updateModifiers()
|
||||||
}
|
}
|
||||||
|
|
||||||
KeySym
|
KeySym
|
||||||
CXWindowsKeyMapper::keyIDToKeySym(KeyID id, KeyModifierMask mask) const
|
CXWindowsKeyState::keyIDToKeySym(KeyID id, KeyModifierMask mask) const
|
||||||
{
|
{
|
||||||
// convert id to keysym
|
// convert id to keysym
|
||||||
KeySym keysym = NoSymbol;
|
KeySym keysym = NoSymbol;
|
||||||
|
@ -718,15 +740,13 @@ CXWindowsKeyMapper::keyIDToKeySym(KeyID id, KeyModifierMask mask) const
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyButton
|
KeyButton
|
||||||
CXWindowsKeyMapper::mapToKeystrokes(IKeyState::Keystrokes& keys,
|
CXWindowsKeyState::mapToKeystrokes(Keystrokes& keys,
|
||||||
const IKeyState& keyState,
|
KeySymIndex keyIndex, bool isAutoRepeat) const
|
||||||
KeySymIndex keyIndex,
|
|
||||||
bool isAutoRepeat) const
|
|
||||||
{
|
{
|
||||||
// keyIndex must be valid
|
// keyIndex must be valid
|
||||||
assert(keyIndex != m_keysymMap.end());
|
assert(keyIndex != m_keysymMap.end());
|
||||||
|
|
||||||
KeyModifierMask currentMask = keyState.getActiveModifiers();
|
KeyModifierMask currentMask = getActiveModifiers();
|
||||||
|
|
||||||
// get the keysym we're trying to generate and possible keycodes
|
// get the keysym we're trying to generate and possible keycodes
|
||||||
const KeySym keysym = keyIndex->first;
|
const KeySym keysym = keyIndex->first;
|
||||||
|
@ -798,14 +818,14 @@ CXWindowsKeyMapper::mapToKeystrokes(IKeyState::Keystrokes& keys,
|
||||||
}
|
}
|
||||||
|
|
||||||
// adjust the modifiers to match the desired modifiers
|
// adjust the modifiers to match the desired modifiers
|
||||||
IKeyState::Keystrokes undo;
|
Keystrokes undo;
|
||||||
if (!adjustModifiers(keys, undo, keyState, desiredMask)) {
|
if (!adjustModifiers(keys, undo, desiredMask)) {
|
||||||
LOG((CLOG_DEBUG2 "failed to adjust modifiers"));
|
LOG((CLOG_DEBUG2 "failed to adjust modifiers"));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// add the key event
|
// add the key event
|
||||||
IKeyState::Keystroke keystroke;
|
Keystroke keystroke;
|
||||||
keystroke.m_key = keycode;
|
keystroke.m_key = keycode;
|
||||||
if (!isAutoRepeat) {
|
if (!isAutoRepeat) {
|
||||||
keystroke.m_press = true;
|
keystroke.m_press = true;
|
||||||
|
@ -830,7 +850,7 @@ CXWindowsKeyMapper::mapToKeystrokes(IKeyState::Keystrokes& keys,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int
|
unsigned int
|
||||||
CXWindowsKeyMapper::findBestKeyIndex(KeySymIndex keyIndex,
|
CXWindowsKeyState::findBestKeyIndex(KeySymIndex keyIndex,
|
||||||
KeyModifierMask /*currentMask*/) const
|
KeyModifierMask /*currentMask*/) const
|
||||||
{
|
{
|
||||||
// there are up to 4 keycodes per keysym to choose from. the
|
// there are up to 4 keycodes per keysym to choose from. the
|
||||||
|
@ -856,7 +876,7 @@ CXWindowsKeyMapper::findBestKeyIndex(KeySymIndex keyIndex,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CXWindowsKeyMapper::isShiftInverted(KeySymIndex keyIndex,
|
CXWindowsKeyState::isShiftInverted(KeySymIndex keyIndex,
|
||||||
KeyModifierMask currentMask) const
|
KeyModifierMask currentMask) const
|
||||||
{
|
{
|
||||||
// each keycode has up to 4 keysym associated with it, one each for:
|
// each keycode has up to 4 keysym associated with it, one each for:
|
||||||
|
@ -885,12 +905,11 @@ CXWindowsKeyMapper::isShiftInverted(KeySymIndex keyIndex,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CXWindowsKeyMapper::adjustModifiers(IKeyState::Keystrokes& keys,
|
CXWindowsKeyState::adjustModifiers(Keystrokes& keys,
|
||||||
IKeyState::Keystrokes& undo,
|
Keystrokes& undo,
|
||||||
const IKeyState& keyState,
|
|
||||||
KeyModifierMask desiredMask) const
|
KeyModifierMask desiredMask) const
|
||||||
{
|
{
|
||||||
KeyModifierMask currentMask = keyState.getActiveModifiers();
|
KeyModifierMask currentMask = getActiveModifiers();
|
||||||
|
|
||||||
// get mode switch set correctly. do this before shift because
|
// get mode switch set correctly. do this before shift because
|
||||||
// mode switch may be sensitive to the shift modifier and will
|
// mode switch may be sensitive to the shift modifier and will
|
||||||
|
@ -909,8 +928,7 @@ CXWindowsKeyMapper::adjustModifiers(IKeyState::Keystrokes& keys,
|
||||||
if (wantShift != haveShift) {
|
if (wantShift != haveShift) {
|
||||||
// add shift keystrokes
|
// add shift keystrokes
|
||||||
LOG((CLOG_DEBUG2 "fix shift for mode switch"));
|
LOG((CLOG_DEBUG2 "fix shift for mode switch"));
|
||||||
if (!keyState.mapModifier(keys, undo,
|
if (!mapModifier(keys, undo, KeyModifierShift, wantShift)) {
|
||||||
KeyModifierShift, wantShift)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
currentMask ^= KeyModifierShift;
|
currentMask ^= KeyModifierShift;
|
||||||
|
@ -918,8 +936,7 @@ CXWindowsKeyMapper::adjustModifiers(IKeyState::Keystrokes& keys,
|
||||||
}
|
}
|
||||||
|
|
||||||
// add mode switch keystrokes
|
// add mode switch keystrokes
|
||||||
if (!keyState.mapModifier(keys, undo,
|
if (!mapModifier(keys, undo, KeyModifierModeSwitch, wantModeSwitch)) {
|
||||||
KeyModifierModeSwitch, wantModeSwitch)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
currentMask ^= KeyModifierModeSwitch;
|
currentMask ^= KeyModifierModeSwitch;
|
||||||
|
@ -931,7 +948,7 @@ CXWindowsKeyMapper::adjustModifiers(IKeyState::Keystrokes& keys,
|
||||||
if (wantShift != haveShift) {
|
if (wantShift != haveShift) {
|
||||||
// add shift keystrokes
|
// add shift keystrokes
|
||||||
LOG((CLOG_DEBUG2 "fix shift"));
|
LOG((CLOG_DEBUG2 "fix shift"));
|
||||||
if (!keyState.mapModifier(keys, undo, KeyModifierShift, wantShift)) {
|
if (!mapModifier(keys, undo, KeyModifierShift, wantShift)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
currentMask ^= KeyModifierShift;
|
currentMask ^= KeyModifierShift;
|
||||||
|
@ -941,13 +958,13 @@ CXWindowsKeyMapper::adjustModifiers(IKeyState::Keystrokes& keys,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CXWindowsKeyMapper::isNumLockSensitive(KeySym keysym) const
|
CXWindowsKeyState::isNumLockSensitive(KeySym keysym) const
|
||||||
{
|
{
|
||||||
return (IsKeypadKey(keysym) || IsPrivateKeypadKey(keysym));
|
return (IsKeypadKey(keysym) || IsPrivateKeypadKey(keysym));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CXWindowsKeyMapper::isCapsLockSensitive(KeySym keysym) const
|
CXWindowsKeyState::isCapsLockSensitive(KeySym keysym) const
|
||||||
{
|
{
|
||||||
KeySym lKey, uKey;
|
KeySym lKey, uKey;
|
||||||
XConvertCase(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[0] = 0;
|
||||||
m_keycode[1] = 0;
|
m_keycode[1] = 0;
|
|
@ -12,62 +12,55 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef CXWINDOWSKEYMAPPER_H
|
#ifndef CXWINDOWSKEYSTATE_H
|
||||||
#define CXWINDOWSKEYMAPPER_H
|
#define CXWINDOWSKEYSTATE_H
|
||||||
|
|
||||||
#include "IKeyState.h"
|
#include "CKeyState.h"
|
||||||
#include "stdmap.h"
|
#include "stdmap.h"
|
||||||
#if defined(X_DISPLAY_MISSING)
|
#if defined(X_DISPLAY_MISSING)
|
||||||
# error X11 is required to build synergy
|
# error X11 is required to build synergy
|
||||||
#else
|
#else
|
||||||
# include <X11/Xlib.h>
|
# include <X11/Xlib.h>
|
||||||
|
# if defined(HAVE_X11_EXTENSIONS_XTEST_H)
|
||||||
|
# include <X11/extensions/XTest.h>
|
||||||
|
# else
|
||||||
|
# error The XTest extension is required to build synergy
|
||||||
|
# endif
|
||||||
#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:
|
public:
|
||||||
CXWindowsKeyMapper();
|
CXWindowsKeyState(Display*);
|
||||||
~CXWindowsKeyMapper();
|
~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
|
//! @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
|
//! Convert X modifier mask to synergy mask
|
||||||
/*!
|
/*!
|
||||||
Returns the synergy modifier mask corresponding to the given X
|
Returns the synergy modifier mask corresponding to the X modifier
|
||||||
modifier mask.
|
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:
|
private:
|
||||||
class KeyMapping {
|
class KeyMapping {
|
||||||
public:
|
public:
|
||||||
|
@ -90,9 +83,8 @@ private:
|
||||||
typedef std::map<KeySym, KeyMapping> KeySymMap;
|
typedef std::map<KeySym, KeyMapping> KeySymMap;
|
||||||
typedef KeySymMap::const_iterator KeySymIndex;
|
typedef KeySymMap::const_iterator KeySymIndex;
|
||||||
|
|
||||||
// save the current keyboard mapping and note the currently
|
// save the current keyboard mapping and note the modifiers
|
||||||
// pressed keys in \c keyState.
|
void updateKeysymMap();
|
||||||
void updateKeysymMap(Display* display, IKeyState* keyState);
|
|
||||||
|
|
||||||
// note interesting modifier KeySyms
|
// note interesting modifier KeySyms
|
||||||
void updateModifiers();
|
void updateModifiers();
|
||||||
|
@ -105,8 +97,7 @@ private:
|
||||||
KeySym keyIDToKeySym(KeyID id, KeyModifierMask mask) const;
|
KeySym keyIDToKeySym(KeyID id, KeyModifierMask mask) const;
|
||||||
|
|
||||||
// map a KeySym into the keystrokes to produce it
|
// map a KeySym into the keystrokes to produce it
|
||||||
KeyButton mapToKeystrokes(IKeyState::Keystrokes& keys,
|
KeyButton mapToKeystrokes(Keystrokes& keys,
|
||||||
const IKeyState& keyState,
|
|
||||||
KeySymIndex keyIndex,
|
KeySymIndex keyIndex,
|
||||||
bool isAutoRepeat) const;
|
bool isAutoRepeat) const;
|
||||||
|
|
||||||
|
@ -120,9 +111,8 @@ private:
|
||||||
|
|
||||||
// returns the keystrokes to adjust the modifiers into the desired
|
// returns the keystrokes to adjust the modifiers into the desired
|
||||||
// state the keystrokes to get back to the current state.
|
// state the keystrokes to get back to the current state.
|
||||||
bool adjustModifiers(IKeyState::Keystrokes& keys,
|
bool adjustModifiers(Keystrokes& keys,
|
||||||
IKeyState::Keystrokes& undo,
|
Keystrokes& undo,
|
||||||
const IKeyState& keyState,
|
|
||||||
KeyModifierMask desiredMask) const;
|
KeyModifierMask desiredMask) const;
|
||||||
|
|
||||||
// returns true if keysym is sensitive to the NumLock state
|
// returns true if keysym is sensitive to the NumLock state
|
||||||
|
@ -132,6 +122,8 @@ private:
|
||||||
bool isCapsLockSensitive(KeySym keysym) const;
|
bool isCapsLockSensitive(KeySym keysym) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Display* m_display;
|
||||||
|
|
||||||
// keysym to keycode mapping
|
// keysym to keycode mapping
|
||||||
KeySymMap m_keysymMap;
|
KeySymMap m_keysymMap;
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "CXWindowsScreen.h"
|
#include "CXWindowsScreen.h"
|
||||||
#include "CXWindowsClipboard.h"
|
#include "CXWindowsClipboard.h"
|
||||||
#include "CXWindowsEventQueueBuffer.h"
|
#include "CXWindowsEventQueueBuffer.h"
|
||||||
|
#include "CXWindowsKeyState.h"
|
||||||
#include "CXWindowsScreenSaver.h"
|
#include "CXWindowsScreenSaver.h"
|
||||||
#include "CXWindowsUtil.h"
|
#include "CXWindowsUtil.h"
|
||||||
#include "CClipboard.h"
|
#include "CClipboard.h"
|
||||||
|
@ -131,7 +132,6 @@ CXWindowsScreen::CXWindowsScreen(bool isPrimary) :
|
||||||
m_xCenter(0), m_yCenter(0),
|
m_xCenter(0), m_yCenter(0),
|
||||||
m_xCursor(0), m_yCursor(0),
|
m_xCursor(0), m_yCursor(0),
|
||||||
m_keyState(NULL),
|
m_keyState(NULL),
|
||||||
m_keyMapper(),
|
|
||||||
m_im(NULL),
|
m_im(NULL),
|
||||||
m_ic(NULL),
|
m_ic(NULL),
|
||||||
m_lastKeycode(0),
|
m_lastKeycode(0),
|
||||||
|
@ -154,6 +154,7 @@ CXWindowsScreen::CXWindowsScreen(bool isPrimary) :
|
||||||
m_window = openWindow();
|
m_window = openWindow();
|
||||||
m_screensaver = new CXWindowsScreenSaver(m_display,
|
m_screensaver = new CXWindowsScreenSaver(m_display,
|
||||||
m_window, getEventTarget());
|
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 "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));
|
LOG((CLOG_DEBUG "window is 0x%08x", m_window));
|
||||||
}
|
}
|
||||||
|
@ -201,7 +202,9 @@ CXWindowsScreen::~CXWindowsScreen()
|
||||||
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
|
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
|
||||||
delete m_clipboard[id];
|
delete m_clipboard[id];
|
||||||
}
|
}
|
||||||
|
delete m_keyState;
|
||||||
delete m_screensaver;
|
delete m_screensaver;
|
||||||
|
m_keyState = NULL;
|
||||||
m_screensaver = NULL;
|
m_screensaver = NULL;
|
||||||
if (m_display != NULL) {
|
if (m_display != NULL) {
|
||||||
// FIXME -- is it safe to clean up the IC and IM without a display?
|
// FIXME -- is it safe to clean up the IC and IM without a display?
|
||||||
|
@ -219,12 +222,6 @@ CXWindowsScreen::~CXWindowsScreen()
|
||||||
s_screen = NULL;
|
s_screen = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
CXWindowsScreen::setKeyState(IKeyState* keyState)
|
|
||||||
{
|
|
||||||
m_keyState = keyState;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
CXWindowsScreen::enable()
|
CXWindowsScreen::enable()
|
||||||
{
|
{
|
||||||
|
@ -319,7 +316,6 @@ CXWindowsScreen::leave()
|
||||||
}
|
}
|
||||||
|
|
||||||
// raise and show the window
|
// raise and show the window
|
||||||
// FIXME -- take focus?
|
|
||||||
XMapRaised(m_display, m_window);
|
XMapRaised(m_display, m_window);
|
||||||
|
|
||||||
// grab the mouse and keyboard, if primary and possible
|
// grab the mouse and keyboard, if primary and possible
|
||||||
|
@ -328,6 +324,9 @@ CXWindowsScreen::leave()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// take focus
|
||||||
|
XSetInputFocus(m_display, m_window, RevertToPointerRoot, CurrentTime);
|
||||||
|
|
||||||
// now warp the mouse. we warp after showing the window so we're
|
// now warp the mouse. we warp after showing the window so we're
|
||||||
// guaranteed to get the mouse leave event and to prevent the
|
// guaranteed to get the mouse leave event and to prevent the
|
||||||
// keyboard focus from changing under point-to-focus policies.
|
// 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
|
void
|
||||||
CXWindowsScreen::setSequenceNumber(UInt32 seqNum)
|
CXWindowsScreen::setSequenceNumber(UInt32 seqNum)
|
||||||
{
|
{
|
||||||
|
@ -547,21 +538,6 @@ CXWindowsScreen::isAnyMouseButtonDown() const
|
||||||
return false;
|
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
|
void
|
||||||
CXWindowsScreen::getCursorCenter(SInt32& x, SInt32& y) const
|
CXWindowsScreen::getCursorCenter(SInt32& x, SInt32& y) const
|
||||||
{
|
{
|
||||||
|
@ -569,28 +545,6 @@ CXWindowsScreen::getCursorCenter(SInt32& x, SInt32& y) const
|
||||||
y = m_yCenter;
|
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
|
bool
|
||||||
CXWindowsScreen::fakeCtrlAltDel() const
|
CXWindowsScreen::fakeCtrlAltDel() const
|
||||||
{
|
{
|
||||||
|
@ -645,15 +599,6 @@ CXWindowsScreen::fakeMouseWheel(SInt32 delta) const
|
||||||
XFlush(m_display);
|
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*
|
Display*
|
||||||
CXWindowsScreen::openDisplay() const
|
CXWindowsScreen::openDisplay() const
|
||||||
{
|
{
|
||||||
|
@ -788,6 +733,7 @@ CXWindowsScreen::openIM()
|
||||||
// open the input methods
|
// open the input methods
|
||||||
XIM im = XOpenIM(m_display, NULL, NULL, NULL);
|
XIM im = XOpenIM(m_display, NULL, NULL, NULL);
|
||||||
if (im == NULL) {
|
if (im == NULL) {
|
||||||
|
LOG((CLOG_INFO "no support for IM"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -811,7 +757,7 @@ CXWindowsScreen::openIM()
|
||||||
}
|
}
|
||||||
XFree(styles);
|
XFree(styles);
|
||||||
if (style == 0) {
|
if (style == 0) {
|
||||||
LOG((CLOG_WARN "no supported IM styles"));
|
LOG((CLOG_INFO "no supported IM styles"));
|
||||||
XCloseIM(im);
|
XCloseIM(im);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -859,6 +805,12 @@ CXWindowsScreen::sendClipboardEvent(CEvent::Type type, ClipboardID id)
|
||||||
sendEvent(type, info);
|
sendEvent(type, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IKeyState*
|
||||||
|
CXWindowsScreen::getKeyState() const
|
||||||
|
{
|
||||||
|
return m_keyState;
|
||||||
|
}
|
||||||
|
|
||||||
Bool
|
Bool
|
||||||
CXWindowsScreen::findKeyEvent(Display*, XEvent* xevent, XPointer arg)
|
CXWindowsScreen::findKeyEvent(Display*, XEvent* xevent, XPointer arg)
|
||||||
{
|
{
|
||||||
|
@ -1063,7 +1015,7 @@ void
|
||||||
CXWindowsScreen::onKeyPress(XKeyEvent& xkey)
|
CXWindowsScreen::onKeyPress(XKeyEvent& xkey)
|
||||||
{
|
{
|
||||||
LOG((CLOG_DEBUG1 "event: KeyPress code=%d, state=0x%04x", xkey.keycode, xkey.state));
|
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);
|
KeyID key = mapKeyFromX(&xkey);
|
||||||
if (key != kKeyNone) {
|
if (key != kKeyNone) {
|
||||||
// check for ctrl+alt+del emulation
|
// check for ctrl+alt+del emulation
|
||||||
|
@ -1083,19 +1035,15 @@ CXWindowsScreen::onKeyPress(XKeyEvent& xkey)
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle key
|
// handle key
|
||||||
sendEvent(getKeyDownEvent(), CKeyInfo::alloc(key, mask, keycode, 1));
|
m_keyState->sendKeyEvent(getEventTarget(),
|
||||||
KeyModifierMask keyMask = m_keyState->getMaskForKey(keycode);
|
true, false, key, mask, 1, keycode);
|
||||||
if (m_keyState->isHalfDuplex(keyMask)) {
|
|
||||||
sendEvent(getKeyUpEvent(),
|
|
||||||
CKeyInfo::alloc(key, mask | keyMask, keycode, 1));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CXWindowsScreen::onKeyRelease(XKeyEvent& xkey, bool isRepeat)
|
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);
|
KeyID key = mapKeyFromX(&xkey);
|
||||||
if (key != kKeyNone) {
|
if (key != kKeyNone) {
|
||||||
// check for ctrl+alt+del emulation
|
// check for ctrl+alt+del emulation
|
||||||
|
@ -1112,12 +1060,8 @@ CXWindowsScreen::onKeyRelease(XKeyEvent& xkey, bool isRepeat)
|
||||||
if (!isRepeat) {
|
if (!isRepeat) {
|
||||||
// no press event follows so it's a plain release
|
// no press event follows so it's a plain release
|
||||||
LOG((CLOG_DEBUG1 "event: KeyRelease code=%d, state=0x%04x", keycode, xkey.state));
|
LOG((CLOG_DEBUG1 "event: KeyRelease code=%d, state=0x%04x", keycode, xkey.state));
|
||||||
KeyModifierMask keyMask = m_keyState->getMaskForKey(keycode);
|
m_keyState->sendKeyEvent(getEventTarget(),
|
||||||
if (m_keyState->isHalfDuplex(keyMask)) {
|
false, false, key, mask, 1, keycode);
|
||||||
sendEvent(getKeyDownEvent(),
|
|
||||||
CKeyInfo::alloc(key, mask, keycode, 1));
|
|
||||||
}
|
|
||||||
sendEvent(getKeyUpEvent(), CKeyInfo::alloc(key, mask, keycode, 1));
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// found a press event following so it's a repeat.
|
// 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.
|
// repeats but we'll just send a repeat of 1.
|
||||||
// note that we discard the press event.
|
// note that we discard the press event.
|
||||||
LOG((CLOG_DEBUG1 "event: repeat code=%d, state=0x%04x", keycode, xkey.state));
|
LOG((CLOG_DEBUG1 "event: repeat code=%d, state=0x%04x", keycode, xkey.state));
|
||||||
sendEvent(getKeyRepeatEvent(),
|
m_keyState->sendKeyEvent(getEventTarget(),
|
||||||
CKeyInfo::alloc(key, mask, keycode, 1));
|
false, true, key, mask, 1, keycode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,8 +15,7 @@
|
||||||
#ifndef CXWINDOWSSCREEN_H
|
#ifndef CXWINDOWSSCREEN_H
|
||||||
#define CXWINDOWSSCREEN_H
|
#define CXWINDOWSSCREEN_H
|
||||||
|
|
||||||
#include "IPlatformScreen.h"
|
#include "CPlatformScreen.h"
|
||||||
#include "CXWindowsKeyMapper.h"
|
|
||||||
#include "stdvector.h"
|
#include "stdvector.h"
|
||||||
#if defined(X_DISPLAY_MISSING)
|
#if defined(X_DISPLAY_MISSING)
|
||||||
# error X11 is required to build synergy
|
# error X11 is required to build synergy
|
||||||
|
@ -25,10 +24,11 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class CXWindowsClipboard;
|
class CXWindowsClipboard;
|
||||||
|
class CXWindowsKeyState;
|
||||||
class CXWindowsScreenSaver;
|
class CXWindowsScreenSaver;
|
||||||
|
|
||||||
//! Implementation of IPlatformScreen for X11
|
//! Implementation of IPlatformScreen for X11
|
||||||
class CXWindowsScreen : public IPlatformScreen {
|
class CXWindowsScreen : public CPlatformScreen {
|
||||||
public:
|
public:
|
||||||
CXWindowsScreen(bool isPrimary);
|
CXWindowsScreen(bool isPrimary);
|
||||||
virtual ~CXWindowsScreen();
|
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
|
// IScreen overrides
|
||||||
virtual void* getEventTarget() const;
|
virtual void* getEventTarget() const;
|
||||||
virtual bool getClipboard(ClipboardID id, IClipboard*) const;
|
virtual bool getClipboard(ClipboardID id, IClipboard*) const;
|
||||||
|
@ -67,29 +50,40 @@ public:
|
||||||
virtual void warpCursor(SInt32 x, SInt32 y);
|
virtual void warpCursor(SInt32 x, SInt32 y);
|
||||||
virtual SInt32 getJumpZoneSize() const;
|
virtual SInt32 getJumpZoneSize() const;
|
||||||
virtual bool isAnyMouseButtonDown() const;
|
virtual bool isAnyMouseButtonDown() const;
|
||||||
virtual KeyModifierMask getActiveModifiers() const;
|
|
||||||
virtual void getCursorCenter(SInt32& x, SInt32& y) const;
|
virtual void getCursorCenter(SInt32& x, SInt32& y) const;
|
||||||
virtual const char* getKeyName(KeyButton) const;
|
|
||||||
|
|
||||||
// ISecondaryScreen overrides
|
// ISecondaryScreen overrides
|
||||||
virtual void fakeKeyEvent(KeyButton id, bool press) const;
|
|
||||||
virtual bool fakeCtrlAltDel() const;
|
virtual bool fakeCtrlAltDel() const;
|
||||||
virtual void fakeMouseButton(ButtonID id, bool press) const;
|
virtual void fakeMouseButton(ButtonID id, bool press) const;
|
||||||
virtual void fakeMouseMove(SInt32 x, SInt32 y) const;
|
virtual void fakeMouseMove(SInt32 x, SInt32 y) const;
|
||||||
virtual void fakeMouseWheel(SInt32 delta) const;
|
virtual void fakeMouseWheel(SInt32 delta) const;
|
||||||
virtual KeyButton mapKey(IKeyState::Keystrokes&,
|
|
||||||
const IKeyState& keyState, KeyID id,
|
// IPlatformScreen overrides
|
||||||
KeyModifierMask desiredMask,
|
virtual void enable();
|
||||||
bool isAutoRepeat) const;
|
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:
|
private:
|
||||||
// event sending
|
// event sending
|
||||||
void sendEvent(CEvent::Type, void* = NULL);
|
void sendEvent(CEvent::Type, void* = NULL);
|
||||||
void sendClipboardEvent(CEvent::Type, ClipboardID);
|
void sendClipboardEvent(CEvent::Type, ClipboardID);
|
||||||
|
|
||||||
// event handling
|
|
||||||
void handleSystemEvent(const CEvent&, void*);
|
|
||||||
|
|
||||||
// create the transparent cursor
|
// create the transparent cursor
|
||||||
Cursor createBlankCursor() const;
|
Cursor createBlankCursor() const;
|
||||||
|
|
||||||
|
@ -138,8 +132,6 @@ private:
|
||||||
|
|
||||||
void warpCursorNoFlush(SInt32 x, SInt32 y);
|
void warpCursorNoFlush(SInt32 x, SInt32 y);
|
||||||
|
|
||||||
void updateButtons();
|
|
||||||
|
|
||||||
static Bool findKeyEvent(Display*, XEvent* xevent, XPointer arg);
|
static Bool findKeyEvent(Display*, XEvent* xevent, XPointer arg);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -162,8 +154,7 @@ private:
|
||||||
SInt32 m_xCursor, m_yCursor;
|
SInt32 m_xCursor, m_yCursor;
|
||||||
|
|
||||||
// keyboard stuff
|
// keyboard stuff
|
||||||
IKeyState* m_keyState;
|
CXWindowsKeyState* m_keyState;
|
||||||
CXWindowsKeyMapper m_keyMapper;
|
|
||||||
|
|
||||||
// input method stuff
|
// input method stuff
|
||||||
XIM m_im;
|
XIM m_im;
|
||||||
|
|
|
@ -54,7 +54,7 @@ libplatform_a_SOURCES = \
|
||||||
CXWindowsClipboardUCS2Converter.cpp \
|
CXWindowsClipboardUCS2Converter.cpp \
|
||||||
CXWindowsClipboardUTF8Converter.cpp \
|
CXWindowsClipboardUTF8Converter.cpp \
|
||||||
CXWindowsEventQueueBuffer.cpp \
|
CXWindowsEventQueueBuffer.cpp \
|
||||||
CXWindowsKeyMapper.cpp \
|
CXWindowsKeyState.cpp \
|
||||||
CXWindowsScreen.cpp \
|
CXWindowsScreen.cpp \
|
||||||
CXWindowsScreenSaver.cpp \
|
CXWindowsScreenSaver.cpp \
|
||||||
CXWindowsUtil.cpp \
|
CXWindowsUtil.cpp \
|
||||||
|
@ -63,7 +63,7 @@ libplatform_a_SOURCES = \
|
||||||
CXWindowsClipboardUCS2Converter.h \
|
CXWindowsClipboardUCS2Converter.h \
|
||||||
CXWindowsClipboardUTF8Converter.h \
|
CXWindowsClipboardUTF8Converter.h \
|
||||||
CXWindowsEventQueueBuffer.h \
|
CXWindowsEventQueueBuffer.h \
|
||||||
CXWindowsKeyMapper.h \
|
CXWindowsKeyState.h \
|
||||||
CXWindowsScreen.h \
|
CXWindowsScreen.h \
|
||||||
CXWindowsScreenSaver.h \
|
CXWindowsScreenSaver.h \
|
||||||
CXWindowsUtil.h \
|
CXWindowsUtil.h \
|
||||||
|
|
|
@ -105,13 +105,13 @@ CPrimaryClient::disable()
|
||||||
|
|
||||||
void
|
void
|
||||||
CPrimaryClient::enter(SInt32 xAbs, SInt32 yAbs,
|
CPrimaryClient::enter(SInt32 xAbs, SInt32 yAbs,
|
||||||
UInt32 seqNum, KeyModifierMask, bool screensaver)
|
UInt32 seqNum, KeyModifierMask mask, bool screensaver)
|
||||||
{
|
{
|
||||||
m_screen->setSequenceNumber(seqNum);
|
m_screen->setSequenceNumber(seqNum);
|
||||||
if (!screensaver) {
|
if (!screensaver) {
|
||||||
m_screen->warpCursor(xAbs, yAbs);
|
m_screen->warpCursor(xAbs, yAbs);
|
||||||
}
|
}
|
||||||
m_screen->enter();
|
m_screen->enter(mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
|
@ -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 <string.h>
|
||||||
|
|
||||||
|
//
|
||||||
|
// 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<KeyButton>(((*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));
|
||||||
|
}
|
||||||
|
}
|
|
@ -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<Keystroke> Keystrokes;
|
||||||
|
typedef std::vector<KeyButton> 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
|
|
@ -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);
|
||||||
|
}
|
|
@ -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
|
|
@ -32,9 +32,6 @@ CScreen::CScreen(IPlatformScreen* platformScreen) :
|
||||||
{
|
{
|
||||||
assert(m_screen != NULL);
|
assert(m_screen != NULL);
|
||||||
|
|
||||||
// open screen
|
|
||||||
m_screen->setKeyState(this);
|
|
||||||
|
|
||||||
// reset options
|
// reset options
|
||||||
resetOptions();
|
resetOptions();
|
||||||
|
|
||||||
|
@ -78,7 +75,7 @@ CScreen::disable()
|
||||||
leave();
|
leave();
|
||||||
}
|
}
|
||||||
else if (m_isPrimary && !m_entered) {
|
else if (m_isPrimary && !m_entered) {
|
||||||
enter();
|
enter(0);
|
||||||
}
|
}
|
||||||
m_screen->disable();
|
m_screen->disable();
|
||||||
if (m_isPrimary) {
|
if (m_isPrimary) {
|
||||||
|
@ -93,7 +90,7 @@ CScreen::disable()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CScreen::enter()
|
CScreen::enter(KeyModifierMask toggleMask)
|
||||||
{
|
{
|
||||||
assert(m_entered == false);
|
assert(m_entered == false);
|
||||||
LOG((CLOG_INFO "entering screen"));
|
LOG((CLOG_INFO "entering screen"));
|
||||||
|
@ -105,7 +102,7 @@ CScreen::enter()
|
||||||
enterPrimary();
|
enterPrimary();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
enterSecondary();
|
enterSecondary(toggleMask);
|
||||||
}
|
}
|
||||||
m_screen->enter();
|
m_screen->enter();
|
||||||
}
|
}
|
||||||
|
@ -186,22 +183,7 @@ CScreen::keyDown(KeyID id, KeyModifierMask mask, KeyButton button)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
m_screen->fakeKeyDown(id, mask, button);
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -209,86 +191,14 @@ CScreen::keyRepeat(KeyID id,
|
||||||
KeyModifierMask mask, SInt32 count, KeyButton button)
|
KeyModifierMask mask, SInt32 count, KeyButton button)
|
||||||
{
|
{
|
||||||
assert(!m_isPrimary);
|
assert(!m_isPrimary);
|
||||||
|
m_screen->fakeKeyRepeat(id, mask, count, button);
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CScreen::keyUp(KeyID, KeyModifierMask, KeyButton button)
|
CScreen::keyUp(KeyID, KeyModifierMask, KeyButton button)
|
||||||
{
|
{
|
||||||
assert(!m_isPrimary);
|
assert(!m_isPrimary);
|
||||||
|
m_screen->fakeKeyUp(button);
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -323,8 +233,7 @@ void
|
||||||
CScreen::resetOptions()
|
CScreen::resetOptions()
|
||||||
{
|
{
|
||||||
// reset options
|
// reset options
|
||||||
m_numLockHalfDuplex = false;
|
m_halfDuplex = 0;
|
||||||
m_capsLockHalfDuplex = false;
|
|
||||||
|
|
||||||
// if screen saver synchronization was off then turn it on since
|
// if screen saver synchronization was off then turn it on since
|
||||||
// that's the default option state.
|
// 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"));
|
LOG((CLOG_DEBUG1 "screen saver synchronization %s", m_screenSaverSync ? "on" : "off"));
|
||||||
}
|
}
|
||||||
else if (options[i] == kOptionHalfDuplexCapsLock) {
|
else if (options[i] == kOptionHalfDuplexCapsLock) {
|
||||||
m_capsLockHalfDuplex = (options[i + 1] != 0);
|
if (options[i + 1] != 0) {
|
||||||
LOG((CLOG_DEBUG1 "half-duplex caps-lock %s", m_capsLockHalfDuplex ? "on" : "off"));
|
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) {
|
else if (options[i] == kOptionHalfDuplexNumLock) {
|
||||||
m_numLockHalfDuplex = (options[i + 1] != 0);
|
if (options[i + 1] != 0) {
|
||||||
LOG((CLOG_DEBUG1 "half-duplex num-lock %s", m_numLockHalfDuplex ? "on" : "off"));
|
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
|
// be necessary but we don't seem to get some key release
|
||||||
// events sometimes. this is an emergency backup so the
|
// events sometimes. this is an emergency backup so the
|
||||||
// client doesn't get stuck on the screen.
|
// client doesn't get stuck on the screen.
|
||||||
const_cast<CScreen*>(this)->updateKeys();
|
m_screen->updateKeys();
|
||||||
KeyButton key2 = isAnyKeyDown();
|
KeyButton key2 = isAnyKeyDown();
|
||||||
if (key2 != 0) {
|
if (key2 != 0) {
|
||||||
LOG((CLOG_DEBUG "locked by %s", m_screen->getKeyName(key2)));
|
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);
|
m_screen->getCursorCenter(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KeyModifierMask
|
||||||
|
CScreen::getActiveModifiers() const
|
||||||
|
{
|
||||||
|
return m_screen->getActiveModifiers();
|
||||||
|
}
|
||||||
|
|
||||||
void*
|
void*
|
||||||
CScreen::getEventTarget() const
|
CScreen::getEventTarget() const
|
||||||
{
|
{
|
||||||
|
@ -457,253 +384,6 @@ CScreen::getCursorPos(SInt32& x, SInt32& y) const
|
||||||
m_screen->getCursorPos(x, y);
|
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<KeyButton>((*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<KeyButton>(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
|
void
|
||||||
CScreen::enablePrimary()
|
CScreen::enablePrimary()
|
||||||
{
|
{
|
||||||
|
@ -749,13 +429,16 @@ CScreen::enterPrimary()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CScreen::enterSecondary()
|
CScreen::enterSecondary(KeyModifierMask toggleMask)
|
||||||
{
|
{
|
||||||
// update our keyboard state to reflect the local state
|
// update our keyboard state to reflect the local state
|
||||||
updateKeys();
|
m_screen->updateKeys();
|
||||||
|
|
||||||
// remember toggle key state. we'll restore this when we leave.
|
// 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
|
void
|
||||||
|
@ -774,170 +457,42 @@ CScreen::leaveSecondary()
|
||||||
setToggleState(m_toggleKeys);
|
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
|
void
|
||||||
CScreen::doKeystrokes(const Keystrokes& keys, SInt32 count)
|
CScreen::releaseKeys()
|
||||||
{
|
{
|
||||||
// do nothing if no keys or no repeats
|
// release keys that we've synthesized a press for and only those
|
||||||
if (count < 1 || keys.empty()) {
|
// keys. we don't want to synthesize a release on a key the user
|
||||||
return;
|
// is still physically pressing.
|
||||||
}
|
for (KeyButton i = 1; i < IKeyState::kNumButtons; ++i) {
|
||||||
|
if (m_screen->isKeyDown(i)) {
|
||||||
// generate key events
|
m_screen->fakeKeyUp(i);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CScreen::fakeKeyEvent(KeyButton key, bool press, bool repeat) const
|
CScreen::setToggleState(KeyModifierMask mask)
|
||||||
{
|
{
|
||||||
// half-duplex keys are special. we ignore releases and convert
|
// toggle modifiers that don't match the desired state
|
||||||
// a press when the toggle is active to a release.
|
KeyModifierMask different = (m_screen->getActiveModifiers() ^ mask);
|
||||||
KeyModifierMask mask = getMaskForKey(key);
|
if ((different & KeyModifierCapsLock) != 0) {
|
||||||
if (isHalfDuplex(mask)) {
|
m_screen->fakeToggle(KeyModifierCapsLock);
|
||||||
if (repeat || !press) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if (isModifierActive(mask)) {
|
if ((different & KeyModifierNumLock) != 0) {
|
||||||
press = false;
|
m_screen->fakeToggle(KeyModifierNumLock);
|
||||||
|
}
|
||||||
|
if ((different & KeyModifierScrollLock) != 0) {
|
||||||
|
m_screen->fakeToggle(KeyModifierScrollLock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// send key event
|
KeyButton
|
||||||
LOG((CLOG_DEBUG2 " %d %s%s", key, press ? "down" : "up", repeat ? " repeat" : ""));
|
CScreen::isAnyKeyDown() const
|
||||||
m_screen->fakeKeyEvent(key, press);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CScreen::updateKeyState(KeyButton button, KeyButton key, bool press)
|
|
||||||
{
|
{
|
||||||
// ignore bogus keys
|
for (KeyButton i = 1; i < IKeyState::kNumButtons; ++i) {
|
||||||
key &= 0x1ffu;
|
if (m_screen->isKeyDown(i)) {
|
||||||
if (button == 0 || key == 0) {
|
return i;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return 0;
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CScreen::toggleKey(KeyModifierMask mask)
|
|
||||||
{
|
|
||||||
// get the system key ID for this toggle key ID
|
|
||||||
MaskToKeys::const_iterator i = m_maskToKeys.find(mask);
|
|
||||||
if (i == m_maskToKeys.end()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,12 +15,11 @@
|
||||||
#ifndef CSCREEN_H
|
#ifndef CSCREEN_H
|
||||||
#define CSCREEN_H
|
#define CSCREEN_H
|
||||||
|
|
||||||
#include "IKeyState.h"
|
|
||||||
#include "IScreen.h"
|
#include "IScreen.h"
|
||||||
#include "ClipboardTypes.h"
|
#include "ClipboardTypes.h"
|
||||||
|
#include "KeyTypes.h"
|
||||||
#include "MouseTypes.h"
|
#include "MouseTypes.h"
|
||||||
#include "OptionTypes.h"
|
#include "OptionTypes.h"
|
||||||
#include "stdmap.h"
|
|
||||||
|
|
||||||
class IClipboard;
|
class IClipboard;
|
||||||
class IPlatformScreen;
|
class IPlatformScreen;
|
||||||
|
@ -30,7 +29,7 @@ class IPlatformScreen;
|
||||||
This is a platform independent screen. It can work as either a
|
This is a platform independent screen. It can work as either a
|
||||||
primary or secondary screen.
|
primary or secondary screen.
|
||||||
*/
|
*/
|
||||||
class CScreen : public IScreen, public IKeyState {
|
class CScreen : public IScreen {
|
||||||
public:
|
public:
|
||||||
CScreen(IPlatformScreen* platformScreen);
|
CScreen(IPlatformScreen* platformScreen);
|
||||||
virtual ~CScreen();
|
virtual ~CScreen();
|
||||||
|
@ -55,9 +54,10 @@ public:
|
||||||
|
|
||||||
//! Enter screen
|
//! 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
|
//! Leave screen
|
||||||
/*!
|
/*!
|
||||||
|
@ -208,6 +208,12 @@ public:
|
||||||
*/
|
*/
|
||||||
void getCursorCenter(SInt32& x, SInt32& y) const;
|
void getCursorCenter(SInt32& x, SInt32& y) const;
|
||||||
|
|
||||||
|
//! Get the active modifiers
|
||||||
|
/*!
|
||||||
|
Returns the modifiers that are currently active.
|
||||||
|
*/
|
||||||
|
KeyModifierMask getActiveModifiers() const;
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
// IScreen overrides
|
// IScreen overrides
|
||||||
|
@ -217,25 +223,6 @@ public:
|
||||||
SInt32& width, SInt32& height) const;
|
SInt32& width, SInt32& height) const;
|
||||||
virtual void getCursorPos(SInt32& x, SInt32& y) 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:
|
protected:
|
||||||
void enablePrimary();
|
void enablePrimary();
|
||||||
void enableSecondary();
|
void enableSecondary();
|
||||||
|
@ -243,35 +230,16 @@ protected:
|
||||||
void disableSecondary();
|
void disableSecondary();
|
||||||
|
|
||||||
void enterPrimary();
|
void enterPrimary();
|
||||||
void enterSecondary();
|
void enterSecondary(KeyModifierMask toggleMask);
|
||||||
void leavePrimary();
|
void leavePrimary();
|
||||||
void leaveSecondary();
|
void leaveSecondary();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Get the modifier mask for the current key state
|
void releaseKeys();
|
||||||
KeyModifierMask getModifierMask() const;
|
void setToggleState(KeyModifierMask);
|
||||||
|
KeyButton isAnyKeyDown() 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;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef std::map<KeyButton, KeyButton> ServerKeyMap;
|
|
||||||
typedef std::map<KeyModifierMask, KeyButtons> MaskToKeys;
|
|
||||||
typedef std::map<KeyButton, KeyModifierMask> KeyToMask;
|
|
||||||
|
|
||||||
// our platform dependent screen
|
// our platform dependent screen
|
||||||
IPlatformScreen* m_screen;
|
IPlatformScreen* m_screen;
|
||||||
|
|
||||||
|
@ -289,26 +257,7 @@ private:
|
||||||
|
|
||||||
// note toggle keys that toggles on up/down (false) or on
|
// note toggle keys that toggles on up/down (false) or on
|
||||||
// transition (true)
|
// transition (true)
|
||||||
bool m_numLockHalfDuplex;
|
KeyModifierMask m_halfDuplex;
|
||||||
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;
|
|
||||||
|
|
||||||
// the toggle key state when this screen was last entered
|
// the toggle key state when this screen was last entered
|
||||||
KeyModifierMask m_toggleKeys;
|
KeyModifierMask m_toggleKeys;
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -17,20 +17,30 @@
|
||||||
|
|
||||||
#include "IInterface.h"
|
#include "IInterface.h"
|
||||||
#include "KeyTypes.h"
|
#include "KeyTypes.h"
|
||||||
#include "CString.h"
|
#include "CEvent.h"
|
||||||
#include "stdvector.h"
|
|
||||||
|
|
||||||
|
//! Key state interface
|
||||||
|
/*!
|
||||||
|
This interface provides access to set and query the keyboard state and
|
||||||
|
to synthesize key events.
|
||||||
|
*/
|
||||||
class IKeyState : public IInterface {
|
class IKeyState : public IInterface {
|
||||||
public:
|
public:
|
||||||
class Keystroke {
|
enum {
|
||||||
public:
|
kNumButtons = 0x200
|
||||||
KeyButton m_key;
|
|
||||||
bool m_press;
|
|
||||||
bool m_repeat;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<Keystroke> Keystrokes;
|
//! Key event data
|
||||||
typedef std::vector<KeyButton> KeyButtons;
|
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
|
//! @name manipulators
|
||||||
//@{
|
//@{
|
||||||
|
@ -42,79 +52,52 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual void updateKeys() = 0;
|
virtual void updateKeys() = 0;
|
||||||
|
|
||||||
//! Release fake pressed keys
|
//! Set half-duplex mask
|
||||||
/*!
|
/*!
|
||||||
Send fake key events to release keys that aren't physically pressed
|
Sets which modifier toggle keys are half-duplex. A half-duplex
|
||||||
but are logically pressed.
|
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
|
Synthesizes a key repeat event and updates the key state.
|
||||||
toggled on.
|
|
||||||
*/
|
*/
|
||||||
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
|
Synthesizes a key release event and updates the key state.
|
||||||
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.
|
|
||||||
*/
|
*/
|
||||||
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
|
//! @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
|
//! Test if key is pressed
|
||||||
/*!
|
/*!
|
||||||
Returns true iff the given key is down. Half-duplex toggles
|
Returns true iff the given key is down. Half-duplex toggles
|
||||||
should always return false.
|
always return false.
|
||||||
*/
|
*/
|
||||||
virtual bool isKeyDown(KeyButton) const = 0;
|
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
|
//! Get the active modifiers
|
||||||
/*!
|
/*!
|
||||||
Returns the modifiers that are currently active.
|
Returns the modifiers that are currently active.
|
||||||
|
@ -122,35 +105,25 @@ public:
|
||||||
virtual KeyModifierMask
|
virtual KeyModifierMask
|
||||||
getActiveModifiers() const = 0;
|
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)
|
Return a string describing the given key.
|
||||||
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.
|
|
||||||
*/
|
*/
|
||||||
virtual bool mapModifier(Keystrokes& keys, Keystrokes& undo,
|
virtual const char* getKeyName(KeyButton) const = 0;
|
||||||
KeyModifierMask mask, bool desireActive) const = 0;
|
|
||||||
|
|
||||||
//! Get modifier mask for key
|
//! Get key down event type. Event data is CKeyInfo*, count == 1.
|
||||||
/*!
|
static CEvent::Type getKeyDownEvent();
|
||||||
Returns the modifier mask for \c key. If \c key is not a modifier
|
//! Get key up event type. Event data is CKeyInfo*, count == 1.
|
||||||
key then returns 0.
|
static CEvent::Type getKeyUpEvent();
|
||||||
*/
|
//! Get key repeat event type. Event data is CKeyInfo*.
|
||||||
virtual KeyModifierMask
|
static CEvent::Type getKeyRepeatEvent();
|
||||||
getMaskForKey(KeyButton) const = 0;
|
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
protected:
|
private:
|
||||||
typedef UInt8 KeyState;
|
static CEvent::Type s_keyDownEvent;
|
||||||
enum EKeyState {
|
static CEvent::Type s_keyUpEvent;
|
||||||
kDown = 0x01, //!< Key is down
|
static CEvent::Type s_keyRepeatEvent;
|
||||||
kToggled = 0x80 //!< Key is toggled on
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -18,11 +18,11 @@
|
||||||
#include "IScreen.h"
|
#include "IScreen.h"
|
||||||
#include "IPrimaryScreen.h"
|
#include "IPrimaryScreen.h"
|
||||||
#include "ISecondaryScreen.h"
|
#include "ISecondaryScreen.h"
|
||||||
|
#include "IKeyState.h"
|
||||||
#include "ClipboardTypes.h"
|
#include "ClipboardTypes.h"
|
||||||
#include "OptionTypes.h"
|
#include "OptionTypes.h"
|
||||||
|
|
||||||
class IClipboard;
|
class IClipboard;
|
||||||
class IKeyState;
|
|
||||||
|
|
||||||
//! Screen interface
|
//! Screen interface
|
||||||
/*!
|
/*!
|
||||||
|
@ -31,18 +31,12 @@ screen implementations that are used by both primary and secondary
|
||||||
screens.
|
screens.
|
||||||
*/
|
*/
|
||||||
class IPlatformScreen : public IScreen,
|
class IPlatformScreen : public IScreen,
|
||||||
public IPrimaryScreen, public ISecondaryScreen {
|
public IPrimaryScreen, public ISecondaryScreen,
|
||||||
|
public IKeyState {
|
||||||
public:
|
public:
|
||||||
//! @name manipulators
|
//! @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 screen
|
||||||
/*!
|
/*!
|
||||||
Enable the screen, preparing it to report system and user events.
|
Enable the screen, preparing it to report system and user events.
|
||||||
|
@ -124,13 +118,6 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual void setOptions(const COptionsList& options) = 0;
|
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
|
//! Set clipboard sequence number
|
||||||
/*!
|
/*!
|
||||||
Sets the sequence number to use in subsequent clipboard events.
|
Sets the sequence number to use in subsequent clipboard events.
|
||||||
|
@ -161,20 +148,27 @@ public:
|
||||||
virtual void warpCursor(SInt32 x, SInt32 y) = 0;
|
virtual void warpCursor(SInt32 x, SInt32 y) = 0;
|
||||||
virtual SInt32 getJumpZoneSize() const = 0;
|
virtual SInt32 getJumpZoneSize() const = 0;
|
||||||
virtual bool isAnyMouseButtonDown() const = 0;
|
virtual bool isAnyMouseButtonDown() const = 0;
|
||||||
virtual KeyModifierMask getActiveModifiers() const = 0;
|
|
||||||
virtual void getCursorCenter(SInt32& x, SInt32& y) const = 0;
|
virtual void getCursorCenter(SInt32& x, SInt32& y) const = 0;
|
||||||
virtual const char* getKeyName(KeyButton) const = 0;
|
|
||||||
|
|
||||||
// ISecondaryScreen overrides
|
// ISecondaryScreen overrides
|
||||||
virtual void fakeKeyEvent(KeyButton id, bool press) const = 0;
|
|
||||||
virtual bool fakeCtrlAltDel() const = 0;
|
virtual bool fakeCtrlAltDel() const = 0;
|
||||||
virtual void fakeMouseButton(ButtonID id, bool press) const = 0;
|
virtual void fakeMouseButton(ButtonID id, bool press) const = 0;
|
||||||
virtual void fakeMouseMove(SInt32 x, SInt32 y) const = 0;
|
virtual void fakeMouseMove(SInt32 x, SInt32 y) const = 0;
|
||||||
virtual void fakeMouseWheel(SInt32 delta) const = 0;
|
virtual void fakeMouseWheel(SInt32 delta) const = 0;
|
||||||
virtual KeyButton mapKey(IKeyState::Keystrokes&,
|
|
||||||
const IKeyState& keyState, KeyID id,
|
// IKeyState overrides
|
||||||
KeyModifierMask desiredMask,
|
virtual void updateKeys() = 0;
|
||||||
bool isAutoRepeat) const = 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:
|
protected:
|
||||||
//! Handle system event
|
//! Handle system event
|
||||||
|
@ -193,10 +187,10 @@ protected:
|
||||||
|
|
||||||
A primary screen has further responsibilities. It should post
|
A primary screen has further responsibilities. It should post
|
||||||
the events in \c IPrimaryScreen as appropriate. It should also
|
the events in \c IPrimaryScreen as appropriate. It should also
|
||||||
call \c setKeyDown() on the \c IKeyState passed to \c setKeyState()
|
call \c setKeyDown() on its \c CKeyState whenever a key is pressed
|
||||||
whenever a key is pressed or released (but not for key repeats).
|
or released (but not for key repeats). And it should call
|
||||||
And it should call \c updateKeys() on the \c IKeyState if necessary
|
\c updateKeys() on its \c CKeyState if necessary when the keyboard
|
||||||
when the keyboard mapping changes.
|
mapping changes.
|
||||||
|
|
||||||
The target of all events should be the value returned by
|
The target of all events should be the value returned by
|
||||||
\c getEventTarget().
|
\c getEventTarget().
|
||||||
|
|
|
@ -18,9 +18,6 @@
|
||||||
// IPrimaryScreen
|
// 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_buttonDownEvent = CEvent::kUnknown;
|
||||||
CEvent::Type IPrimaryScreen::s_buttonUpEvent = CEvent::kUnknown;
|
CEvent::Type IPrimaryScreen::s_buttonUpEvent = CEvent::kUnknown;
|
||||||
CEvent::Type IPrimaryScreen::s_motionPrimaryEvent = 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_ssActivatedEvent = CEvent::kUnknown;
|
||||||
CEvent::Type IPrimaryScreen::s_ssDeactivatedEvent = 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
|
CEvent::Type
|
||||||
IPrimaryScreen::getButtonDownEvent()
|
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
|
// IPrimaryScreen::CButtonInfo
|
||||||
//
|
//
|
||||||
|
|
|
@ -16,9 +16,8 @@
|
||||||
#define IPRIMARYSCREEN_H
|
#define IPRIMARYSCREEN_H
|
||||||
|
|
||||||
#include "IInterface.h"
|
#include "IInterface.h"
|
||||||
#include "IKeyState.h"
|
|
||||||
#include "CEvent.h"
|
|
||||||
#include "MouseTypes.h"
|
#include "MouseTypes.h"
|
||||||
|
#include "CEvent.h"
|
||||||
|
|
||||||
//! Primary screen interface
|
//! Primary screen interface
|
||||||
/*!
|
/*!
|
||||||
|
@ -27,17 +26,6 @@ primary screen implementations.
|
||||||
*/
|
*/
|
||||||
class IPrimaryScreen : public IInterface {
|
class IPrimaryScreen : public IInterface {
|
||||||
public:
|
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
|
//! Button event data
|
||||||
class CButtonInfo {
|
class CButtonInfo {
|
||||||
public:
|
public:
|
||||||
|
@ -103,14 +91,6 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual bool isAnyMouseButtonDown() const = 0;
|
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
|
//! Get cursor center position
|
||||||
/*!
|
/*!
|
||||||
Return the cursor center position which is where we park the
|
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;
|
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*.
|
//! Get button down event type. Event data is CButtonInfo*.
|
||||||
static CEvent::Type getButtonDownEvent();
|
static CEvent::Type getButtonDownEvent();
|
||||||
//! Get button up event type. Event data is CButtonInfo*.
|
//! Get button up event type. Event data is CButtonInfo*.
|
||||||
|
@ -156,9 +124,6 @@ public:
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
private:
|
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_buttonDownEvent;
|
||||||
static CEvent::Type s_buttonUpEvent;
|
static CEvent::Type s_buttonUpEvent;
|
||||||
static CEvent::Type s_motionPrimaryEvent;
|
static CEvent::Type s_motionPrimaryEvent;
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
#define ISECONDARYSCREEN_H
|
#define ISECONDARYSCREEN_H
|
||||||
|
|
||||||
#include "IInterface.h"
|
#include "IInterface.h"
|
||||||
#include "IKeyState.h"
|
|
||||||
#include "MouseTypes.h"
|
#include "MouseTypes.h"
|
||||||
|
|
||||||
//! Secondary screen interface
|
//! Secondary screen interface
|
||||||
|
@ -29,12 +28,6 @@ public:
|
||||||
//! @name accessors
|
//! @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
|
//! Fake ctrl+alt+del
|
||||||
/*!
|
/*!
|
||||||
Synthesize a press of ctrl+alt+del. Return true if processing is
|
Synthesize a press of ctrl+alt+del. Return true if processing is
|
||||||
|
@ -60,22 +53,6 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual void fakeMouseWheel(SInt32 delta) const = 0;
|
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;
|
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -26,16 +26,21 @@ MAINTAINERCLEANFILES = \
|
||||||
noinst_LIBRARIES = libsynergy.a
|
noinst_LIBRARIES = libsynergy.a
|
||||||
libsynergy_a_SOURCES = \
|
libsynergy_a_SOURCES = \
|
||||||
CClipboard.cpp \
|
CClipboard.cpp \
|
||||||
|
CKeyState.cpp \
|
||||||
CPacketStreamFilter.cpp \
|
CPacketStreamFilter.cpp \
|
||||||
|
CPlatformScreen.cpp \
|
||||||
CProtocolUtil.cpp \
|
CProtocolUtil.cpp \
|
||||||
CScreen.cpp \
|
CScreen.cpp \
|
||||||
IClipboard.cpp \
|
IClipboard.cpp \
|
||||||
|
IKeyState.cpp \
|
||||||
IPrimaryScreen.cpp \
|
IPrimaryScreen.cpp \
|
||||||
IScreen.cpp \
|
IScreen.cpp \
|
||||||
XScreen.cpp \
|
XScreen.cpp \
|
||||||
XSynergy.cpp \
|
XSynergy.cpp \
|
||||||
CClipboard.h \
|
CClipboard.h \
|
||||||
|
CKeyState.h \
|
||||||
CPacketStreamFilter.h \
|
CPacketStreamFilter.h \
|
||||||
|
CPlatformScreen.h \
|
||||||
CProtocolUtil.h \
|
CProtocolUtil.h \
|
||||||
CScreen.h \
|
CScreen.h \
|
||||||
ClipboardTypes.h \
|
ClipboardTypes.h \
|
||||||
|
|
Loading…
Reference in New Issue