Changed windows server to release ctrl and alt keys when it's

sending a key that requires AltGr.  That's because AltGr *is*
ctrl and alt but AltGr should be seen on clients as mode
switch without the ctrl and alt.  I can't think of a better
way to do this other than to not send modifier keystrokes to
the clients at all.
This commit is contained in:
crs 2003-07-08 18:40:46 +00:00
parent c325b923ea
commit f27fd7b021
2 changed files with 262 additions and 148 deletions

View File

@ -485,10 +485,11 @@ CMSWindowsPrimaryScreen::onPreDispatch(const CEvent* event)
lParam |= (0x00ff0000 & (MapVirtualKey(wParam, 0) << 24)); lParam |= (0x00ff0000 & (MapVirtualKey(wParam, 0) << 24));
// process as if it were a key up // process as if it were a key up
bool altgr;
KeyModifierMask mask; KeyModifierMask mask;
KeyButton button = static_cast<KeyButton>( KeyButton button = static_cast<KeyButton>(
(lParam & 0x00ff0000u) >> 16); (lParam & 0x00ff0000u) >> 16);
const KeyID key = mapKey(wParam, lParam, &mask); const KeyID key = mapKey(wParam, lParam, &mask, &altgr);
LOG((CLOG_DEBUG1 "event: fake key release key=%d mask=0x%04x button=0x%04x", key, mask, button)); LOG((CLOG_DEBUG1 "event: fake key release key=%d mask=0x%04x button=0x%04x", key, mask, button));
m_receiver->onKeyUp(key, mask, button); m_receiver->onKeyUp(key, mask, button);
updateKey(wParam, false); updateKey(wParam, false);
@ -502,10 +503,11 @@ CMSWindowsPrimaryScreen::onPreDispatch(const CEvent* event)
lParam |= (0x00ff0000 & (MapVirtualKey(wParam, 0) << 24)); lParam |= (0x00ff0000 & (MapVirtualKey(wParam, 0) << 24));
// process as if it were a key up // process as if it were a key up
bool altgr;
KeyModifierMask mask; KeyModifierMask mask;
KeyButton button = static_cast<KeyButton>( KeyButton button = static_cast<KeyButton>(
(lParam & 0x00ff0000u) >> 16); (lParam & 0x00ff0000u) >> 16);
const KeyID key = mapKey(wParam, lParam, &mask); const KeyID key = mapKey(wParam, lParam, &mask, &altgr);
LOG((CLOG_DEBUG1 "event: fake key release key=%d mask=0x%04x button=0x%04x", key, mask, button)); LOG((CLOG_DEBUG1 "event: fake key release key=%d mask=0x%04x button=0x%04x", key, mask, button));
m_receiver->onKeyUp(key, mask, button); m_receiver->onKeyUp(key, mask, button);
updateKey(wParam, false); updateKey(wParam, false);
@ -535,22 +537,111 @@ CMSWindowsPrimaryScreen::onPreDispatch(const CEvent* event)
} }
// process key normally // process key normally
bool altgr;
KeyModifierMask mask; KeyModifierMask mask;
const KeyID key = mapKey(wParam, lParam, &mask); const KeyID key = mapKey(wParam, lParam, &mask, &altgr);
KeyButton button = static_cast<KeyButton>( KeyButton button = static_cast<KeyButton>(
(lParam & 0x00ff0000u) >> 16); (lParam & 0x00ff0000u) >> 16);
if (key != kKeyNone && key != kKeyMultiKey) { if (key != kKeyNone && key != kKeyMultiKey) {
if ((lParam & 0x80000000) == 0) { if ((lParam & 0x80000000) == 0) {
// key press // key press
// if AltGr required for this key then make sure
// the ctrl and alt keys are *not* down on the
// client. windows simulates AltGr with ctrl and
// alt for some inexplicable reason and clients
// will get confused if they see mode switch and
// ctrl and alt. we'll also need to put ctrl and
// alt back the way there were after we simulate
// the key.
bool ctrlL = ((m_keys[VK_LCONTROL] & 0x80) != 0);
bool ctrlR = ((m_keys[VK_RCONTROL] & 0x80) != 0);
bool altL = ((m_keys[VK_LMENU] & 0x80) != 0);
bool altR = ((m_keys[VK_RMENU] & 0x80) != 0);
if (altgr) {
KeyID key;
KeyButton button;
KeyModifierMask mask2 = (mask &
~(KeyModifierControl |
KeyModifierAlt |
KeyModifierModeSwitch));
if (ctrlL) {
key = kKeyControl_L;
button = mapKeyToScanCode(VK_LCONTROL, VK_CONTROL);
LOG((CLOG_DEBUG1 "event: fake key release key=%d mask=0x%04x button=0x%04x", key, mask2, button));
m_receiver->onKeyUp(key, mask2, button);
}
if (ctrlR) {
key = kKeyControl_R;
button = mapKeyToScanCode(VK_RCONTROL, VK_CONTROL);
LOG((CLOG_DEBUG1 "event: fake key release key=%d mask=0x%04x button=0x%04x", key, mask2, button));
m_receiver->onKeyUp(key, mask2, button);
}
if (altL) {
key = kKeyAlt_L;
button = mapKeyToScanCode(VK_LMENU, VK_MENU);
LOG((CLOG_DEBUG1 "event: fake key release key=%d mask=0x%04x button=0x%04x", key, mask2, button));
m_receiver->onKeyUp(key, mask2, button);
}
if (altR) {
key = kKeyAlt_R;
button = mapKeyToScanCode(VK_RMENU, VK_MENU);
LOG((CLOG_DEBUG1 "event: fake key release key=%d mask=0x%04x button=0x%04x", key, mask2, button));
m_receiver->onKeyUp(key, mask2, button);
}
}
// send key
const bool wasDown = ((lParam & 0x40000000) != 0); const bool wasDown = ((lParam & 0x40000000) != 0);
const SInt32 repeat = (SInt32)(lParam & 0xffff); SInt32 repeat = (SInt32)(lParam & 0xffff);
if (repeat >= 2 || wasDown) { if (!wasDown) {
LOG((CLOG_DEBUG1 "event: key press key=%d mask=0x%04x button=0x%04x", key, mask, button));
m_receiver->onKeyDown(key, mask, button);
if (repeat > 0) {
--repeat;
}
}
if (repeat >= 1) {
LOG((CLOG_DEBUG1 "event: key repeat key=%d mask=0x%04x count=%d button=0x%04x", key, mask, repeat, button)); LOG((CLOG_DEBUG1 "event: key repeat key=%d mask=0x%04x count=%d button=0x%04x", key, mask, repeat, button));
m_receiver->onKeyRepeat(key, mask, repeat, button); m_receiver->onKeyRepeat(key, mask, repeat, button);
} }
else {
LOG((CLOG_DEBUG1 "event: key press key=%d mask=0x%04x button=0x%04x", key, mask, button)); // restore ctrl and alt state
m_receiver->onKeyDown(key, mask, button); if (altgr) {
KeyID key;
KeyButton button;
KeyModifierMask mask2 = (mask &
~(KeyModifierControl |
KeyModifierAlt |
KeyModifierModeSwitch));
if (ctrlL) {
key = kKeyControl_L;
button = mapKeyToScanCode(VK_LCONTROL, VK_CONTROL);
LOG((CLOG_DEBUG1 "event: fake key press key=%d mask=0x%04x button=0x%04x", key, mask2, button));
m_receiver->onKeyDown(key, mask2, button);
mask2 |= KeyModifierControl;
}
if (ctrlR) {
key = kKeyControl_R;
button = mapKeyToScanCode(VK_RCONTROL, VK_CONTROL);
LOG((CLOG_DEBUG1 "event: fake key press key=%d mask=0x%04x button=0x%04x", key, mask2, button));
m_receiver->onKeyDown(key, mask2, button);
mask2 |= KeyModifierControl;
}
if (altL) {
key = kKeyAlt_L;
button = mapKeyToScanCode(VK_LMENU, VK_MENU);
LOG((CLOG_DEBUG1 "event: fake key press key=%d mask=0x%04x button=0x%04x", key, mask2, button));
m_receiver->onKeyDown(key, mask2, button);
mask2 |= KeyModifierAlt;
}
if (altR) {
key = kKeyAlt_R;
button = mapKeyToScanCode(VK_RMENU, VK_MENU);
LOG((CLOG_DEBUG1 "event: fake key press key=%d mask=0x%04x button=0x%04x", key, mask2, button));
m_receiver->onKeyDown(key, mask2, button);
mask2 |= KeyModifierAlt;
}
} }
} }
else { else {
@ -1283,7 +1374,8 @@ KeyID
CMSWindowsPrimaryScreen::mapKey( CMSWindowsPrimaryScreen::mapKey(
WPARAM vkCode, WPARAM vkCode,
LPARAM info, LPARAM info,
KeyModifierMask* maskOut) KeyModifierMask* maskOut,
bool* altgr)
{ {
// note: known microsoft bugs // note: known microsoft bugs
// Q72583 -- MapVirtualKey() maps keypad keys incorrectly // Q72583 -- MapVirtualKey() maps keypad keys incorrectly
@ -1292,66 +1384,18 @@ CMSWindowsPrimaryScreen::mapKey(
// SEPARATOR, MULTIPLY, SUBTRACT, ADD // SEPARATOR, MULTIPLY, SUBTRACT, ADD
assert(maskOut != NULL); assert(maskOut != NULL);
assert(altgr != NULL);
// map modifier key
KeyModifierMask mask = 0;
if (((m_keys[VK_LSHIFT] |
m_keys[VK_RSHIFT] |
m_keys[VK_SHIFT]) & 0x80) != 0) {
mask |= KeyModifierShift;
}
if (((m_keys[VK_LCONTROL] |
m_keys[VK_RCONTROL] |
m_keys[VK_CONTROL]) & 0x80) != 0) {
mask |= KeyModifierControl;
}
if ((m_keys[VK_RMENU] & 0x80) != 0) {
// right alt => AltGr on windows
mask |= KeyModifierModeSwitch;
}
else if (((m_keys[VK_LMENU] |
m_keys[VK_MENU]) & 0x80) != 0) {
mask |= KeyModifierAlt;
}
if (((m_keys[VK_LWIN] |
m_keys[VK_RWIN]) & 0x80) != 0) {
mask |= KeyModifierSuper;
}
if ((m_keys[VK_CAPITAL] & 0x01) != 0) {
mask |= KeyModifierCapsLock;
}
if ((m_keys[VK_NUMLOCK] & 0x01) != 0) {
mask |= KeyModifierNumLock;
}
if ((m_keys[VK_SCROLL] & 0x01) != 0) {
mask |= KeyModifierScrollLock;
}
// ctrl+alt => AltGr on windows
/* don't convert ctrl+alt to mode switch. if we do that then we can
* never send ctrl+alt+[key] from windows to some platform that
* doesn't treat ctrl+alt as mode switch (i.e. all other platforms).
* instead, let windows clients automatically treat ctrl+alt as
* AltGr and let other clients use ctrl+alt as is. the right alt
* key serves as a mode switch key.
if ((mask & (KeyModifierControl | KeyModifierAlt)) ==
(KeyModifierControl | KeyModifierAlt)) {
mask |= KeyModifierModeSwitch;
mask &= ~(KeyModifierControl | KeyModifierAlt);
}
*/
*maskOut = mask;
LOG((CLOG_DEBUG2 "key in vk=%d info=0x%08x mask=0x%04x", vkCode, info, mask));
// get the scan code and the extended keyboard flag // get the scan code and the extended keyboard flag
UINT scanCode = static_cast<UINT>((info & 0x00ff0000u) >> 16); UINT scanCode = static_cast<UINT>((info & 0x00ff0000u) >> 16);
int extended = ((info & 0x01000000) == 0) ? 0 : 1; int extended = ((info & 0x01000000) == 0) ? 0 : 1;
LOG((CLOG_DEBUG1 "key vk=%d ext=%d scan=%d", vkCode, extended, scanCode)); LOG((CLOG_DEBUG1 "key vk=%d info=0x%08x ext=%d scan=%d", vkCode, info, extended, scanCode));
// handle some keys via table lookup // handle some keys via table lookup
char c = 0;
KeyID id = g_virtualKey[vkCode][extended]; KeyID id = g_virtualKey[vkCode][extended];
if (id != kKeyNone) { if (id == kKeyNone) {
return id; // not in table
}
// save the control state then clear it. ToAscii() maps ctrl+letter // save the control state then clear it. ToAscii() maps ctrl+letter
// to the corresponding control code and ctrl+backspace to delete. // to the corresponding control code and ctrl+backspace to delete.
@ -1363,7 +1407,7 @@ CMSWindowsPrimaryScreen::mapKey(
BYTE control = m_keys[VK_CONTROL]; BYTE control = m_keys[VK_CONTROL];
BYTE lMenu = m_keys[VK_LMENU]; BYTE lMenu = m_keys[VK_LMENU];
BYTE menu = m_keys[VK_MENU]; BYTE menu = m_keys[VK_MENU];
if ((mask & KeyModifierModeSwitch) == 0) { if ((control & 0x80) == 0 || (menu & 0x80) == 0) {
m_keys[VK_LCONTROL] = 0; m_keys[VK_LCONTROL] = 0;
m_keys[VK_RCONTROL] = 0; m_keys[VK_RCONTROL] = 0;
m_keys[VK_CONTROL] = 0; m_keys[VK_CONTROL] = 0;
@ -1389,24 +1433,30 @@ CMSWindowsPrimaryScreen::mapKey(
// if result is less than zero then it was a dead key. leave it // if result is less than zero then it was a dead key. leave it
// there. // there.
if (result < 0) { if (result < 0) {
return kKeyMultiKey; id = kKeyMultiKey;
} }
// if result is 1 then the key was succesfully converted // if result is 1 then the key was succesfully converted
else if (result == 1) { else if (result == 1) {
c = static_cast<char>(ascii & 0xff);
if (ascii >= 0x80) { if (ascii >= 0x80) {
// character is not really ASCII. instead it's some // character is not really ASCII. instead it's some
// character in the current ANSI code page. try to // character in the current ANSI code page. try to
// convert that to a Unicode character. if we fail // convert that to a Unicode character. if we fail
// then use the single byte character as is. // then use the single byte character as is.
char src = static_cast<char>(ascii & 0xff); char src = c;
wchar_t unicode; wchar_t unicode;
if (MultiByteToWideChar(CP_THREAD_ACP, MB_PRECOMPOSED, if (MultiByteToWideChar(CP_THREAD_ACP, MB_PRECOMPOSED,
&src, 1, &unicode, 1) > 0) { &src, 1, &unicode, 1) > 0) {
return static_cast<KeyID>(unicode); id = static_cast<KeyID>(unicode);
}
else {
id = static_cast<KeyID>(ascii & 0x00ff);
} }
} }
return static_cast<KeyID>(ascii & 0x00ff); else {
id = static_cast<KeyID>(ascii & 0x00ff);
}
} }
// if result is 2 then a previous dead key could not be composed. // if result is 2 then a previous dead key could not be composed.
@ -1447,11 +1497,64 @@ CMSWindowsPrimaryScreen::mapKey(
// put it back // put it back
ToAscii(vkCode, scanCode, keys, &ascii, 0); ToAscii(vkCode, scanCode, keys, &ascii, 0);
return kKeyMultiKey; id = kKeyMultiKey;
}
} }
// cannot convert key // set mask
return kKeyNone; *altgr = false;
if (id != kKeyNone && id != kKeyMultiKey && c != 0) {
// note if key requires AltGr
SHORT virtualKeyAndModifierState = VkKeyScan(c);
BYTE modifierState = HIBYTE(virtualKeyAndModifierState);
if ((modifierState & 6) == 6) {
// key requires ctrl and alt == AltGr
*altgr = true;
}
// map modifier key
KeyModifierMask mask = 0;
if (((m_keys[VK_LSHIFT] |
m_keys[VK_RSHIFT] |
m_keys[VK_SHIFT]) & 0x80) != 0) {
mask |= KeyModifierShift;
}
if (*altgr) {
mask |= KeyModifierModeSwitch;
}
else {
if (((m_keys[VK_LCONTROL] |
m_keys[VK_RCONTROL] |
m_keys[VK_CONTROL]) & 0x80) != 0) {
mask |= KeyModifierControl;
}
if (((m_keys[VK_LMENU] |
m_keys[VK_RMENU] |
m_keys[VK_MENU]) & 0x80) != 0) {
mask |= KeyModifierAlt;
}
}
if (((m_keys[VK_LWIN] |
m_keys[VK_RWIN]) & 0x80) != 0) {
mask |= KeyModifierSuper;
}
if ((m_keys[VK_CAPITAL] & 0x01) != 0) {
mask |= KeyModifierCapsLock;
}
if ((m_keys[VK_NUMLOCK] & 0x01) != 0) {
mask |= KeyModifierNumLock;
}
if ((m_keys[VK_SCROLL] & 0x01) != 0) {
mask |= KeyModifierScrollLock;
}
*maskOut = mask;
}
else {
// don't care
*maskOut = 0;
}
return id;
} }
ButtonID ButtonID
@ -1679,3 +1782,13 @@ CMSWindowsPrimaryScreen::isModifier(UINT vkCode) const
return false; return false;
} }
} }
KeyButton
CMSWindowsPrimaryScreen::mapKeyToScanCode(UINT vk1, UINT vk2) const
{
KeyButton button = static_cast<KeyButton>(MapVirtualKey(vk1, 0));
if (button == 0) {
button = static_cast<KeyButton>(MapVirtualKey(vk2, 0));
}
return button;
}

View File

@ -87,10 +87,11 @@ private:
// key and button queries // key and button queries
KeyID mapKey(WPARAM keycode, LPARAM info, KeyID mapKey(WPARAM keycode, LPARAM info,
KeyModifierMask* maskOut); KeyModifierMask* maskOut, bool* altgr);
ButtonID mapButton(WPARAM msg, LPARAM button) const; ButtonID mapButton(WPARAM msg, LPARAM button) const;
void updateKey(UINT vkCode, bool press); void updateKey(UINT vkCode, bool press);
bool isModifier(UINT vkCode) const; bool isModifier(UINT vkCode) const;
KeyButton mapKeyToScanCode(UINT vk1, UINT vk2) const;
private: private:
IPrimaryScreenReceiver* m_receiver; IPrimaryScreenReceiver* m_receiver;