Checkpoint refactoring. CSecondaryScreen now does the work common
across platform secondary screens. X11 screen was compiled and tested but not the win23 screen. Will next change inheritance hierarchy.
This commit is contained in:
parent
e725270c00
commit
221628fd84
File diff suppressed because it is too large
Load Diff
|
@ -25,8 +25,6 @@
|
|||
#include "IMSWindowsScreenEventHandler.h"
|
||||
#include "CMutex.h"
|
||||
#include "CString.h"
|
||||
#include "stdmap.h"
|
||||
#include "stdvector.h"
|
||||
|
||||
class CMSWindowsScreen;
|
||||
class IScreenReceiver;
|
||||
|
@ -39,16 +37,6 @@ public:
|
|||
virtual ~CMSWindowsSecondaryScreen();
|
||||
|
||||
// CSecondaryScreen overrides
|
||||
virtual void keyDown(KeyID, KeyModifierMask, KeyButton);
|
||||
virtual void keyRepeat(KeyID, KeyModifierMask,
|
||||
SInt32 count, KeyButton);
|
||||
virtual void keyUp(KeyID, KeyModifierMask, KeyButton);
|
||||
virtual void mouseDown(ButtonID);
|
||||
virtual void mouseUp(ButtonID);
|
||||
virtual void mouseMove(SInt32 xAbsolute, SInt32 yAbsolute);
|
||||
virtual void mouseWheel(SInt32 delta);
|
||||
virtual void resetOptions();
|
||||
virtual void setOptions(const COptionsList& options);
|
||||
virtual IScreen* getScreen() const;
|
||||
|
||||
// IMSWindowsScreenEventHandler overrides
|
||||
|
@ -56,7 +44,6 @@ public:
|
|||
virtual bool onPreDispatch(const CEvent* event);
|
||||
virtual bool onEvent(CEvent* event);
|
||||
virtual void onOneShotTimerExpired(UInt32 id);
|
||||
virtual SInt32 getJumpZoneSize() const;
|
||||
virtual void postCreateWindow(HWND);
|
||||
virtual void preDestroyWindow(HWND);
|
||||
virtual void onAccessibleDesktop();
|
||||
|
@ -71,20 +58,26 @@ protected:
|
|||
virtual void destroyWindow();
|
||||
virtual void showWindow(SInt32 x, SInt32 y);
|
||||
virtual void hideWindow();
|
||||
virtual void warpCursor(SInt32 x, SInt32 y);
|
||||
virtual void updateKeys();
|
||||
virtual void releaseKeys();
|
||||
virtual void setToggleState(KeyModifierMask);
|
||||
virtual KeyModifierMask getToggleState() const;
|
||||
virtual void updateKeys(KeyState* sysKeyStates);
|
||||
virtual KeyModifierMask getModifiers() const;
|
||||
|
||||
virtual SysKeyID getUnhanded(SysKeyID) const;
|
||||
virtual SysKeyID getOtherHanded(SysKeyID) const;
|
||||
virtual bool isAutoRepeating(SysKeyID) const;
|
||||
virtual KeyModifierMask getModifierKeyMask(SysKeyID) const;
|
||||
virtual bool isModifierActive(SysKeyID) const;
|
||||
virtual SysKeyID getToggleSysKey(KeyID keyID) const;
|
||||
virtual bool synthesizeCtrlAltDel(EKeyAction);
|
||||
virtual void sync() const;
|
||||
virtual KeyModifierMask
|
||||
mapKey(Keystrokes&, SysKeyID& sysKeyID, KeyID,
|
||||
KeyModifierMask, KeyModifierMask, EKeyAction) const;
|
||||
virtual void fakeKeyEvent(SysKeyID, bool press) const;
|
||||
virtual void fakeMouseButton(ButtonID, bool press) const;
|
||||
virtual void fakeMouseMove(SInt32 x, SInt32 y) const;
|
||||
virtual void fakeMouseWheel(SInt32 delta) const;
|
||||
|
||||
private:
|
||||
enum EKeyAction { kPress, kRelease, kRepeat };
|
||||
class Keystroke {
|
||||
public:
|
||||
UINT m_virtualKey;
|
||||
bool m_press;
|
||||
bool m_repeat;
|
||||
};
|
||||
class CModifierInfo {
|
||||
public:
|
||||
KeyModifierMask m_mask;
|
||||
|
@ -92,8 +85,6 @@ private:
|
|||
UINT m_virtualKey2;
|
||||
bool m_isToggle;
|
||||
};
|
||||
typedef std::vector<Keystroke> Keystrokes;
|
||||
typedef std::map<KeyButton, UINT> ServerKeyMap;
|
||||
|
||||
// open/close desktop (for windows 95/98/me)
|
||||
bool openDesktop();
|
||||
|
@ -108,9 +99,6 @@ private:
|
|||
// key and button queries and operations
|
||||
DWORD mapButton(ButtonID button,
|
||||
bool press, DWORD* data) const;
|
||||
KeyModifierMask mapKey(Keystrokes&, UINT& virtualKey, KeyID,
|
||||
KeyModifierMask, EKeyAction) const;
|
||||
KeyModifierMask mapKeyRelease(Keystrokes& keys, UINT virtualKey) const;
|
||||
UINT mapCharacter(Keystrokes& keys,
|
||||
char c, HKL hkl,
|
||||
KeyModifierMask currentMask,
|
||||
|
@ -121,19 +109,14 @@ private:
|
|||
KeyModifierMask currentMask,
|
||||
KeyModifierMask desiredMask,
|
||||
EKeyAction action) const;
|
||||
void doKeystrokes(const Keystrokes&, SInt32 count);
|
||||
const CModifierInfo* getModifierInfo(UINT virtualKey) const;
|
||||
|
||||
void toggleKey(UINT virtualKey, KeyModifierMask mask);
|
||||
KeyState getKeyState(UINT virtualKey) const;
|
||||
UINT virtualKeyToScanCode(UINT& virtualKey) const;
|
||||
bool isExtendedKey(UINT virtualKey) const;
|
||||
void sendKeyEvent(UINT virtualKey, bool press);
|
||||
|
||||
UINT getCodePageFromLangID(LANGID) const;
|
||||
|
||||
// generate a fake ctrl+alt+del
|
||||
void synthesizeCtrlAltDel();
|
||||
|
||||
// thread that generates fake ctrl+alt+del
|
||||
static void ctrlAltDelThread(void*);
|
||||
|
||||
|
@ -147,18 +130,6 @@ private:
|
|||
// our window
|
||||
HWND m_window;
|
||||
|
||||
// virtual key states as set by us or the user
|
||||
BYTE m_keys[256];
|
||||
|
||||
// virtual key states as set by us
|
||||
BYTE m_fakeKeys[256];
|
||||
|
||||
// current active modifiers
|
||||
KeyModifierMask m_mask;
|
||||
|
||||
// map server key buttons to local virtual keys
|
||||
ServerKeyMap m_serverKeyMap;
|
||||
|
||||
// modifier table
|
||||
static const CModifierInfo s_modifier[];
|
||||
};
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -17,7 +17,6 @@
|
|||
|
||||
#include "CSecondaryScreen.h"
|
||||
#include "IScreenEventHandler.h"
|
||||
#include "stdbitset.h"
|
||||
#include "stdmap.h"
|
||||
#include "stdvector.h"
|
||||
#if defined(X_DISPLAY_MISSING)
|
||||
|
@ -37,14 +36,6 @@ public:
|
|||
virtual ~CXWindowsSecondaryScreen();
|
||||
|
||||
// CSecondaryScreen overrides
|
||||
virtual void keyDown(KeyID, KeyModifierMask, KeyButton);
|
||||
virtual void keyRepeat(KeyID, KeyModifierMask,
|
||||
SInt32 count, KeyButton);
|
||||
virtual void keyUp(KeyID, KeyModifierMask, KeyButton);
|
||||
virtual void mouseDown(ButtonID);
|
||||
virtual void mouseUp(ButtonID);
|
||||
virtual void mouseMove(SInt32 x, SInt32 y);
|
||||
virtual void mouseWheel(SInt32 delta);
|
||||
virtual void resetOptions();
|
||||
virtual void setOptions(const COptionsList& options);
|
||||
virtual IScreen* getScreen() const;
|
||||
|
@ -54,7 +45,6 @@ public:
|
|||
virtual bool onPreDispatch(const CEvent* event);
|
||||
virtual bool onEvent(CEvent* event);
|
||||
virtual void onOneShotTimerExpired(UInt32 id);
|
||||
virtual SInt32 getJumpZoneSize() const;
|
||||
|
||||
protected:
|
||||
// CSecondaryScreen overrides
|
||||
|
@ -69,22 +59,24 @@ protected:
|
|||
virtual void destroyWindow();
|
||||
virtual void showWindow(SInt32 x, SInt32 y);
|
||||
virtual void hideWindow();
|
||||
virtual void warpCursor(SInt32 x, SInt32 y);
|
||||
virtual void updateKeys();
|
||||
virtual void releaseKeys();
|
||||
virtual void setToggleState(KeyModifierMask);
|
||||
virtual KeyModifierMask getToggleState() const;
|
||||
virtual void updateKeys(KeyState* sysKeyStates);
|
||||
virtual KeyModifierMask getModifiers() const;
|
||||
|
||||
virtual bool isAutoRepeating(SysKeyID) const;
|
||||
virtual KeyModifierMask getModifierKeyMask(SysKeyID) const;
|
||||
virtual bool isModifierActive(SysKeyID) const;
|
||||
virtual SysKeyID getToggleSysKey(KeyID keyID) const;
|
||||
virtual void flush();
|
||||
virtual KeyModifierMask
|
||||
mapKey(Keystrokes&, SysKeyID& sysKeyID, KeyID,
|
||||
KeyModifierMask, KeyModifierMask, EKeyAction) const;
|
||||
virtual void fakeKeyEvent(SysKeyID, bool press) const;
|
||||
virtual void fakeMouseButton(ButtonID, bool press) const;
|
||||
virtual void fakeMouseMove(SInt32 x, SInt32 y) const;
|
||||
virtual void fakeMouseWheel(SInt32 delta) const;
|
||||
|
||||
private:
|
||||
enum EKeyAction { kPress, kRelease, kRepeat };
|
||||
typedef unsigned int ModifierIndex;
|
||||
typedef unsigned int ModifierMask;
|
||||
class Keystroke {
|
||||
public:
|
||||
KeyCode m_keycode;
|
||||
Bool m_press;
|
||||
bool m_repeat;
|
||||
};
|
||||
class KeyMapping {
|
||||
public:
|
||||
KeyMapping();
|
||||
|
@ -97,7 +89,7 @@ private:
|
|||
bool m_modeSwitchSensitive[4];
|
||||
|
||||
// the modifier mask of keysym or 0 if not a modifier
|
||||
ModifierMask m_modifierMask;
|
||||
KeyModifierMask m_modifierMask;
|
||||
|
||||
// whether keysym is sensitive to caps and num lock
|
||||
bool m_numLockSensitive;
|
||||
|
@ -108,50 +100,40 @@ private:
|
|||
typedef std::map<KeyCode, ModifierIndex> KeyCodeToModifierMap;
|
||||
typedef std::map<KeySym, KeyMapping> KeySymMap;
|
||||
typedef KeySymMap::const_iterator KeySymIndex;
|
||||
typedef std::vector<Keystroke> Keystrokes;
|
||||
typedef std::vector<KeySym> KeySyms;
|
||||
typedef std::map<KeySym, KeySyms> KeySymsMap;
|
||||
typedef std::map<KeyButton, KeyCode> ServerKeyMap;
|
||||
|
||||
void flush(Display*) const;
|
||||
|
||||
unsigned int mapButton(ButtonID button) const;
|
||||
|
||||
ModifierMask mapKey(Keystrokes&, KeyCode&, KeyID,
|
||||
KeyModifierMask, EKeyAction) const;
|
||||
ModifierMask mapKeyRelease(Keystrokes&, KeyCode) const;
|
||||
bool mapToKeystrokes(Keystrokes& keys,
|
||||
KeyCode& keycode,
|
||||
ModifierMask& finalMask,
|
||||
SysKeyID& keycode,
|
||||
KeyModifierMask& finalMask,
|
||||
KeySymIndex keyIndex,
|
||||
ModifierMask currentMask,
|
||||
EKeyAction action) const;
|
||||
KeyModifierMask currentMask,
|
||||
EKeyAction action,
|
||||
bool isHalfDuplex) const;
|
||||
bool adjustModifiers(Keystrokes& keys,
|
||||
Keystrokes& undo,
|
||||
ModifierMask& inOutMask,
|
||||
ModifierMask desiredMask) const;
|
||||
KeyModifierMask& inOutMask,
|
||||
KeyModifierMask desiredMask) const;
|
||||
bool adjustModifier(Keystrokes& keys,
|
||||
Keystrokes& undo,
|
||||
KeySym keysym,
|
||||
bool desireActive) const;
|
||||
void doKeystrokes(const Keystrokes&, SInt32 count);
|
||||
ModifierMask maskToX(KeyModifierMask) const;
|
||||
KeyModifierMask mapToModifierMask(ModifierIndex, KeySym) const;
|
||||
|
||||
unsigned int findBestKeyIndex(KeySymIndex keyIndex,
|
||||
ModifierMask currentMask) const;
|
||||
KeyModifierMask currentMask) const;
|
||||
bool isShiftInverted(KeySymIndex keyIndex,
|
||||
ModifierMask currentMask) const;
|
||||
ModifierMask getModifierMask(KeySym) const;
|
||||
KeyModifierMask currentMask) const;
|
||||
|
||||
void doUpdateKeys(Display*);
|
||||
void doReleaseKeys(Display*);
|
||||
void updateKeysymMap(Display* display);
|
||||
void updateModifiers(Display* display);
|
||||
ModifierIndex keySymToModifierIndex(KeySym) const;
|
||||
void toggleKey(Display*, KeySym, ModifierMask mask);
|
||||
static bool isToggleKeysym(KeySym);
|
||||
|
||||
KeySym keyIDToKeySym(KeyID id, ModifierMask mask) const;
|
||||
KeySym keyIDToKeySym(KeyID id, KeyModifierMask mask) const;
|
||||
bool adjustForNumLock(KeySym) const;
|
||||
bool adjustForCapsLock(KeySym) const;
|
||||
|
||||
|
@ -163,31 +145,15 @@ private:
|
|||
CXWindowsScreen* m_screen;
|
||||
Window m_window;
|
||||
|
||||
// note toggle keys that toggles on up/down (false) or on
|
||||
// transition (true)
|
||||
bool m_numLockHalfDuplex;
|
||||
bool m_capsLockHalfDuplex;
|
||||
|
||||
// set entries indicate keys that are pressed (by us or by the user).
|
||||
// indexed by keycode.
|
||||
std::bitset<256> m_keys;
|
||||
|
||||
// set entries indicate keys that are synthetically pressed by us.
|
||||
// this is normally the same as m_keys.
|
||||
std::bitset<256> m_fakeKeys;
|
||||
|
||||
// logical to physical button mapping. m_buttons[i] gives the
|
||||
// physical button for logical button i+1.
|
||||
std::vector<unsigned char> m_buttons;
|
||||
|
||||
// current active modifiers (X key masks)
|
||||
ModifierMask m_mask;
|
||||
|
||||
// the modifiers that have keys bound to them
|
||||
ModifierMask m_modifierMask;
|
||||
KeyModifierMask m_modifierMask;
|
||||
|
||||
// set bits indicate modifiers that toggle (e.g. caps-lock)
|
||||
ModifierMask m_toggleModifierMask;
|
||||
KeyModifierMask m_toggleModifierMask;
|
||||
|
||||
// keysym to keycode mapping
|
||||
KeySymMap m_keysymMap;
|
||||
|
@ -195,6 +161,9 @@ private:
|
|||
// modifier index to keycodes
|
||||
KeyCodes m_modifierKeycodes[8];
|
||||
|
||||
// modifier index to modifier mask
|
||||
KeyModifierMask m_modifierIndexToMask[8];
|
||||
|
||||
// keycode to modifier index
|
||||
KeyCodeToModifierMap m_keycodeToModifier;
|
||||
|
||||
|
@ -209,20 +178,6 @@ private:
|
|||
KeySym m_capsLockKeysym;
|
||||
KeySym m_scrollLockKeysym;
|
||||
|
||||
// modifier masks
|
||||
ModifierMask m_shiftMask;
|
||||
ModifierMask m_ctrlMask;
|
||||
ModifierMask m_altMask;
|
||||
ModifierMask m_metaMask;
|
||||
ModifierMask m_superMask;
|
||||
ModifierMask m_modeSwitchMask;
|
||||
ModifierMask m_numLockMask;
|
||||
ModifierMask m_capsLockMask;
|
||||
ModifierMask m_scrollLockMask;
|
||||
|
||||
// map server key buttons to local keycodes
|
||||
ServerKeyMap m_serverKeyMap;
|
||||
|
||||
// the keyboard control state the last time this screen was entered
|
||||
XKeyboardState m_keyControl;
|
||||
|
||||
|
|
|
@ -50,7 +50,6 @@ public:
|
|||
virtual void onScreensaver(bool activated) = 0;
|
||||
virtual bool onPreDispatch(const CEvent* event) = 0;
|
||||
virtual bool onEvent(CEvent* event) = 0;
|
||||
virtual SInt32 getJumpZoneSize() const = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -116,7 +116,10 @@ CSecondaryScreen::remoteControl()
|
|||
}
|
||||
|
||||
// update keyboard state
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
updateKeys();
|
||||
}
|
||||
|
||||
// now remote ready. fake being active for call to leave().
|
||||
bool screenSaverSync;
|
||||
|
@ -156,7 +159,7 @@ CSecondaryScreen::enter(SInt32 x, SInt32 y, KeyModifierMask mask)
|
|||
|
||||
LOG((CLOG_INFO "entering screen at %d,%d mask=%04x", x, y, mask));
|
||||
|
||||
getScreen()->syncDesktop();
|
||||
sync();
|
||||
|
||||
// now active
|
||||
m_active = true;
|
||||
|
@ -167,14 +170,13 @@ CSecondaryScreen::enter(SInt32 x, SInt32 y, KeyModifierMask mask)
|
|||
// update our keyboard state to reflect the local state
|
||||
updateKeys();
|
||||
|
||||
// remember toggle key state
|
||||
m_toggleKeys = getToggleState();
|
||||
|
||||
// toggle modifiers that don't match the desired state
|
||||
// toggle modifiers that don't match the desired state and
|
||||
// remember previous toggle key state.
|
||||
m_toggleKeys = m_mask;
|
||||
setToggleState(mask);
|
||||
|
||||
// warp to requested location
|
||||
warpCursor(x, y);
|
||||
fakeMouseMove(x, y);
|
||||
|
||||
// show mouse
|
||||
hideWindow();
|
||||
|
@ -190,7 +192,7 @@ CSecondaryScreen::leave()
|
|||
CLock lock(&m_mutex);
|
||||
assert(m_active == true);
|
||||
|
||||
getScreen()->syncDesktop();
|
||||
sync();
|
||||
|
||||
// subclass hook
|
||||
onPreLeave();
|
||||
|
@ -198,7 +200,7 @@ CSecondaryScreen::leave()
|
|||
// restore toggle key state
|
||||
setToggleState(m_toggleKeys);
|
||||
|
||||
// warp and hide mouse
|
||||
// hide mouse
|
||||
SInt32 x, y;
|
||||
getScreen()->getCursorCenter(x, y);
|
||||
showWindow(x, y);
|
||||
|
@ -242,16 +244,314 @@ CSecondaryScreen::screensaver(bool activate)
|
|||
}
|
||||
}
|
||||
|
||||
CSecondaryScreen::SysKeyID
|
||||
CSecondaryScreen::getUnhanded(SysKeyID) const
|
||||
{
|
||||
// no key represents both left and right sides of any key
|
||||
return 0;
|
||||
}
|
||||
|
||||
CSecondaryScreen::SysKeyID
|
||||
CSecondaryScreen::getOtherHanded(SysKeyID) const
|
||||
{
|
||||
// no key represents both left and right sides of any key
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
CSecondaryScreen::synthesizeCtrlAltDel(EKeyAction)
|
||||
{
|
||||
// pass keys through unchanged
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::sync() const
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::flush()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::doKeystrokes(const Keystrokes& keys, SInt32 count)
|
||||
{
|
||||
// do nothing if no keys or no repeats
|
||||
if (count < 1 || keys.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// generate key events
|
||||
LOG((CLOG_DEBUG2 "keystrokes:"));
|
||||
for (Keystrokes::const_iterator k = keys.begin(); k != keys.end(); ) {
|
||||
if (k->m_repeat) {
|
||||
// repeat from here up to but not including the next key
|
||||
// with m_repeat == false count times.
|
||||
Keystrokes::const_iterator start = k;
|
||||
for (; count > 0; --count) {
|
||||
// send repeating events
|
||||
for (k = start; k != keys.end() && k->m_repeat; ++k) {
|
||||
LOG((CLOG_DEBUG2 " %d %s repeat", k->m_sysKeyID, k->m_press ? "down" : "up"));
|
||||
fakeKeyEvent(k->m_sysKeyID, k->m_press);
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
LOG((CLOG_DEBUG2 " %d %s", k->m_sysKeyID, k->m_press ? "down" : "up"));
|
||||
fakeKeyEvent(k->m_sysKeyID, k->m_press);
|
||||
|
||||
// next key
|
||||
++k;
|
||||
}
|
||||
}
|
||||
|
||||
flush();
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::keyDown(KeyID key,
|
||||
KeyModifierMask mask, KeyButton button)
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
sync();
|
||||
|
||||
// check for ctrl+alt+del emulation
|
||||
if (key == kKeyDelete &&
|
||||
(mask & (KeyModifierControl | KeyModifierAlt)) ==
|
||||
(KeyModifierControl | KeyModifierAlt)) {
|
||||
LOG((CLOG_DEBUG "emulating ctrl+alt+del press"));
|
||||
if (synthesizeCtrlAltDel(kPress)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// get the sequence of keys to simulate key press and the final
|
||||
// modifier state.
|
||||
Keystrokes keys;
|
||||
SysKeyID sysKeyID;
|
||||
m_mask = mapKey(keys, sysKeyID, key, m_mask, mask, kPress);
|
||||
if (keys.empty()) {
|
||||
// do nothing if there are no associated keys (i.e. lookup failed)
|
||||
return;
|
||||
}
|
||||
sysKeyID &= 0xffu;
|
||||
|
||||
// generate key events
|
||||
doKeystrokes(keys, 1);
|
||||
|
||||
// do not record button down if button or system key is 0 (invalid)
|
||||
if (button != 0 && sysKeyID != 0) {
|
||||
// note that key is now down
|
||||
SysKeyID unhandedSysKeyID = getUnhanded(sysKeyID);
|
||||
m_serverKeyMap[button] = sysKeyID;
|
||||
m_keys[sysKeyID] |= kDown;
|
||||
m_fakeKeys[sysKeyID] |= kDown;
|
||||
if (unhandedSysKeyID != 0) {
|
||||
m_keys[unhandedSysKeyID] |= kDown;
|
||||
m_fakeKeys[unhandedSysKeyID] |= kDown;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CSecondaryScreen::keyRepeat(KeyID key,
|
||||
KeyModifierMask mask, SInt32 count, KeyButton button)
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
sync();
|
||||
|
||||
// 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;
|
||||
SysKeyID sysKeyID;
|
||||
m_mask = mapKey(keys, sysKeyID, key, m_mask, mask, kRepeat);
|
||||
if (keys.empty()) {
|
||||
return;
|
||||
}
|
||||
sysKeyID &= 0xffu;
|
||||
|
||||
// if this key shouldn't auto-repeat then ignore
|
||||
if (!isAutoRepeating(sysKeyID)) {
|
||||
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 (sysKeyID != 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_sysKeyID & 0xffu) == sysKeyID) {
|
||||
index2->m_sysKeyID = 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 = sysKeyID;
|
||||
|
||||
// note that new key is now down
|
||||
m_keys[index->second] |= kDown;
|
||||
m_fakeKeys[index->second] |= kDown;
|
||||
}
|
||||
|
||||
// generate key events
|
||||
doKeystrokes(keys, count);
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::keyUp(KeyID key, KeyModifierMask mask, KeyButton button)
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
sync();
|
||||
|
||||
// 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;
|
||||
}
|
||||
SysKeyID sysKeyID = index->second;
|
||||
|
||||
// check for ctrl+alt+del emulation
|
||||
if (key == kKeyDelete &&
|
||||
(mask & (KeyModifierControl | KeyModifierAlt)) ==
|
||||
(KeyModifierControl | KeyModifierAlt)) {
|
||||
LOG((CLOG_DEBUG "emulating ctrl+alt+del release"));
|
||||
if (synthesizeCtrlAltDel(kRelease)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// get the sequence of keys to simulate key release
|
||||
Keystrokes keys;
|
||||
Keystroke keystroke;
|
||||
keystroke.m_sysKeyID = sysKeyID;
|
||||
keystroke.m_press = false;
|
||||
keystroke.m_repeat = false;
|
||||
keys.push_back(keystroke);
|
||||
|
||||
// generate key events
|
||||
doKeystrokes(keys, 1);
|
||||
|
||||
// note that key is now up
|
||||
SysKeyID unhandedSysKeyID = getUnhanded(sysKeyID);
|
||||
m_serverKeyMap.erase(index);
|
||||
m_keys[sysKeyID] &= ~kDown;
|
||||
m_fakeKeys[sysKeyID] &= ~kDown;
|
||||
if (unhandedSysKeyID != 0) {
|
||||
SysKeyID otherHandedSysKeyID = getOtherHanded(sysKeyID);
|
||||
if ((m_keys[otherHandedSysKeyID] & kDown) == 0) {
|
||||
m_keys[unhandedSysKeyID] &= ~kDown;
|
||||
m_fakeKeys[unhandedSysKeyID] &= ~kDown;
|
||||
}
|
||||
}
|
||||
|
||||
// get the new modifier state
|
||||
mask = getModifierKeyMask(sysKeyID);
|
||||
if (mask != 0) {
|
||||
// key is a modifier key
|
||||
if ((mask & (KeyModifierCapsLock |
|
||||
KeyModifierNumLock |
|
||||
KeyModifierScrollLock)) != 0) {
|
||||
// modifier is a toggle
|
||||
m_mask ^= mask;
|
||||
}
|
||||
else if (!isModifierActive(sysKeyID)) {
|
||||
// all keys for this modifier are released
|
||||
m_mask &= ~mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::mouseDown(ButtonID button)
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
sync();
|
||||
fakeMouseButton(button, true);
|
||||
flush();
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::mouseUp(ButtonID button)
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
sync();
|
||||
fakeMouseButton(button, false);
|
||||
flush();
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::mouseMove(SInt32 x, SInt32 y)
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
sync();
|
||||
fakeMouseMove(x, y);
|
||||
flush();
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::mouseWheel(SInt32 delta)
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
sync();
|
||||
fakeMouseWheel(delta);
|
||||
flush();
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::setToggleState(KeyModifierMask mask)
|
||||
{
|
||||
// toggle modifiers that don't match the desired state
|
||||
KeyModifierMask different = (m_mask ^ mask);
|
||||
if ((different & KeyModifierCapsLock) != 0) {
|
||||
toggleKey(kKeyCapsLock, KeyModifierCapsLock);
|
||||
}
|
||||
if ((different & KeyModifierNumLock) != 0) {
|
||||
toggleKey(kKeyNumLock, KeyModifierNumLock);
|
||||
}
|
||||
if ((different & KeyModifierScrollLock) != 0) {
|
||||
toggleKey(kKeyScrollLock, KeyModifierScrollLock);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::resetOptions()
|
||||
{
|
||||
// set screen saver synchronization flag and see if we need to
|
||||
// update the screen saver synchronization.
|
||||
// update the screen saver synchronization. reset other options.
|
||||
bool screenSaverSyncOn;
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
screenSaverSyncOn = (!m_screenSaverSync && m_remoteReady);
|
||||
m_screenSaverSync = true;
|
||||
m_numLockHalfDuplex = false;
|
||||
m_capsLockHalfDuplex = false;
|
||||
}
|
||||
|
||||
// update screen saver synchronization
|
||||
|
@ -275,6 +575,14 @@ CSecondaryScreen::setOptions(const COptionsList& options)
|
|||
m_screenSaverSync = (options[i + 1] != 0);
|
||||
LOG((CLOG_DEBUG1 "screen saver synchronization %s", m_screenSaverSync ? "on" : "off"));
|
||||
}
|
||||
else if (options[i] == kOptionHalfDuplexCapsLock) {
|
||||
m_capsLockHalfDuplex = (options[i + 1] != 0);
|
||||
LOG((CLOG_DEBUG1 "half-duplex caps-lock %s", m_capsLockHalfDuplex ? "on" : "off"));
|
||||
}
|
||||
else if (options[i] == kOptionHalfDuplexNumLock) {
|
||||
m_numLockHalfDuplex = (options[i + 1] != 0);
|
||||
LOG((CLOG_DEBUG1 "half-duplex num-lock %s", m_numLockHalfDuplex ? "on" : "off"));
|
||||
}
|
||||
}
|
||||
if (!m_remoteReady || oldScreenSaverSync == m_screenSaverSync) {
|
||||
updateScreenSaverSync = false;
|
||||
|
@ -306,17 +614,23 @@ CSecondaryScreen::getClipboard(ClipboardID id,
|
|||
getScreen()->getClipboard(id, clipboard);
|
||||
}
|
||||
|
||||
SInt32
|
||||
CSecondaryScreen::getJumpZoneSize() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
|
||||
{
|
||||
getScreen()->syncDesktop();
|
||||
sync();
|
||||
getScreen()->getShape(x, y, w, h);
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::getCursorPos(SInt32& x, SInt32& y) const
|
||||
{
|
||||
getScreen()->syncDesktop();
|
||||
sync();
|
||||
getScreen()->getCursorPos(x, y);
|
||||
}
|
||||
|
||||
|
@ -379,3 +693,89 @@ CSecondaryScreen::onPostLeave()
|
|||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::updateKeys()
|
||||
{
|
||||
sync();
|
||||
|
||||
// clear key state
|
||||
memset(m_keys, 0, sizeof(m_keys));
|
||||
memset(m_fakeKeys, 0, sizeof(m_fakeKeys));
|
||||
|
||||
// let subclass set m_keys
|
||||
updateKeys(m_keys);
|
||||
|
||||
// get m_mask from subclass
|
||||
m_mask = getModifiers();
|
||||
LOG((CLOG_DEBUG2 "modifiers on update: 0x%04x", m_mask));
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::releaseKeys()
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
sync();
|
||||
|
||||
// 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 (UInt32 i = 1; i < 256; ++i) {
|
||||
if ((m_fakeKeys[i] & kDown) != 0) {
|
||||
fakeKeyEvent(i, false);
|
||||
m_keys[i] &= ~kDown;
|
||||
m_fakeKeys[i] &= ~kDown;
|
||||
}
|
||||
}
|
||||
|
||||
flush();
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::toggleKey(KeyID keyID, KeyModifierMask mask)
|
||||
{
|
||||
// get the system key ID for this toggle key ID
|
||||
SysKeyID sysKeyID = getToggleSysKey(keyID);
|
||||
if (sysKeyID == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// toggle the key
|
||||
if (isKeyHalfDuplex(keyID)) {
|
||||
// "half-duplex" toggle
|
||||
fakeKeyEvent(sysKeyID, (m_mask & mask) == 0);
|
||||
}
|
||||
else {
|
||||
// normal toggle
|
||||
fakeKeyEvent(sysKeyID, true);
|
||||
fakeKeyEvent(sysKeyID, false);
|
||||
}
|
||||
flush();
|
||||
|
||||
// toggle shadow state
|
||||
m_mask ^= mask;
|
||||
sysKeyID &= 0xffu;
|
||||
m_keys[sysKeyID] ^= kToggled;
|
||||
m_fakeKeys[sysKeyID] ^= kToggled;
|
||||
}
|
||||
|
||||
bool
|
||||
CSecondaryScreen::isKeyDown(SysKeyID sysKeyID) const
|
||||
{
|
||||
sysKeyID &= 0xffu;
|
||||
return (sysKeyID != 0 && ((m_keys[sysKeyID] & kDown) != 0));
|
||||
}
|
||||
|
||||
bool
|
||||
CSecondaryScreen::isKeyToggled(SysKeyID sysKeyID) const
|
||||
{
|
||||
sysKeyID &= 0xffu;
|
||||
return (sysKeyID != 0 && ((m_keys[sysKeyID] & kToggled) != 0));
|
||||
}
|
||||
|
||||
bool
|
||||
CSecondaryScreen::isKeyHalfDuplex(KeyID keyID) const
|
||||
{
|
||||
return ((keyID == kKeyCapsLock && m_capsLockHalfDuplex) ||
|
||||
(keyID == kKeyNumLock && m_numLockHalfDuplex));
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
#include "MouseTypes.h"
|
||||
#include "OptionTypes.h"
|
||||
#include "CMutex.h"
|
||||
#include "stdmap.h"
|
||||
#include "stdvector.h"
|
||||
|
||||
class IClipboard;
|
||||
class IScreen;
|
||||
|
@ -130,41 +132,41 @@ public:
|
|||
synthesize an up or repeat for the same client key synthesized by
|
||||
keyDown().
|
||||
*/
|
||||
virtual void keyDown(KeyID id, KeyModifierMask, KeyButton) = 0;
|
||||
void keyDown(KeyID id, KeyModifierMask, KeyButton);
|
||||
|
||||
//! Notify of key repeat
|
||||
/*!
|
||||
Synthesize key events to generate a press and release of key \c id
|
||||
\c count times. If possible match the given modifier mask.
|
||||
*/
|
||||
virtual void keyRepeat(KeyID id, KeyModifierMask,
|
||||
SInt32 count, KeyButton) = 0;
|
||||
void keyRepeat(KeyID id, KeyModifierMask,
|
||||
SInt32 count, KeyButton);
|
||||
|
||||
//! Notify of key release
|
||||
/*!
|
||||
Synthesize key events to generate a release of key \c id. If possible
|
||||
match the given modifier mask.
|
||||
*/
|
||||
virtual void keyUp(KeyID id, KeyModifierMask, KeyButton) = 0;
|
||||
void keyUp(KeyID id, KeyModifierMask, KeyButton);
|
||||
|
||||
//! Notify of mouse press
|
||||
/*!
|
||||
Synthesize mouse events to generate a press of mouse button \c id.
|
||||
*/
|
||||
virtual void mouseDown(ButtonID id) = 0;
|
||||
void mouseDown(ButtonID id);
|
||||
|
||||
//! Notify of mouse release
|
||||
/*!
|
||||
Synthesize mouse events to generate a release of mouse button \c id.
|
||||
*/
|
||||
virtual void mouseUp(ButtonID id) = 0;
|
||||
void mouseUp(ButtonID id);
|
||||
|
||||
//! Notify of mouse motion
|
||||
/*!
|
||||
Synthesize mouse events to generate mouse motion to the absolute
|
||||
screen position \c xAbs,yAbs.
|
||||
*/
|
||||
virtual void mouseMove(SInt32 xAbs, SInt32 yAbs) = 0;
|
||||
void mouseMove(SInt32 xAbs, SInt32 yAbs);
|
||||
|
||||
//! Notify of mouse wheel motion
|
||||
/*!
|
||||
|
@ -173,7 +175,7 @@ public:
|
|||
motion towards the user. Each wheel click should generate a delta
|
||||
of +/-120.
|
||||
*/
|
||||
virtual void mouseWheel(SInt32 delta) = 0;
|
||||
void mouseWheel(SInt32 delta);
|
||||
|
||||
//! Notify of options changes
|
||||
/*!
|
||||
|
@ -212,7 +214,7 @@ public:
|
|||
Return the jump zone size, the size of the regions on the edges of
|
||||
the screen that cause the cursor to jump to another screen.
|
||||
*/
|
||||
virtual SInt32 getJumpZoneSize() const = 0;
|
||||
SInt32 getJumpZoneSize() const;
|
||||
|
||||
//! Get screen shape
|
||||
/*!
|
||||
|
@ -237,6 +239,26 @@ public:
|
|||
//@}
|
||||
|
||||
protected:
|
||||
typedef UInt8 KeyState;
|
||||
typedef UInt32 SysKeyID;
|
||||
enum EKeyState { kDown = 0x01, kToggled = 0x80 };
|
||||
enum EKeyAction { kPress, kRelease, kRepeat };
|
||||
class Keystroke {
|
||||
public:
|
||||
SysKeyID m_sysKeyID;
|
||||
bool m_press;
|
||||
bool m_repeat;
|
||||
};
|
||||
typedef std::vector<Keystroke> Keystrokes;
|
||||
typedef std::map<KeyButton, SysKeyID> ServerKeyMap;
|
||||
|
||||
void updateKeys();
|
||||
void releaseKeys();
|
||||
void doKeystrokes(const Keystrokes&, SInt32 count);
|
||||
bool isKeyDown(SysKeyID) const;
|
||||
bool isKeyToggled(SysKeyID) const;
|
||||
bool isKeyHalfDuplex(KeyID) const;
|
||||
|
||||
//! Pre-mainLoop() hook
|
||||
/*!
|
||||
Called on entry to mainLoop(). Override to perform platform specific
|
||||
|
@ -338,38 +360,54 @@ protected:
|
|||
*/
|
||||
virtual void hideWindow() = 0;
|
||||
|
||||
//! Synchronize key state
|
||||
/*!
|
||||
Save the current keyboard state. Normally a screen will save
|
||||
the keyboard state in this method and use this shadow state,
|
||||
available through isKeyDown() and getKeyState(), when
|
||||
synthesizing events.
|
||||
*/
|
||||
virtual void updateKeys(KeyState* sysKeyStates) = 0;
|
||||
|
||||
//! Get modifier key state
|
||||
/*!
|
||||
Return the current keyboard modifier state.
|
||||
*/
|
||||
virtual KeyModifierMask getModifiers() const = 0;
|
||||
|
||||
//! Synchronize toggle key state
|
||||
/*!
|
||||
Toggles modifiers that don't match the given state so that they do.
|
||||
*/
|
||||
void setToggleState(KeyModifierMask);
|
||||
|
||||
virtual SysKeyID getUnhanded(SysKeyID) const;
|
||||
virtual SysKeyID getOtherHanded(SysKeyID) const;
|
||||
virtual bool isAutoRepeating(SysKeyID) const = 0;
|
||||
virtual KeyModifierMask getModifierKeyMask(SysKeyID) const = 0;
|
||||
virtual bool isModifierActive(SysKeyID) const = 0;
|
||||
virtual SysKeyID getToggleSysKey(KeyID keyID) const = 0;
|
||||
virtual bool synthesizeCtrlAltDel(EKeyAction);
|
||||
virtual void sync() const;
|
||||
virtual void flush();
|
||||
|
||||
virtual KeyModifierMask
|
||||
mapKey(Keystrokes&, SysKeyID& sysKeyID, KeyID,
|
||||
KeyModifierMask currentMask,
|
||||
KeyModifierMask desiredMask, EKeyAction) const = 0;
|
||||
virtual void fakeKeyEvent(SysKeyID, bool press) const = 0;
|
||||
virtual void fakeMouseButton(ButtonID, bool press) const = 0;
|
||||
|
||||
//! Warp cursor
|
||||
/*!
|
||||
Warp the cursor to the absolute coordinates \c x,y.
|
||||
*/
|
||||
virtual void warpCursor(SInt32 x, SInt32 y) = 0;
|
||||
virtual void fakeMouseMove(SInt32 x, SInt32 y) const = 0;
|
||||
|
||||
//! Synchronize key state
|
||||
/*!
|
||||
Check the current keyboard state. Normally a screen will save
|
||||
the keyboard state in this method and use this shadow state
|
||||
when synthesizing events.
|
||||
*/
|
||||
virtual void updateKeys() = 0;
|
||||
virtual void fakeMouseWheel(SInt32 delta) const = 0;
|
||||
|
||||
//! Release keys
|
||||
/*!
|
||||
Synthesizes key release event for any key that our key state
|
||||
says is down.
|
||||
*/
|
||||
virtual void releaseKeys() = 0;
|
||||
|
||||
//! Synchronize toggle key state
|
||||
/*!
|
||||
Toggle modifiers that don't match the given state so that they do.
|
||||
*/
|
||||
virtual void setToggleState(KeyModifierMask) = 0;
|
||||
|
||||
//! Get the toggle key state
|
||||
/*!
|
||||
Returns the current state of the toggle keys.
|
||||
*/
|
||||
virtual KeyModifierMask getToggleState() const = 0;
|
||||
private:
|
||||
void toggleKey(KeyID, KeyModifierMask);
|
||||
|
||||
private:
|
||||
CMutex m_mutex;
|
||||
|
@ -380,11 +418,29 @@ private:
|
|||
// m_active is true if this screen has been entered
|
||||
bool m_active;
|
||||
|
||||
// true if screen saver should be synchronized to server
|
||||
bool m_screenSaverSync;
|
||||
|
||||
// map server key buttons to local system keys
|
||||
ServerKeyMap m_serverKeyMap;
|
||||
|
||||
// system key states as set by us or the user
|
||||
KeyState m_keys[256];
|
||||
|
||||
// system key states as set by us
|
||||
KeyState m_fakeKeys[256];
|
||||
|
||||
// current active modifiers
|
||||
// XXX -- subclasses still have and use this
|
||||
KeyModifierMask m_mask;
|
||||
|
||||
// the toggle key state when this screen was last entered
|
||||
KeyModifierMask m_toggleKeys;
|
||||
|
||||
// true if screen saver should be synchronized to server
|
||||
bool m_screenSaverSync;
|
||||
// note toggle keys that toggles on up/down (false) or on
|
||||
// transition (true)
|
||||
bool m_numLockHalfDuplex;
|
||||
bool m_capsLockHalfDuplex;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -63,16 +63,6 @@ public:
|
|||
*/
|
||||
virtual void onOneShotTimerExpired(UInt32 id) = 0;
|
||||
|
||||
//@}
|
||||
//! @name accessors
|
||||
//@{
|
||||
|
||||
//! Get jump zone size
|
||||
/*!
|
||||
Called to get the jump zone size.
|
||||
*/
|
||||
virtual SInt32 getJumpZoneSize() const = 0;
|
||||
|
||||
//@}
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue