Create virtual key up events for all pressed keys when the display loses focus.
This is a workaround for missed key events and incorrect key state reporting. This is actually a cleaner solution to the previous workaround on Windows and works nicely on Linux too.
This commit is contained in:
parent
035a4d679b
commit
42ccc83499
|
@ -1125,6 +1125,8 @@ final class LinuxDisplay implements DisplayImplementation {
|
|||
private void releaseInput() {
|
||||
if (isLegacyFullscreen() || input_released)
|
||||
return;
|
||||
if ( keyboard != null )
|
||||
keyboard.releaseAll();
|
||||
input_released = true;
|
||||
updateInputGrab();
|
||||
if (current_window_mode == FULLSCREEN_NETWM) {
|
||||
|
|
|
@ -296,7 +296,7 @@ final class LinuxKeyboard {
|
|||
return keycode;
|
||||
}
|
||||
|
||||
private byte getKeyState(int event_type) {
|
||||
private static byte getKeyState(int event_type) {
|
||||
switch (event_type) {
|
||||
case LinuxEvent.KeyPress:
|
||||
return 1;
|
||||
|
@ -307,10 +307,22 @@ final class LinuxKeyboard {
|
|||
}
|
||||
}
|
||||
|
||||
/** This is called when the window loses focus: we release all currently pressed keys. */
|
||||
void releaseAll() {
|
||||
for ( int i = 0; i < key_down_buffer.length; i++ ) {
|
||||
if ( key_down_buffer[i] != 0 ) {
|
||||
key_down_buffer[i] = 0;
|
||||
putKeyboardEvent(i, (byte)0, 0, 0L, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleKeyEvent(long event_ptr, long millis, int event_type, int event_keycode, int event_state) {
|
||||
int keycode = getKeycode(event_ptr, event_state);
|
||||
byte key_state = getKeyState(event_type);
|
||||
boolean repeat = key_state == key_down_buffer[keycode];
|
||||
if ( repeat && event_type == LinuxEvent.KeyRelease ) // This can happen for modifier keys after losing and regaining focus.
|
||||
return;
|
||||
key_down_buffer[keycode] = key_state;
|
||||
long nanos = millis*1000000;
|
||||
if (event_type == LinuxEvent.KeyPress) {
|
||||
|
|
|
@ -362,7 +362,7 @@ final class WindowsDisplay implements DisplayImplementation {
|
|||
/*
|
||||
* Called when the application is alt-tabbed to or from
|
||||
*/
|
||||
private void appActivate(boolean active) {
|
||||
private void appActivate(boolean active, long millis) {
|
||||
if (inAppActivate) {
|
||||
return;
|
||||
}
|
||||
|
@ -379,14 +379,15 @@ final class WindowsDisplay implements DisplayImplementation {
|
|||
redoMakeContextCurrent = true;
|
||||
if (Display.isFullscreen())
|
||||
updateClipping();
|
||||
|
||||
} else {
|
||||
if ( keyboard != null )
|
||||
keyboard.fireLostKeyEvents();
|
||||
} else if (Display.isFullscreen()) {
|
||||
keyboard.releaseAll(millis);
|
||||
if ( Display.isFullscreen() ) {
|
||||
showWindow(getHwnd(), SW_SHOWMINNOACTIVE);
|
||||
resetDisplayMode();
|
||||
} else
|
||||
updateClipping();
|
||||
}
|
||||
updateCursor();
|
||||
inAppActivate = false;
|
||||
}
|
||||
|
@ -997,10 +998,10 @@ final class WindowsDisplay implements DisplayImplementation {
|
|||
return defWindowProc(hwnd, msg, wParam, lParam);
|
||||
}
|
||||
case WM_KILLFOCUS:
|
||||
appActivate(false);
|
||||
appActivate(false, millis);
|
||||
return 0L;
|
||||
case WM_SETFOCUS:
|
||||
appActivate(true);
|
||||
appActivate(true, millis);
|
||||
return 0L;
|
||||
case WM_MOUSEACTIVATE:
|
||||
if ( parent != null ) {
|
||||
|
|
|
@ -122,6 +122,18 @@ final class WindowsKeyboard {
|
|||
return (GetAsyncKeyState(virt_key) & 0x8000) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called when the window loses focus: we release all currently pressed keys. If a key has been pressed (or hasn't been released at all), before we
|
||||
* regain focus, we'll start receiving repeat press events. We'll treat the first of those as a non-repeat press.
|
||||
*/
|
||||
void releaseAll(long millis) {
|
||||
for ( int i = 0; i < virt_key_down_buffer.length; i++ ) {
|
||||
if ( isKeyPressed(virt_key_down_buffer[i]) ) {
|
||||
handleKey(i, 0, false, (byte)0, millis, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handleKey(int virt_key, int scan_code, boolean extended, byte event_state, long millis, boolean repeat) {
|
||||
virt_key = translateExtended(virt_key, scan_code, extended);
|
||||
if ( !repeat && isKeyPressed(event_state) == isKeyPressed(virt_key_down_buffer[virt_key]) )
|
||||
|
@ -132,6 +144,7 @@ final class WindowsKeyboard {
|
|||
int keycode = WindowsKeycodes.mapVirtualKeyToLWJGLCode(virt_key);
|
||||
if (keycode < key_down_buffer.length) {
|
||||
key_down_buffer[keycode] = event_state;
|
||||
repeat &= isKeyPressed(virt_key_down_buffer[virt_key]); // Treat the first repeat event after releaseAll() as a non-repeat press.
|
||||
virt_key_down_buffer[virt_key] = event_state;
|
||||
}
|
||||
retained_key_code = keycode;
|
||||
|
@ -141,13 +154,6 @@ final class WindowsKeyboard {
|
|||
retained_repeat = repeat;
|
||||
}
|
||||
|
||||
void fireLostKeyEvents() {
|
||||
for ( int i = 0; i < virt_key_down_buffer.length; i++ ) {
|
||||
if ( isKeyPressed(virt_key_down_buffer[i]) && !isKeyPressedAsync(i) )
|
||||
handleKey(i, 0, false, (byte)0, 0L, false);
|
||||
}
|
||||
}
|
||||
|
||||
void handleChar(int event_char, long millis, boolean repeat) {
|
||||
if (has_retained_event && retained_char != 0)
|
||||
flushRetained();
|
||||
|
|
Loading…
Reference in New Issue