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:
parent
c325b923ea
commit
f27fd7b021
|
@ -485,10 +485,11 @@ CMSWindowsPrimaryScreen::onPreDispatch(const CEvent* event)
|
|||
lParam |= (0x00ff0000 & (MapVirtualKey(wParam, 0) << 24));
|
||||
|
||||
// process as if it were a key up
|
||||
bool altgr;
|
||||
KeyModifierMask mask;
|
||||
KeyButton button = static_cast<KeyButton>(
|
||||
(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));
|
||||
m_receiver->onKeyUp(key, mask, button);
|
||||
updateKey(wParam, false);
|
||||
|
@ -502,10 +503,11 @@ CMSWindowsPrimaryScreen::onPreDispatch(const CEvent* event)
|
|||
lParam |= (0x00ff0000 & (MapVirtualKey(wParam, 0) << 24));
|
||||
|
||||
// process as if it were a key up
|
||||
bool altgr;
|
||||
KeyModifierMask mask;
|
||||
KeyButton button = static_cast<KeyButton>(
|
||||
(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));
|
||||
m_receiver->onKeyUp(key, mask, button);
|
||||
updateKey(wParam, false);
|
||||
|
@ -535,22 +537,111 @@ CMSWindowsPrimaryScreen::onPreDispatch(const CEvent* event)
|
|||
}
|
||||
|
||||
// process key normally
|
||||
bool altgr;
|
||||
KeyModifierMask mask;
|
||||
const KeyID key = mapKey(wParam, lParam, &mask);
|
||||
const KeyID key = mapKey(wParam, lParam, &mask, &altgr);
|
||||
KeyButton button = static_cast<KeyButton>(
|
||||
(lParam & 0x00ff0000u) >> 16);
|
||||
if (key != kKeyNone && key != kKeyMultiKey) {
|
||||
if ((lParam & 0x80000000) == 0) {
|
||||
// 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 SInt32 repeat = (SInt32)(lParam & 0xffff);
|
||||
if (repeat >= 2 || wasDown) {
|
||||
SInt32 repeat = (SInt32)(lParam & 0xffff);
|
||||
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));
|
||||
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));
|
||||
m_receiver->onKeyDown(key, mask, button);
|
||||
|
||||
// restore ctrl and alt state
|
||||
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 {
|
||||
|
@ -1283,7 +1374,8 @@ KeyID
|
|||
CMSWindowsPrimaryScreen::mapKey(
|
||||
WPARAM vkCode,
|
||||
LPARAM info,
|
||||
KeyModifierMask* maskOut)
|
||||
KeyModifierMask* maskOut,
|
||||
bool* altgr)
|
||||
{
|
||||
// note: known microsoft bugs
|
||||
// Q72583 -- MapVirtualKey() maps keypad keys incorrectly
|
||||
|
@ -1292,66 +1384,18 @@ CMSWindowsPrimaryScreen::mapKey(
|
|||
// SEPARATOR, MULTIPLY, SUBTRACT, ADD
|
||||
|
||||
assert(maskOut != 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));
|
||||
assert(altgr != NULL);
|
||||
|
||||
// get the scan code and the extended keyboard flag
|
||||
UINT scanCode = static_cast<UINT>((info & 0x00ff0000u) >> 16);
|
||||
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
|
||||
char c = 0;
|
||||
KeyID id = g_virtualKey[vkCode][extended];
|
||||
if (id != kKeyNone) {
|
||||
return id;
|
||||
}
|
||||
if (id == kKeyNone) {
|
||||
// not in table
|
||||
|
||||
// save the control state then clear it. ToAscii() maps ctrl+letter
|
||||
// to the corresponding control code and ctrl+backspace to delete.
|
||||
|
@ -1363,7 +1407,7 @@ CMSWindowsPrimaryScreen::mapKey(
|
|||
BYTE control = m_keys[VK_CONTROL];
|
||||
BYTE lMenu = m_keys[VK_LMENU];
|
||||
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_RCONTROL] = 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
|
||||
// there.
|
||||
if (result < 0) {
|
||||
return kKeyMultiKey;
|
||||
id = kKeyMultiKey;
|
||||
}
|
||||
|
||||
// if result is 1 then the key was succesfully converted
|
||||
else if (result == 1) {
|
||||
c = static_cast<char>(ascii & 0xff);
|
||||
if (ascii >= 0x80) {
|
||||
// character is not really ASCII. instead it's some
|
||||
// character in the current ANSI code page. try to
|
||||
// convert that to a Unicode character. if we fail
|
||||
// then use the single byte character as is.
|
||||
char src = static_cast<char>(ascii & 0xff);
|
||||
char src = c;
|
||||
wchar_t unicode;
|
||||
if (MultiByteToWideChar(CP_THREAD_ACP, MB_PRECOMPOSED,
|
||||
&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.
|
||||
|
@ -1447,11 +1497,64 @@ CMSWindowsPrimaryScreen::mapKey(
|
|||
|
||||
// put it back
|
||||
ToAscii(vkCode, scanCode, keys, &ascii, 0);
|
||||
return kKeyMultiKey;
|
||||
id = kKeyMultiKey;
|
||||
}
|
||||
}
|
||||
|
||||
// cannot convert key
|
||||
return kKeyNone;
|
||||
// set mask
|
||||
*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
|
||||
|
@ -1679,3 +1782,13 @@ CMSWindowsPrimaryScreen::isModifier(UINT vkCode) const
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -87,10 +87,11 @@ private:
|
|||
|
||||
// key and button queries
|
||||
KeyID mapKey(WPARAM keycode, LPARAM info,
|
||||
KeyModifierMask* maskOut);
|
||||
KeyModifierMask* maskOut, bool* altgr);
|
||||
ButtonID mapButton(WPARAM msg, LPARAM button) const;
|
||||
void updateKey(UINT vkCode, bool press);
|
||||
bool isModifier(UINT vkCode) const;
|
||||
KeyButton mapKeyToScanCode(UINT vk1, UINT vk2) const;
|
||||
|
||||
private:
|
||||
IPrimaryScreenReceiver* m_receiver;
|
||||
|
|
Loading…
Reference in New Issue