Improve AltGr detection even further on Windows so we can detect the case when Ctrl and AltGr are pressed together.tags/v1.8.90
@@ -66,7 +66,8 @@ Client (classic, non-raw, mode) | |||
- CapsLock, NumLock | |||
- Shift, Ctrl | |||
- Alt, AltGr, Super [Win, X11] (FIXME: Ctrl+AltGr broken on Win) | |||
- Alt, AltGr, Super [Win, X11] | |||
- Ctrl+AltGr [Win] | |||
- Meta [X11] | |||
- Left/right identification (FIXME: broken for Shift on Win) | |||
- CmdL => AltL, CmdR => SuperL, AltL => ModeSwitch, AltR => Level3Shift [OS X] | |||
@@ -75,7 +76,6 @@ Client (classic, non-raw, mode) | |||
- CapsLock, Shift and AltGr affect symbol lookup | |||
- Ctrl does not affect symbol lookup | |||
- Ctrl+Alt+<ANY> sends the same symbol as <ANY> | |||
- Ctrl+AltGr+<ANY> sends the same symbol as AltGr+<ANY> (FIXME: broken on Win) | |||
- "Shift press, A press, Shift release, A release" should not send "a release" | |||
- Numpad: |
@@ -838,24 +838,18 @@ int Viewport::handleSystemEvent(void *event, void *data) | |||
// Ctrl+Alt. However the remote end might not be Windows, so we need | |||
// to merge those in to a single AltGr event. We detect this case | |||
// by seeing the two key events directly after each other with a very | |||
// short time between them (<50ms). | |||
// short time between them (<50ms) and supress the Ctrl event. | |||
if (self->altGrArmed) { | |||
self->altGrArmed = false; | |||
Fl::remove_timeout(handleAltGrTimeout); | |||
if (isExtended && (keyCode == 0x38) && (vKey == VK_MENU) && | |||
((msg->time - self->altGrCtrlTime) < 50)) { | |||
// FIXME: We fail to detect this if either Ctrl key is | |||
// first manually pressed as Windows then no longer | |||
// sends the fake Ctrl down event. It does however | |||
// happily send real Ctrl events even when AltGr | |||
// is already down. | |||
vlog.debug("Detected AltGr combination"); | |||
self->handleKeyPress(0xb8, XK_ISO_Level3_Shift); | |||
return 1; | |||
// Alt seen, so this is an AltGr sequence | |||
} else { | |||
// Not Alt, so fire the queued up Ctrl event | |||
self->handleKeyPress(0x1d, XK_Control_L); | |||
} | |||
self->handleKeyPress(0x1d, XK_Control_L); | |||
} | |||
if (keyCode == SCAN_FAKE) { | |||
@@ -917,12 +911,18 @@ int Viewport::handleSystemEvent(void *event, void *data) | |||
if ((keySym == XK_Shift_L) && (keyCode == 0x36)) | |||
keySym = XK_Shift_R; | |||
// Possible start of AltGr sequence? (see above) | |||
if ((keyCode == 0x1d) && (keySym == XK_Control_L)) { | |||
self->altGrArmed = true; | |||
self->altGrCtrlTime = msg->time; | |||
Fl::add_timeout(0.1, handleAltGrTimeout, self); | |||
return 1; | |||
// AltGr handling (see above) | |||
if (win32_has_altgr()) { | |||
if ((keyCode == 0xb8) && (keySym == XK_Alt_R)) | |||
keySym = XK_ISO_Level3_Shift; | |||
// Possible start of AltGr sequence? | |||
if ((keyCode == 0x1d) && (keySym == XK_Control_L)) { | |||
self->altGrArmed = true; | |||
self->altGrCtrlTime = msg->time; | |||
Fl::add_timeout(0.1, handleAltGrTimeout, self); | |||
return 1; | |||
} | |||
} | |||
self->handleKeyPress(keyCode, keySym); |
@@ -33,6 +33,9 @@ | |||
#define MAPVK_VK_TO_CHAR 2 | |||
#endif | |||
int has_altgr; | |||
HKL current_layout = 0; | |||
static HANDLE thread; | |||
static DWORD thread_id; | |||
@@ -300,3 +303,58 @@ int win32_vkey_to_keysym(UINT vkey, int extended) | |||
return NoSymbol; | |||
} | |||
int win32_has_altgr(void) | |||
{ | |||
BYTE orig_state[256]; | |||
BYTE altgr_state[256]; | |||
if (current_layout == GetKeyboardLayout(0)) | |||
return has_altgr; | |||
// Save current keyboard state so we can get things sane again after | |||
// we're done | |||
if (!GetKeyboardState(orig_state)) | |||
return 0; | |||
// We press Ctrl+Alt (Windows fake AltGr) and then test every key | |||
// to see if it produces a printable character. If so then we assume | |||
// AltGr is used in the current layout. | |||
has_altgr = 0; | |||
memset(altgr_state, 0, sizeof(altgr_state)); | |||
altgr_state[VK_CONTROL] = 0x80; | |||
altgr_state[VK_MENU] = 0x80; | |||
for (UINT vkey = 0;vkey <= 0xff;vkey++) { | |||
int ret; | |||
WCHAR wstr[10]; | |||
// Need to skip this one as it is a bit magical and will trigger | |||
// a false positive | |||
if (vkey == VK_PACKET) | |||
continue; | |||
ret = ToUnicode(vkey, 0, altgr_state, wstr, | |||
sizeof(wstr)/sizeof(wstr[0]), 0); | |||
if (ret == 1) { | |||
has_altgr = 1; | |||
break; | |||
} | |||
if (ret == -1) { | |||
// Dead key, need to clear out state before we proceed | |||
do { | |||
ret = ToUnicode(vkey, 0, altgr_state, wstr, | |||
sizeof(wstr)/sizeof(wstr[0]), 0); | |||
} while (ret < 0); | |||
} | |||
} | |||
SetKeyboardState(orig_state); | |||
current_layout = GetKeyboardLayout(0); | |||
return has_altgr; | |||
} |
@@ -32,6 +32,8 @@ void win32_disable_lowlevel_keyboard(HWND hwnd); | |||
int win32_vkey_to_keysym(UINT vkey, int extended); | |||
int win32_has_altgr(void); | |||
}; | |||
#endif |