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:
crs 2003-07-26 13:41:41 +00:00
parent e725270c00
commit 221628fd84
8 changed files with 1121 additions and 1306 deletions

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -116,7 +116,10 @@ CSecondaryScreen::remoteControl()
}
// update keyboard state
updateKeys();
{
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;
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));
}

View File

@ -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

View File

@ -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;
//@}
};