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:
crs
2004-03-08 20:53:32 +00:00
parent f068232643
commit 9e995bedbf
6 changed files with 353 additions and 277 deletions

View File

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