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() {
|
private void releaseInput() {
|
||||||
if (isLegacyFullscreen() || input_released)
|
if (isLegacyFullscreen() || input_released)
|
||||||
return;
|
return;
|
||||||
|
if ( keyboard != null )
|
||||||
|
keyboard.releaseAll();
|
||||||
input_released = true;
|
input_released = true;
|
||||||
updateInputGrab();
|
updateInputGrab();
|
||||||
if (current_window_mode == FULLSCREEN_NETWM) {
|
if (current_window_mode == FULLSCREEN_NETWM) {
|
||||||
|
|
|
@ -296,7 +296,7 @@ final class LinuxKeyboard {
|
||||||
return keycode;
|
return keycode;
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte getKeyState(int event_type) {
|
private static byte getKeyState(int event_type) {
|
||||||
switch (event_type) {
|
switch (event_type) {
|
||||||
case LinuxEvent.KeyPress:
|
case LinuxEvent.KeyPress:
|
||||||
return 1;
|
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) {
|
private void handleKeyEvent(long event_ptr, long millis, int event_type, int event_keycode, int event_state) {
|
||||||
int keycode = getKeycode(event_ptr, event_state);
|
int keycode = getKeycode(event_ptr, event_state);
|
||||||
byte key_state = getKeyState(event_type);
|
byte key_state = getKeyState(event_type);
|
||||||
boolean repeat = key_state == key_down_buffer[keycode];
|
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;
|
key_down_buffer[keycode] = key_state;
|
||||||
long nanos = millis*1000000;
|
long nanos = millis*1000000;
|
||||||
if (event_type == LinuxEvent.KeyPress) {
|
if (event_type == LinuxEvent.KeyPress) {
|
||||||
|
|
|
@ -362,7 +362,7 @@ final class WindowsDisplay implements DisplayImplementation {
|
||||||
/*
|
/*
|
||||||
* Called when the application is alt-tabbed to or from
|
* Called when the application is alt-tabbed to or from
|
||||||
*/
|
*/
|
||||||
private void appActivate(boolean active) {
|
private void appActivate(boolean active, long millis) {
|
||||||
if (inAppActivate) {
|
if (inAppActivate) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -379,14 +379,15 @@ final class WindowsDisplay implements DisplayImplementation {
|
||||||
redoMakeContextCurrent = true;
|
redoMakeContextCurrent = true;
|
||||||
if (Display.isFullscreen())
|
if (Display.isFullscreen())
|
||||||
updateClipping();
|
updateClipping();
|
||||||
|
} else {
|
||||||
if ( keyboard != null )
|
if ( keyboard != null )
|
||||||
keyboard.fireLostKeyEvents();
|
keyboard.releaseAll(millis);
|
||||||
} else if (Display.isFullscreen()) {
|
if ( Display.isFullscreen() ) {
|
||||||
showWindow(getHwnd(), SW_SHOWMINNOACTIVE);
|
showWindow(getHwnd(), SW_SHOWMINNOACTIVE);
|
||||||
resetDisplayMode();
|
resetDisplayMode();
|
||||||
} else
|
} else
|
||||||
updateClipping();
|
updateClipping();
|
||||||
|
}
|
||||||
updateCursor();
|
updateCursor();
|
||||||
inAppActivate = false;
|
inAppActivate = false;
|
||||||
}
|
}
|
||||||
|
@ -997,10 +998,10 @@ final class WindowsDisplay implements DisplayImplementation {
|
||||||
return defWindowProc(hwnd, msg, wParam, lParam);
|
return defWindowProc(hwnd, msg, wParam, lParam);
|
||||||
}
|
}
|
||||||
case WM_KILLFOCUS:
|
case WM_KILLFOCUS:
|
||||||
appActivate(false);
|
appActivate(false, millis);
|
||||||
return 0L;
|
return 0L;
|
||||||
case WM_SETFOCUS:
|
case WM_SETFOCUS:
|
||||||
appActivate(true);
|
appActivate(true, millis);
|
||||||
return 0L;
|
return 0L;
|
||||||
case WM_MOUSEACTIVATE:
|
case WM_MOUSEACTIVATE:
|
||||||
if ( parent != null ) {
|
if ( parent != null ) {
|
||||||
|
|
|
@ -122,6 +122,18 @@ final class WindowsKeyboard {
|
||||||
return (GetAsyncKeyState(virt_key) & 0x8000) != 0;
|
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) {
|
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);
|
virt_key = translateExtended(virt_key, scan_code, extended);
|
||||||
if ( !repeat && isKeyPressed(event_state) == isKeyPressed(virt_key_down_buffer[virt_key]) )
|
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);
|
int keycode = WindowsKeycodes.mapVirtualKeyToLWJGLCode(virt_key);
|
||||||
if (keycode < key_down_buffer.length) {
|
if (keycode < key_down_buffer.length) {
|
||||||
key_down_buffer[keycode] = event_state;
|
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;
|
virt_key_down_buffer[virt_key] = event_state;
|
||||||
}
|
}
|
||||||
retained_key_code = keycode;
|
retained_key_code = keycode;
|
||||||
|
@ -141,13 +154,6 @@ final class WindowsKeyboard {
|
||||||
retained_repeat = repeat;
|
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) {
|
void handleChar(int event_char, long millis, boolean repeat) {
|
||||||
if (has_retained_event && retained_char != 0)
|
if (has_retained_event && retained_char != 0)
|
||||||
flushRetained();
|
flushRetained();
|
||||||
|
|
Loading…
Reference in New Issue