mirror of
https://github.com/debauchee/barrier.git
synced 2026-02-09 13:15:33 +08:00
Win32 fixes. Fixed slightly off cursor positioning when using
absolute mouse_event(). Improved keyboard handling: now using keyboard layout of last foreground window when leaving server so users can meaningfully choose the locale, moved dead key handling into hook library so there should be no more race conditions involving the keyboard dead key buffer, simplified keyboard and cursor handling by using a full screen transparent window when not using low level hooks, fixed error in restoring buffered dead key when checking for dead keys. This hopefully fixes all known keyboard bugs on win32.
This commit is contained in:
@@ -706,7 +706,7 @@ const KeyButton CMSWindowsKeyMapper::s_mapEF00[] =
|
||||
|
||||
CMSWindowsKeyMapper::CMSWindowsKeyMapper() : m_deadKey(0)
|
||||
{
|
||||
// do nothing
|
||||
m_keyLayout = GetKeyboardLayout(0);
|
||||
}
|
||||
|
||||
CMSWindowsKeyMapper::~CMSWindowsKeyMapper()
|
||||
@@ -872,6 +872,12 @@ CMSWindowsKeyMapper::updateKey(KeyButton key, bool pressed)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsKeyMapper::setKeyLayout(HKL keyLayout)
|
||||
{
|
||||
m_keyLayout = keyLayout;
|
||||
}
|
||||
|
||||
KeyButton
|
||||
CMSWindowsKeyMapper::mapKey(IKeyState::Keystrokes& keys,
|
||||
const IKeyState& keyState, KeyID id,
|
||||
@@ -1057,8 +1063,8 @@ CMSWindowsKeyMapper::mapKey(IKeyState::Keystrokes& keys,
|
||||
}
|
||||
|
||||
KeyID
|
||||
CMSWindowsKeyMapper::mapKeyFromEvent(WPARAM vkCode, LPARAM info,
|
||||
KeyModifierMask* maskOut, bool* altgr) const
|
||||
CMSWindowsKeyMapper::mapKeyFromEvent(WPARAM charAndVirtKey,
|
||||
LPARAM info, KeyModifierMask* maskOut, bool* altgr) const
|
||||
{
|
||||
// note: known microsoft bugs
|
||||
// Q72583 -- MapVirtualKey() maps keypad keys incorrectly
|
||||
@@ -1066,59 +1072,18 @@ CMSWindowsKeyMapper::mapKeyFromEvent(WPARAM vkCode, LPARAM info,
|
||||
// 95,98,NT4: num pad scan code -> bad vk code except
|
||||
// SEPARATOR, MULTIPLY, SUBTRACT, ADD
|
||||
|
||||
HKL hkl = GetKeyboardLayout(0);
|
||||
char c = (char)((charAndVirtKey & 0xff00u) >> 8);
|
||||
UINT vkCode = (charAndVirtKey & 0xffu);
|
||||
|
||||
// get the scan code and the extended keyboard flag
|
||||
UINT scanCode = static_cast<UINT>((info & 0x00ff0000u) >> 16);
|
||||
int extended = ((info & 0x01000000) == 0) ? 0 : 1;
|
||||
bool press = ((info & 0x80000000) == 0);
|
||||
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 = s_virtualKey[vkCode][extended];
|
||||
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.
|
||||
// we don't want that translation so we clear the control modifier
|
||||
// state. however, if we want to simulate AltGr (which is ctrl+alt)
|
||||
// then we must not clear it.
|
||||
BYTE keys[256];
|
||||
memcpy(keys, m_keys, sizeof(keys));
|
||||
BYTE control = keys[VK_CONTROL];
|
||||
BYTE menu = keys[VK_MENU];
|
||||
if ((control & 0x80) == 0 || (menu & 0x80) == 0) {
|
||||
keys[VK_LCONTROL] = 0;
|
||||
keys[VK_RCONTROL] = 0;
|
||||
keys[VK_CONTROL] = 0;
|
||||
}
|
||||
else {
|
||||
keys[VK_LCONTROL] = 0x80;
|
||||
keys[VK_CONTROL] = 0x80;
|
||||
keys[VK_LMENU] = 0x80;
|
||||
keys[VK_MENU] = 0x80;
|
||||
}
|
||||
|
||||
// map to a character
|
||||
bool isMenu = ((menu & 0x80) != 0);
|
||||
c = mapToCharacter(vkCode, scanCode, keys, press, isMenu, hkl);
|
||||
|
||||
// if mapping failed and ctrl and alt are pressed then try again
|
||||
// with both not pressed. this handles the case where ctrl and
|
||||
// alt are being used as individual modifiers rather than AltGr.
|
||||
if (c == 0 && (control & 0x80) != 0 && (menu & 0x80) != 0) {
|
||||
keys[VK_LCONTROL] = 0;
|
||||
keys[VK_RCONTROL] = 0;
|
||||
keys[VK_CONTROL] = 0;
|
||||
keys[VK_LMENU] = 0;
|
||||
keys[VK_RMENU] = 0;
|
||||
keys[VK_MENU] = 0;
|
||||
c = mapToCharacter(vkCode, scanCode, keys, press, isMenu, hkl);
|
||||
}
|
||||
|
||||
// map character to key id
|
||||
// not in table; map character to key id
|
||||
if (c != 0) {
|
||||
if ((c & 0x80u) != 0) {
|
||||
// character is not really ASCII. instead it's some
|
||||
@@ -1155,7 +1120,7 @@ CMSWindowsKeyMapper::mapKeyFromEvent(WPARAM vkCode, LPARAM info,
|
||||
// required (only because it solves the problems we've seen
|
||||
// so far). in the second, we'll use whatever the keyboard
|
||||
// state says.
|
||||
WORD virtualKeyAndModifierState = VkKeyScanEx(c, hkl);
|
||||
WORD virtualKeyAndModifierState = VkKeyScanEx(c, m_keyLayout);
|
||||
if (virtualKeyAndModifierState == 0xffff) {
|
||||
// there is no mapping. assume AltGr.
|
||||
LOG((CLOG_DEBUG1 "no VkKeyScan() mapping"));
|
||||
@@ -1233,8 +1198,7 @@ UINT
|
||||
CMSWindowsKeyMapper::keyToScanCode(KeyButton* virtualKey) const
|
||||
{
|
||||
// try mapping given virtual key
|
||||
HKL hkl = GetKeyboardLayout(0);
|
||||
UINT code = MapVirtualKeyEx((*virtualKey) & 0xffu, 0, hkl);
|
||||
UINT code = MapVirtualKeyEx((*virtualKey) & 0xffu, 0, m_keyLayout);
|
||||
if (code != 0) {
|
||||
return code;
|
||||
}
|
||||
@@ -1265,17 +1229,17 @@ CMSWindowsKeyMapper::keyToScanCode(KeyButton* virtualKey) const
|
||||
case VK_LSHIFT:
|
||||
case VK_RSHIFT:
|
||||
*virtualKey = VK_SHIFT;
|
||||
return MapVirtualKeyEx(VK_SHIFT, 0, hkl);
|
||||
return MapVirtualKeyEx(VK_SHIFT, 0, m_keyLayout);
|
||||
|
||||
case VK_LCONTROL:
|
||||
case VK_RCONTROL:
|
||||
*virtualKey = VK_CONTROL;
|
||||
return MapVirtualKeyEx(VK_CONTROL, 0, hkl);
|
||||
return MapVirtualKeyEx(VK_CONTROL, 0, m_keyLayout);
|
||||
|
||||
case VK_LMENU:
|
||||
case VK_RMENU:
|
||||
*virtualKey = VK_MENU;
|
||||
return MapVirtualKeyEx(VK_MENU, 0, hkl);
|
||||
return MapVirtualKeyEx(VK_MENU, 0, m_keyLayout);
|
||||
|
||||
default:
|
||||
return 0;
|
||||
@@ -1528,93 +1492,9 @@ CMSWindowsKeyMapper::isDeadChar(TCHAR c, HKL hkl, bool menu) const
|
||||
toAscii(' ', hkl, 0, &dummy);
|
||||
|
||||
// put old dead key back if there was one
|
||||
if (old == 2) {
|
||||
if (old == 1 && ascii != ' ') {
|
||||
toAscii(static_cast<TCHAR>(ascii & 0xffu), hkl, menu, &dummy);
|
||||
}
|
||||
|
||||
return isDead;
|
||||
}
|
||||
|
||||
bool
|
||||
CMSWindowsKeyMapper::putBackDeadChar(TCHAR c, HKL hkl, bool menu) const
|
||||
{
|
||||
return (toAscii(c, hkl, menu, NULL) < 0);
|
||||
}
|
||||
|
||||
TCHAR
|
||||
CMSWindowsKeyMapper::getSavedDeadChar(HKL hkl) const
|
||||
{
|
||||
WORD old;
|
||||
int nOld = toAscii(' ', hkl, false, &old);
|
||||
if (nOld == 1 || nOld == 2) {
|
||||
TCHAR c = static_cast<TCHAR>(old & 0xffu);
|
||||
if (nOld == 2 || isDeadChar(c, hkl, false)) {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char
|
||||
CMSWindowsKeyMapper::mapToCharacter(UINT vkCode, UINT scanCode,
|
||||
BYTE* keys, bool press, bool isMenu, HKL hkl) const
|
||||
{
|
||||
// get contents of keyboard layout buffer and clear out that
|
||||
// buffer. we don't want anything placed there by some other
|
||||
// app interfering and we need to put anything there back in
|
||||
// place when we're done.
|
||||
TCHAR oldDeadKey = getSavedDeadChar(hkl);
|
||||
|
||||
// put our previous dead key, if any, in the layout buffer
|
||||
putBackDeadChar(m_deadKey, hkl, false);
|
||||
m_deadKey = 0;
|
||||
|
||||
// process key
|
||||
WORD ascii;
|
||||
int result = ToAsciiEx(vkCode, scanCode, keys, &ascii,
|
||||
isMenu ? 1 : 0, hkl);
|
||||
|
||||
// if result is less than zero then it was a dead key
|
||||
char c = 0;
|
||||
if (result < 0) {
|
||||
// save dead key if a key press. we catch the dead key
|
||||
// release in the result == 2 case below.
|
||||
if (press) {
|
||||
m_deadKey = static_cast<TCHAR>(ascii & 0xffu);
|
||||
}
|
||||
}
|
||||
|
||||
// if result is 1 then the key was succesfully converted
|
||||
else if (result == 1) {
|
||||
c = static_cast<char>(ascii & 0xff);
|
||||
}
|
||||
|
||||
// if result is 2 and the two characters are the same and this
|
||||
// is a key release then a dead key was released. save the
|
||||
// dead key. if the two characters are the same and this is
|
||||
// not a release then a dead key was pressed twice. send the
|
||||
// dead key.
|
||||
else if (result == 2) {
|
||||
if (((ascii & 0xff00u) >> 8) == (ascii & 0x00ffu)) {
|
||||
if (!press) {
|
||||
m_deadKey = static_cast<TCHAR>(ascii & 0xffu);
|
||||
}
|
||||
else {
|
||||
putBackDeadChar(oldDeadKey, hkl, false);
|
||||
result = toAscii(' ', hkl, false, &ascii);
|
||||
c = static_cast<char>((ascii >> 8) & 0xffu);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// clear keyboard layout buffer. this removes any dead key we
|
||||
// may have just put there.
|
||||
toAscii(' ', hkl, false, NULL);
|
||||
|
||||
// restore keyboard layout buffer so a dead key inserted by
|
||||
// another app doesn't disappear mysteriously (from its point
|
||||
// of view).
|
||||
putBackDeadChar(oldDeadKey, hkl, false);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user