diff --git a/terminal-emulator/src/main/java/com/termux/terminal/KeyHandler.java b/terminal-emulator/src/main/java/com/termux/terminal/KeyHandler.java index a4d0f1ac..254f5e3a 100644 --- a/terminal-emulator/src/main/java/com/termux/terminal/KeyHandler.java +++ b/terminal-emulator/src/main/java/com/termux/terminal/KeyHandler.java @@ -59,6 +59,7 @@ public final class KeyHandler { public static final int KEYMOD_ALT = 0x80000000; public static final int KEYMOD_CTRL = 0x40000000; public static final int KEYMOD_SHIFT = 0x20000000; + public static final int KEYMOD_NUM_LOCK = 0x10000000; private static final Map TERMCAP_TO_KEYCODE = new HashMap<>(); @@ -145,10 +146,16 @@ public final class KeyHandler { keyMod |= KEYMOD_ALT; keyCode &= ~KEYMOD_ALT; } + if ((keyCode & KEYMOD_NUM_LOCK) != 0) { + keyMod |= KEYMOD_NUM_LOCK; + keyCode &= ~KEYMOD_NUM_LOCK; + } return getCode(keyCode, keyMod, cursorKeysApplication, keypadApplication); } public static String getCode(int keyCode, int keyMode, boolean cursorApp, boolean keypadApplication) { + boolean numLockOn = (keyMode & KEYMOD_NUM_LOCK) != 0; + keyMode &= ~KEYMOD_NUM_LOCK; switch (keyCode) { case KEYCODE_DPAD_CENTER: return "\015"; @@ -228,8 +235,11 @@ public final class KeyHandler { // Just do what xterm and gnome-terminal does: return prefix + (((keyMode & KEYMOD_CTRL) == 0) ? "\u007F" : "\u0008"); case KEYCODE_NUM_LOCK: - return "\033OP"; - + if (keypadApplication) { + return "\033OP"; + } else { + return null; + } case KEYCODE_SPACE: // If ctrl is not down, return null so that it goes through normal input processing (which may e.g. cause a // combining accent to be written): @@ -249,31 +259,81 @@ public final class KeyHandler { case KEYCODE_NUMPAD_COMMA: return ","; case KEYCODE_NUMPAD_DOT: - return keypadApplication ? "\033On" : "."; + if (numLockOn) { + return keypadApplication ? "\033On" : "."; + } else { + // DELETE + return transformForModifiers("\033[3", keyMode, '~'); + } case KEYCODE_NUMPAD_SUBTRACT: return keypadApplication ? transformForModifiers("\033O", keyMode, 'm') : "-"; case KEYCODE_NUMPAD_DIVIDE: return keypadApplication ? transformForModifiers("\033O", keyMode, 'o') : "/"; case KEYCODE_NUMPAD_0: - return keypadApplication ? transformForModifiers("\033O", keyMode, 'p') : "0"; + if (numLockOn) { + return keypadApplication ? transformForModifiers("\033O", keyMode, 'p') : "0"; + } else { + // INSERT + return transformForModifiers("\033[2", keyMode, '~'); + } case KEYCODE_NUMPAD_1: - return keypadApplication ? transformForModifiers("\033O", keyMode, 'q') : "1"; + if (numLockOn) { + return keypadApplication ? transformForModifiers("\033O", keyMode, 'q') : "1"; + } else { + // END + return (keyMode == 0) ? (cursorApp ? "\033OF" : "\033[F") : transformForModifiers("\033[1", keyMode, 'F'); + } case KEYCODE_NUMPAD_2: - return keypadApplication ? transformForModifiers("\033O", keyMode, 'r') : "2"; + if (numLockOn) { + return keypadApplication ? transformForModifiers("\033O", keyMode, 'r') : "2"; + } else { + // DOWN + return (keyMode == 0) ? (cursorApp ? "\033OB" : "\033[B") : transformForModifiers("\033[1", keyMode, 'B'); + } case KEYCODE_NUMPAD_3: - return keypadApplication ? transformForModifiers("\033O", keyMode, 's') : "3"; + if (numLockOn) { + return keypadApplication ? transformForModifiers("\033O", keyMode, 's') : "3"; + } else { + // PGDN + return "\033[6~"; + } case KEYCODE_NUMPAD_4: - return keypadApplication ? transformForModifiers("\033O", keyMode, 't') : "4"; + if (numLockOn) { + return keypadApplication ? transformForModifiers("\033O", keyMode, 't') : "4"; + } else { + // LEFT + return (keyMode == 0) ? (cursorApp ? "\033OD" : "\033[D") : transformForModifiers("\033[1", keyMode, 'D'); + } case KEYCODE_NUMPAD_5: return keypadApplication ? transformForModifiers("\033O", keyMode, 'u') : "5"; case KEYCODE_NUMPAD_6: - return keypadApplication ? transformForModifiers("\033O", keyMode, 'v') : "6"; + if (numLockOn) { + return keypadApplication ? transformForModifiers("\033O", keyMode, 'v') : "6"; + } else { + // RIGHT + return (keyMode == 0) ? (cursorApp ? "\033OC" : "\033[C") : transformForModifiers("\033[1", keyMode, 'C'); + } case KEYCODE_NUMPAD_7: - return keypadApplication ? transformForModifiers("\033O", keyMode, 'w') : "7"; + if (numLockOn) { + return keypadApplication ? transformForModifiers("\033O", keyMode, 'w') : "7"; + } else { + // HOME + return (keyMode == 0) ? (cursorApp ? "\033OH" : "\033[H") : transformForModifiers("\033[1", keyMode, 'H'); + } case KEYCODE_NUMPAD_8: - return keypadApplication ? transformForModifiers("\033O", keyMode, 'x') : "8"; + if (numLockOn) { + return keypadApplication ? transformForModifiers("\033O", keyMode, 'x') : "8"; + } else { + // UP + return (keyMode == 0) ? (cursorApp ? "\033OA" : "\033[A") : transformForModifiers("\033[1", keyMode, 'A'); + } case KEYCODE_NUMPAD_9: - return keypadApplication ? transformForModifiers("\033O", keyMode, 'y') : "9"; + if (numLockOn) { + return keypadApplication ? transformForModifiers("\033O", keyMode, 'y') : "9"; + } else { + // PGUP + return "\033[5~"; + } case KEYCODE_NUMPAD_EQUALS: return keypadApplication ? transformForModifiers("\033O", keyMode, 'X') : "="; } diff --git a/terminal-emulator/src/test/java/com/termux/terminal/KeyHandlerTest.java b/terminal-emulator/src/test/java/com/termux/terminal/KeyHandlerTest.java index 0826c7fc..15b23761 100644 --- a/terminal-emulator/src/test/java/com/termux/terminal/KeyHandlerTest.java +++ b/terminal-emulator/src/test/java/com/termux/terminal/KeyHandlerTest.java @@ -174,18 +174,30 @@ public class KeyHandlerTest extends TestCase { assertKeysEquals("\033[23;2~", KeyHandler.getCode(KeyEvent.KEYCODE_F11, KeyHandler.KEYMOD_SHIFT, false, false)); assertKeysEquals("\033[24;2~", KeyHandler.getCode(KeyEvent.KEYCODE_F12, KeyHandler.KEYMOD_SHIFT, false, false)); - assertKeysEquals("0", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_0, 0, false, false)); - assertKeysEquals("1", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_1, 0, false, false)); - assertKeysEquals("2", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_2, 0, false, false)); - assertKeysEquals("3", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_3, 0, false, false)); - assertKeysEquals("4", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_4, 0, false, false)); - assertKeysEquals("5", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_5, 0, false, false)); - assertKeysEquals("6", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_6, 0, false, false)); - assertKeysEquals("7", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_7, 0, false, false)); - assertKeysEquals("8", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_8, 0, false, false)); - assertKeysEquals("9", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_9, 0, false, false)); - assertKeysEquals(",", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_COMMA, 0, false, false)); - assertKeysEquals(".", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_DOT, 0, false, false)); + assertKeysEquals("0", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_0, KeyHandler.KEYMOD_NUM_LOCK, false, false)); + assertKeysEquals("1", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_1, KeyHandler.KEYMOD_NUM_LOCK, false, false)); + assertKeysEquals("2", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_2, KeyHandler.KEYMOD_NUM_LOCK, false, false)); + assertKeysEquals("3", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_3, KeyHandler.KEYMOD_NUM_LOCK, false, false)); + assertKeysEquals("4", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_4, KeyHandler.KEYMOD_NUM_LOCK, false, false)); + assertKeysEquals("5", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_5, KeyHandler.KEYMOD_NUM_LOCK, false, false)); + assertKeysEquals("6", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_6, KeyHandler.KEYMOD_NUM_LOCK, false, false)); + assertKeysEquals("7", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_7, KeyHandler.KEYMOD_NUM_LOCK, false, false)); + assertKeysEquals("8", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_8, KeyHandler.KEYMOD_NUM_LOCK, false, false)); + assertKeysEquals("9", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_9, KeyHandler.KEYMOD_NUM_LOCK, false, false)); + assertKeysEquals(",", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_COMMA, KeyHandler.KEYMOD_NUM_LOCK, false, false)); + assertKeysEquals(".", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_DOT, KeyHandler.KEYMOD_NUM_LOCK, false, false)); + + assertKeysEquals("\033[2~", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_0, 0, false, false)); + assertKeysEquals("\033[F", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_1, 0, false, false)); + assertKeysEquals("\033[B", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_2, 0, false, false)); + assertKeysEquals("\033[6~", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_3, 0, false, false)); + assertKeysEquals("\033[D", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_4, 0, false, false)); + assertKeysEquals("5", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_5, 0, false, false)); + assertKeysEquals("\033[C", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_6, 0, false, false)); + assertKeysEquals("\033[H", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_7, 0, false, false)); + assertKeysEquals("\033[A", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_8, 0, false, false)); + assertKeysEquals("\033[5~", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_9, 0, false, false)); + assertKeysEquals("\033[3~", KeyHandler.getCode(KeyEvent.KEYCODE_NUMPAD_DOT, 0, false, false)); } } diff --git a/terminal-view/src/main/java/com/termux/view/TerminalView.java b/terminal-view/src/main/java/com/termux/view/TerminalView.java index 41fe31da..5f2b5949 100644 --- a/terminal-view/src/main/java/com/termux/view/TerminalView.java +++ b/terminal-view/src/main/java/com/termux/view/TerminalView.java @@ -591,6 +591,7 @@ public final class TerminalView extends View { if (controlDown) keyMod |= KeyHandler.KEYMOD_CTRL; if (event.isAltPressed() || leftAltDown) keyMod |= KeyHandler.KEYMOD_ALT; if (event.isShiftPressed()) keyMod |= KeyHandler.KEYMOD_SHIFT; + if (event.isNumLockOn()) keyMod |= KeyHandler.KEYMOD_NUM_LOCK; if (!event.isFunctionPressed() && handleKeyCode(keyCode, keyMod)) { if (LOG_KEY_EVENTS) Log.i(EmulatorDebug.LOG_TAG, "handleKeyCode() took key event"); return true;