Keyboard fixes on win32.
This commit is contained in:
parent
b9193ae1bb
commit
28427a0e9b
|
@ -70,6 +70,19 @@
|
|||
// CMSWindowsSecondaryScreen
|
||||
//
|
||||
|
||||
// a list of modifier key info
|
||||
const CMSWindowsSecondaryScreen::CModifierInfo
|
||||
CMSWindowsSecondaryScreen::s_modifier[] = {
|
||||
{ KeyModifierShift, VK_LSHIFT, VK_RSHIFT, false },
|
||||
{ KeyModifierControl, VK_LCONTROL, VK_RCONTROL | 0x100,false },
|
||||
{ KeyModifierAlt, VK_LMENU, VK_RMENU | 0x100, false },
|
||||
// note -- no keys for KeyModifierMeta
|
||||
{ KeyModifierSuper, VK_LWIN | 0x100, VK_RWIN | 0x100, false },
|
||||
{ KeyModifierCapsLock, VK_CAPITAL, 0, true },
|
||||
{ KeyModifierNumLock, VK_NUMLOCK | 0x100, 0, true },
|
||||
{ KeyModifierScrollLock,VK_SCROLL, 0, true }
|
||||
};
|
||||
|
||||
CMSWindowsSecondaryScreen::CMSWindowsSecondaryScreen(
|
||||
IScreenReceiver* receiver) :
|
||||
m_is95Family(CArchMiscWindows::isWindows95Family()),
|
||||
|
@ -90,9 +103,6 @@ void
|
|||
CMSWindowsSecondaryScreen::keyDown(KeyID key,
|
||||
KeyModifierMask mask, KeyButton button)
|
||||
{
|
||||
Keystrokes keys;
|
||||
UINT virtualKey;
|
||||
|
||||
CLock lock(&m_mutex);
|
||||
m_screen->syncDesktop();
|
||||
|
||||
|
@ -106,15 +116,21 @@ CMSWindowsSecondaryScreen::keyDown(KeyID key,
|
|||
|
||||
// get the sequence of keys to simulate key press and the final
|
||||
// modifier state.
|
||||
Keystrokes keys;
|
||||
UINT virtualKey;
|
||||
m_mask = mapKey(keys, virtualKey, key, mask, kPress);
|
||||
if (keys.empty()) {
|
||||
// do nothing if there are no associated keys (i.e. lookup failed)
|
||||
return;
|
||||
}
|
||||
|
||||
// generate key events
|
||||
doKeystrokes(keys, 1);
|
||||
|
||||
// do not record button down if button is 0 (invalid)
|
||||
if (button != 0) {
|
||||
// note that key is now down
|
||||
m_serverKeyMap[button] = virtualKey;
|
||||
m_keys[virtualKey] |= 0x80;
|
||||
m_fakeKeys[virtualKey] |= 0x80;
|
||||
switch (virtualKey) {
|
||||
|
@ -136,18 +152,13 @@ CMSWindowsSecondaryScreen::keyDown(KeyID key,
|
|||
m_fakeKeys[VK_MENU] |= 0x80;
|
||||
break;
|
||||
}
|
||||
|
||||
// note which server key generated this key
|
||||
m_serverKeyMap[button] = virtualKey;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsSecondaryScreen::keyRepeat(KeyID key,
|
||||
KeyModifierMask mask, SInt32 count, KeyButton button)
|
||||
{
|
||||
Keystrokes keys;
|
||||
UINT virtualKey;
|
||||
|
||||
CLock lock(&m_mutex);
|
||||
m_screen->syncDesktop();
|
||||
|
||||
|
@ -159,20 +170,26 @@ CMSWindowsSecondaryScreen::keyRepeat(KeyID key,
|
|||
|
||||
// get the sequence of keys to simulate key repeat and the final
|
||||
// modifier state.
|
||||
Keystrokes keys;
|
||||
UINT virtualKey;
|
||||
m_mask = mapKey(keys, virtualKey, key, mask, kRepeat);
|
||||
if (keys.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if we've seen this button (and we should have) then make sure
|
||||
// we release the same key we pressed when we saw it.
|
||||
if (index != m_serverKeyMap.end() && virtualKey != index->second) {
|
||||
// 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 (virtualKey != index->second) {
|
||||
// replace key up with previous keycode 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_virtualKey == index->second) {
|
||||
if (index2->m_virtualKey == virtualKey) {
|
||||
index2->m_virtualKey = index->second;
|
||||
break;
|
||||
}
|
||||
|
@ -195,12 +212,8 @@ CMSWindowsSecondaryScreen::keyRepeat(KeyID key,
|
|||
}
|
||||
|
||||
void
|
||||
CMSWindowsSecondaryScreen::keyUp(KeyID key,
|
||||
KeyModifierMask mask, KeyButton button)
|
||||
CMSWindowsSecondaryScreen::keyUp(KeyID, KeyModifierMask, KeyButton button)
|
||||
{
|
||||
Keystrokes keys;
|
||||
UINT virtualKey;
|
||||
|
||||
CLock lock(&m_mutex);
|
||||
m_screen->syncDesktop();
|
||||
|
||||
|
@ -209,42 +222,18 @@ CMSWindowsSecondaryScreen::keyUp(KeyID key,
|
|||
if (index == m_serverKeyMap.end()) {
|
||||
return;
|
||||
}
|
||||
UINT virtualKey = index->second;
|
||||
|
||||
// get the sequence of keys to simulate key release and the final
|
||||
// modifier state.
|
||||
m_mask = mapKey(keys, virtualKey, key, mask, kRelease);
|
||||
|
||||
// if there are no keys to generate then we should at least generate
|
||||
// a key release for the key we pressed.
|
||||
if (keys.empty()) {
|
||||
Keystroke keystroke;
|
||||
virtualKey = index->second;
|
||||
keystroke.m_virtualKey = virtualKey;
|
||||
keystroke.m_press = false;
|
||||
keystroke.m_repeat = false;
|
||||
keys.push_back(keystroke);
|
||||
}
|
||||
|
||||
// if we've seen this button (and we should have) then make sure
|
||||
// we release the same key we pressed when we saw it.
|
||||
if (index != m_serverKeyMap.end() && virtualKey != index->second) {
|
||||
// replace key up with previous virtual key
|
||||
for (Keystrokes::iterator index2 = keys.begin();
|
||||
index2 != keys.end(); ++index2) {
|
||||
if (index2->m_virtualKey == virtualKey) {
|
||||
index2->m_virtualKey = index->second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// use old virtual key
|
||||
virtualKey = index->second;
|
||||
}
|
||||
Keystrokes keys;
|
||||
m_mask = mapKeyRelease(keys, virtualKey);
|
||||
|
||||
// generate key events
|
||||
doKeystrokes(keys, 1);
|
||||
|
||||
// note that key is now up
|
||||
m_serverKeyMap.erase(index);
|
||||
m_keys[virtualKey] &= ~0x80;
|
||||
m_fakeKeys[virtualKey] &= ~0x80;
|
||||
switch (virtualKey) {
|
||||
|
@ -290,11 +279,6 @@ CMSWindowsSecondaryScreen::keyUp(KeyID key,
|
|||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// remove server key from map
|
||||
if (index != m_serverKeyMap.end()) {
|
||||
m_serverKeyMap.erase(index);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1003,6 +987,47 @@ CMSWindowsSecondaryScreen::mapKey(Keystrokes& keys, UINT& virtualKey,
|
|||
return m_mask;
|
||||
}
|
||||
|
||||
KeyModifierMask
|
||||
CMSWindowsSecondaryScreen::mapKeyRelease(Keystrokes& keys,
|
||||
UINT virtualKey) const
|
||||
{
|
||||
// add key release
|
||||
Keystroke keystroke;
|
||||
keystroke.m_virtualKey = virtualKey;
|
||||
keystroke.m_press = false;
|
||||
keystroke.m_repeat = false;
|
||||
keys.push_back(keystroke);
|
||||
|
||||
// if this is a modifier keycode then update the current modifier mask
|
||||
const CModifierInfo* modifier = getModifierInfo(virtualKey);
|
||||
if (modifier != NULL) {
|
||||
if (modifier->m_isToggle) {
|
||||
// toggle keys modify the state on release
|
||||
return (m_mask ^ modifier->m_mask);
|
||||
}
|
||||
else {
|
||||
// can't reset bit until all keys that set it are released.
|
||||
// scan those keys to see if any (except virtualKey) are
|
||||
// pressed.
|
||||
bool down = false;
|
||||
if (virtualKey != (modifier->m_virtualKey & 0xff) &&
|
||||
(m_keys[modifier->m_virtualKey & 0xff] & 0x80) != 0) {
|
||||
down = true;
|
||||
}
|
||||
if (modifier->m_virtualKey2 != 0 &&
|
||||
virtualKey != (modifier->m_virtualKey2 & 0xff) &&
|
||||
(m_keys[modifier->m_virtualKey2 & 0xff] & 0x80) != 0) {
|
||||
down = true;
|
||||
}
|
||||
if (!down) {
|
||||
return (m_mask & ~modifier->m_mask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return m_mask;
|
||||
}
|
||||
|
||||
UINT
|
||||
CMSWindowsSecondaryScreen::mapCharacter(Keystrokes& keys,
|
||||
char c, HKL hkl,
|
||||
|
@ -1102,73 +1127,7 @@ CMSWindowsSecondaryScreen::mapToKeystrokes(Keystrokes& keys,
|
|||
KeyModifierMask currentMask,
|
||||
KeyModifierMask desiredMask, EKeyAction action) const
|
||||
{
|
||||
// a list of modifier key info
|
||||
class CModifierInfo {
|
||||
public:
|
||||
KeyModifierMask m_mask;
|
||||
UINT m_virtualKey;
|
||||
UINT m_virtualKey2;
|
||||
bool m_isToggle;
|
||||
};
|
||||
static const CModifierInfo s_modifier[] = {
|
||||
{ KeyModifierShift, VK_LSHIFT, VK_RSHIFT, false },
|
||||
{ KeyModifierControl, VK_LCONTROL, VK_RCONTROL | 0x100,false },
|
||||
{ KeyModifierAlt, VK_LMENU, VK_RMENU | 0x100, false },
|
||||
// note -- no keys for KeyModifierMeta
|
||||
{ KeyModifierSuper, VK_LWIN | 0x100, VK_RWIN | 0x100, false },
|
||||
{ KeyModifierCapsLock, VK_CAPITAL, 0, true },
|
||||
{ KeyModifierNumLock, VK_NUMLOCK | 0x100, 0, true },
|
||||
{ KeyModifierScrollLock,VK_SCROLL, 0, true }
|
||||
};
|
||||
static const unsigned int s_numModifiers =
|
||||
sizeof(s_modifier) / sizeof(s_modifier[0]);
|
||||
|
||||
// strip out extended key flag
|
||||
UINT virtualKey2 = (virtualKey & ~0x100);
|
||||
|
||||
// note if the key is a modifier
|
||||
unsigned int modifierIndex;
|
||||
switch (virtualKey2) {
|
||||
case VK_SHIFT:
|
||||
case VK_LSHIFT:
|
||||
case VK_RSHIFT:
|
||||
modifierIndex = 0;
|
||||
break;
|
||||
|
||||
case VK_CONTROL:
|
||||
case VK_LCONTROL:
|
||||
case VK_RCONTROL:
|
||||
modifierIndex = 1;
|
||||
break;
|
||||
|
||||
case VK_MENU:
|
||||
case VK_LMENU:
|
||||
case VK_RMENU:
|
||||
modifierIndex = 2;
|
||||
break;
|
||||
|
||||
case VK_LWIN:
|
||||
case VK_RWIN:
|
||||
modifierIndex = 3;
|
||||
break;
|
||||
|
||||
case VK_CAPITAL:
|
||||
modifierIndex = 4;
|
||||
break;
|
||||
|
||||
case VK_NUMLOCK:
|
||||
modifierIndex = 5;
|
||||
break;
|
||||
|
||||
case VK_SCROLL:
|
||||
modifierIndex = 6;
|
||||
break;
|
||||
|
||||
default:
|
||||
modifierIndex = s_numModifiers;
|
||||
break;
|
||||
}
|
||||
const bool isModifier = (modifierIndex != s_numModifiers);
|
||||
const CModifierInfo* modifier = getModifierInfo(virtualKey);
|
||||
|
||||
// add the key events required to get to the desired modifier state.
|
||||
// also save the key events required to restore the current state.
|
||||
|
@ -1176,7 +1135,9 @@ CMSWindowsSecondaryScreen::mapToKeystrokes(Keystrokes& keys,
|
|||
// should not modify modifiers.
|
||||
Keystrokes undo;
|
||||
Keystroke keystroke;
|
||||
if (desiredMask != currentMask && !isModifier) {
|
||||
if (desiredMask != currentMask && modifier == NULL) {
|
||||
const unsigned int s_numModifiers = sizeof(s_modifier) /
|
||||
sizeof(s_modifier[0]);
|
||||
for (unsigned int i = 0; i < s_numModifiers; ++i) {
|
||||
KeyModifierMask bit = s_modifier[i].m_mask;
|
||||
if ((desiredMask & bit) != (currentMask & bit)) {
|
||||
|
@ -1274,35 +1235,12 @@ CMSWindowsSecondaryScreen::mapToKeystrokes(Keystrokes& keys,
|
|||
}
|
||||
|
||||
// if the key is a modifier key then compute the modifier mask after
|
||||
// this key is pressed.
|
||||
// this key is pressed. toggle keys modify the state on release.
|
||||
// other keys set the modifier bit on press.
|
||||
KeyModifierMask mask = currentMask;
|
||||
if (isModifier && action != kRepeat) {
|
||||
// toggle keys modify the state on release. other keys set
|
||||
// the bit on press and clear the bit on release.
|
||||
const CModifierInfo& modifier = s_modifier[modifierIndex];
|
||||
if (modifier.m_isToggle) {
|
||||
if (action == kRelease) {
|
||||
mask ^= modifier.m_mask;
|
||||
}
|
||||
}
|
||||
else if (action == kPress) {
|
||||
mask |= modifier.m_mask;
|
||||
}
|
||||
else {
|
||||
// can't reset bit until all keys that set it are released.
|
||||
// scan those keys to see if any are pressed.
|
||||
bool down = false;
|
||||
if (virtualKey2 != (modifier.m_virtualKey & 0xff) &&
|
||||
(m_keys[modifier.m_virtualKey & 0xff] & 0x80) != 0) {
|
||||
down = true;
|
||||
}
|
||||
if (modifier.m_virtualKey2 != 0 &&
|
||||
virtualKey2 != (modifier.m_virtualKey2 & 0xff) &&
|
||||
(m_keys[modifier.m_virtualKey2 & 0xff] & 0x80) != 0) {
|
||||
down = true;
|
||||
}
|
||||
if (!down)
|
||||
mask &= ~modifier.m_mask;
|
||||
if (action == kPress) {
|
||||
if (modifier != NULL && !modifier->m_isToggle) {
|
||||
mask |= modifier->m_mask;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1344,6 +1282,45 @@ CMSWindowsSecondaryScreen::doKeystrokes(const Keystrokes& keys, SInt32 count)
|
|||
}
|
||||
}
|
||||
|
||||
const CMSWindowsSecondaryScreen::CModifierInfo*
|
||||
CMSWindowsSecondaryScreen::getModifierInfo(UINT virtualKey) const
|
||||
{
|
||||
// note if the key is a modifier. strip out extended key flag from
|
||||
// virtual key before lookup.
|
||||
switch (virtualKey & ~0x100) {
|
||||
case VK_SHIFT:
|
||||
case VK_LSHIFT:
|
||||
case VK_RSHIFT:
|
||||
return s_modifier + 0;
|
||||
|
||||
case VK_CONTROL:
|
||||
case VK_LCONTROL:
|
||||
case VK_RCONTROL:
|
||||
return s_modifier + 1;
|
||||
|
||||
case VK_MENU:
|
||||
case VK_LMENU:
|
||||
case VK_RMENU:
|
||||
return s_modifier + 2;
|
||||
|
||||
case VK_LWIN:
|
||||
case VK_RWIN:
|
||||
return s_modifier + 3;
|
||||
|
||||
case VK_CAPITAL:
|
||||
return s_modifier + 4;
|
||||
|
||||
case VK_NUMLOCK:
|
||||
return s_modifier + 5;
|
||||
|
||||
case VK_SCROLL:
|
||||
return s_modifier + 6;
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsSecondaryScreen::releaseKeys()
|
||||
{
|
||||
|
|
|
@ -85,6 +85,13 @@ private:
|
|||
bool m_press;
|
||||
bool m_repeat;
|
||||
};
|
||||
class CModifierInfo {
|
||||
public:
|
||||
KeyModifierMask m_mask;
|
||||
UINT m_virtualKey;
|
||||
UINT m_virtualKey2;
|
||||
bool m_isToggle;
|
||||
};
|
||||
typedef std::vector<Keystroke> Keystrokes;
|
||||
typedef std::map<KeyButton, UINT> ServerKeyMap;
|
||||
|
||||
|
@ -103,6 +110,7 @@ private:
|
|||
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,
|
||||
|
@ -114,6 +122,7 @@ private:
|
|||
KeyModifierMask desiredMask,
|
||||
EKeyAction action) const;
|
||||
void doKeystrokes(const Keystrokes&, SInt32 count);
|
||||
const CModifierInfo* getModifierInfo(UINT virtualKey) const;
|
||||
|
||||
void toggleKey(UINT virtualKey, KeyModifierMask mask);
|
||||
UINT virtualKeyToScanCode(UINT& virtualKey) const;
|
||||
|
@ -149,6 +158,9 @@ private:
|
|||
|
||||
// map server key buttons to local virtual keys
|
||||
ServerKeyMap m_serverKeyMap;
|
||||
|
||||
// modifier table
|
||||
static const CModifierInfo s_modifier[];
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue