mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-06 09:29:38 +01:00
JBR-7662: Fix key repeat manager sometimes not cancelling properly [WLToolkit]
(cherry picked from commit e1b1116bb9)
This commit is contained in:
@@ -38,13 +38,16 @@ class WLKeyboard {
|
||||
}
|
||||
|
||||
private class KeyRepeatManager {
|
||||
// Methods and fields should only be accessed from the EDT
|
||||
private final Timer timer = new Timer("WLKeyboard.KeyRepeatManager", true);
|
||||
private TimerTask currentRepeatTask;
|
||||
private int delayBeforeRepeatMillis;
|
||||
private int delayBetweenRepeatMillis;
|
||||
|
||||
// called from native code
|
||||
void setRepeatInfo(int charsPerSecond, int delayMillis) {
|
||||
// this function receives (0, 0) when key repeat is disabled
|
||||
assert EventQueue.isDispatchThread();
|
||||
this.delayBeforeRepeatMillis = delayMillis;
|
||||
if (charsPerSecond > 0) {
|
||||
this.delayBetweenRepeatMillis = (int) (1000.0 / charsPerSecond);
|
||||
@@ -59,26 +62,33 @@ class WLKeyboard {
|
||||
return this.delayBeforeRepeatMillis > 0 || this.delayBetweenRepeatMillis > 0;
|
||||
}
|
||||
|
||||
// called from native code
|
||||
void cancelRepeat() {
|
||||
assert EventQueue.isDispatchThread();
|
||||
if (currentRepeatTask != null) {
|
||||
currentRepeatTask.cancel();
|
||||
currentRepeatTask = null;
|
||||
}
|
||||
}
|
||||
|
||||
// called from native code
|
||||
void startRepeat(long timestamp, int keycode) {
|
||||
assert EventQueue.isDispatchThread();
|
||||
cancelRepeat();
|
||||
if (keycode == 0 || !isRepeatEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
long delta = timestamp - System.currentTimeMillis();
|
||||
|
||||
currentRepeatTask = new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
EventQueue.invokeAndWait(() -> {
|
||||
handleKeyPress(delta + System.currentTimeMillis(), keycode, true);
|
||||
if (this == currentRepeatTask) {
|
||||
handleKeyPress(delta + System.currentTimeMillis(), keycode, true);
|
||||
}
|
||||
});
|
||||
} catch (InterruptedException ignored) {
|
||||
} catch (InvocationTargetException e) {
|
||||
@@ -136,6 +146,7 @@ class WLKeyboard {
|
||||
}
|
||||
|
||||
public void onLostFocus() {
|
||||
assert EventQueue.isDispatchThread();
|
||||
keyRepeatManager.cancelRepeat();
|
||||
cancelCompose();
|
||||
}
|
||||
|
||||
@@ -1204,6 +1204,9 @@ getJavaKeyCharForKeycode(xkb_keycode_t xkbKeycode) {
|
||||
// Posts an XKB keysym as KEY_TYPED events, without consulting the current compose state.
|
||||
static void
|
||||
handleKeyTypeNoCompose(long timestamp, xkb_keycode_t xkbKeycode) {
|
||||
#ifdef WL_KEYBOARD_DEBUG
|
||||
fprintf(stderr, "handleKeyTypeNoCompose: xkbKeycode = %d\n", xkbKeycode);
|
||||
#endif
|
||||
int bufSize = xkb.state_key_get_utf8(keyboard.state, xkbKeycode, NULL, 0) + 1;
|
||||
char buf[bufSize];
|
||||
xkb.state_key_get_utf8(keyboard.state, xkbKeycode, buf, bufSize);
|
||||
@@ -1213,8 +1216,17 @@ handleKeyTypeNoCompose(long timestamp, xkb_keycode_t xkbKeycode) {
|
||||
// Handles generating KEY_TYPED events for an XKB keysym, translating it using the active compose state
|
||||
static void
|
||||
handleKeyType(long timestamp, xkb_keycode_t xkbKeycode) {
|
||||
#ifdef WL_KEYBOARD_DEBUG
|
||||
fprintf(stderr, "handleKeyType(xkbKeycode = %d)\n", xkbKeycode);
|
||||
#endif
|
||||
xkb_keysym_t keysym = xkb.state_key_get_one_sym(keyboard.state, xkbKeycode);
|
||||
|
||||
#ifdef WL_KEYBOARD_DEBUG
|
||||
char buf[256];
|
||||
xkb.keysym_get_name(keysym, buf, sizeof buf);
|
||||
fprintf(stderr, "handleKeyType: keysym = %d (%s)\n", keysym, buf);
|
||||
#endif
|
||||
|
||||
if (!keyboard.composeState ||
|
||||
(xkb.compose_state_feed(keyboard.composeState, keysym) == XKB_COMPOSE_FEED_IGNORED)) {
|
||||
handleKeyTypeNoCompose(timestamp, xkbKeycode);
|
||||
@@ -1250,12 +1262,24 @@ handleKeyType(long timestamp, xkb_keycode_t xkbKeycode) {
|
||||
// 2. From the key repeat manager. In this case, isRepeat = true and isPressed = true.
|
||||
static void
|
||||
handleKey(long timestamp, uint32_t keycode, bool isPressed, bool isRepeat) {
|
||||
#ifdef WL_KEYBOARD_DEBUG
|
||||
fprintf(stderr, "handleKey(keycode = %d, isPressed = %d, isRepeat = %d)\n", keycode, isPressed, isRepeat);
|
||||
#endif
|
||||
JNIEnv *env = getEnv();
|
||||
|
||||
xkb_keycode_t xkbKeycode = keycode + 8;
|
||||
bool keyRepeats = xkb.keymap_key_repeats(keyboard.keymap, xkbKeycode);
|
||||
xkb_keysym_t keysym = translateKeycodeToKeysym(keycode, TRANSLATE_USING_ACTIVE_LAYOUT);
|
||||
xkb_keysym_t qwertyKeysym = translateKeycodeToKeysym(keycode, TRANSLATE_USING_QWERTY);
|
||||
|
||||
#ifdef WL_KEYBOARD_DEBUG
|
||||
char buf[256];
|
||||
xkb.keysym_get_name(keysym, buf, sizeof buf);
|
||||
fprintf(stderr, "handleKey: keysym = %d (%s)\n", keysym, buf);
|
||||
xkb.keysym_get_name(qwertyKeysym, buf, sizeof buf);
|
||||
fprintf(stderr, "handleKey: qwertyKeysym = %d (%s)\n", qwertyKeysym, buf);
|
||||
#endif
|
||||
|
||||
int javaKeyCode, javaExtendedKeyCode, javaKeyLocation;
|
||||
|
||||
// If the national layouts support is enabled, and the current keyboard is not ascii-capable,
|
||||
@@ -1288,6 +1312,10 @@ handleKey(long timestamp, uint32_t keycode, bool isPressed, bool isRepeat) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WL_KEYBOARD_DEBUG
|
||||
fprintf(stderr, "handleKey: javaKeyCode = %d\n", javaKeyCode);
|
||||
#endif
|
||||
|
||||
struct WLKeyEvent event = {
|
||||
.timestamp = timestamp,
|
||||
.id = isPressed ? java_awt_event_KeyEvent_KEY_PRESSED : java_awt_event_KeyEvent_KEY_RELEASED,
|
||||
@@ -1303,11 +1331,11 @@ handleKey(long timestamp, uint32_t keycode, bool isPressed, bool isRepeat) {
|
||||
if (isPressed) {
|
||||
handleKeyType(timestamp, xkbKeycode);
|
||||
|
||||
if (!isRepeat && xkb.keymap_key_repeats(keyboard.keymap, xkbKeycode)) {
|
||||
if (!isRepeat && keyRepeats) {
|
||||
(*env)->CallVoidMethod(env, keyboard.keyRepeatManager, startRepeatMID, timestamp, keycode);
|
||||
JNU_CHECK_EXCEPTION(env);
|
||||
}
|
||||
} else {
|
||||
} else if (keyRepeats) {
|
||||
(*env)->CallVoidMethod(env, keyboard.keyRepeatManager, cancelRepeatMID);
|
||||
JNU_CHECK_EXCEPTION(env);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user