From 20f228440da24cdb0cf87747d166c7f4519a9908 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Fri, 10 Feb 2012 06:48:54 -0600 Subject: [PATCH] Decent support for Nexus 7 + Bluetooth keyboard I basically ripped out the ctrl/alt/shift handling (sticky keys), hardcoded a bunch of stuff about function keys and other keys not directly known to Android, and hacked the search key into the home key. Now things work pretty well with my (motorola branded?) bt keyboard. (This has been squashed onto some odd old commits for my HTC Detail's physical keyboard, but I suspect not much of that work is left now..) --- src/org/connectbot/ConsoleActivity.java | 27 ++-- .../connectbot/service/TerminalKeyListener.java | 210 +++++++++++++++----- 2 files changed, 179 insertions(+), 58 deletions(-) diff --git a/src/org/connectbot/ConsoleActivity.java b/src/org/connectbot/ConsoleActivity.java index 5882a84..81a3877 100644 --- a/src/org/connectbot/ConsoleActivity.java +++ b/src/org/connectbot/ConsoleActivity.java @@ -272,6 +272,9 @@ public class ConsoleActivity extends Activity { hardKeyboard = getResources().getConfiguration().keyboard == Configuration.KEYBOARD_QWERTY; + + Log.d(TAG, "hardKeyboard ? " + hardKeyboard); + this.setContentView(R.layout.act_console); clipboard = (ClipboardManager)getSystemService(CLIPBOARD_SERVICE); @@ -631,8 +634,8 @@ public class ConsoleActivity extends Activity { menu.setQwertyMode(true); disconnect = menu.add(R.string.list_host_disconnect); - if (hardKeyboard) - disconnect.setAlphabeticShortcut('w'); + //if (hardKeyboard) + //disconnect.setAlphabeticShortcut('w'); if (!sessionOpen && disconnected) disconnect.setTitle(R.string.console_menu_close); disconnect.setEnabled(activeTerminal); @@ -649,8 +652,8 @@ public class ConsoleActivity extends Activity { }); copy = menu.add(R.string.console_menu_copy); - if (hardKeyboard) - copy.setAlphabeticShortcut('c'); + //if (hardKeyboard) + //copy.setAlphabeticShortcut('c'); copy.setIcon(android.R.drawable.ic_menu_set_as); copy.setEnabled(activeTerminal); copy.setOnMenuItemClickListener(new OnMenuItemClickListener() { @@ -674,8 +677,8 @@ public class ConsoleActivity extends Activity { }); paste = menu.add(R.string.console_menu_paste); - if (hardKeyboard) - paste.setAlphabeticShortcut('v'); + //if (hardKeyboard) + //paste.setAlphabeticShortcut('v'); paste.setIcon(android.R.drawable.ic_menu_edit); paste.setEnabled(clipboard.hasText() && sessionOpen); paste.setOnMenuItemClickListener(new OnMenuItemClickListener() { @@ -693,8 +696,8 @@ public class ConsoleActivity extends Activity { }); portForward = menu.add(R.string.console_menu_portforwards); - if (hardKeyboard) - portForward.setAlphabeticShortcut('f'); + //if (hardKeyboard) + //portForward.setAlphabeticShortcut('f'); portForward.setIcon(android.R.drawable.ic_menu_manage); portForward.setEnabled(sessionOpen && canForwardPorts); portForward.setOnMenuItemClickListener(new OnMenuItemClickListener() { @@ -710,8 +713,8 @@ public class ConsoleActivity extends Activity { }); urlscan = menu.add(R.string.console_menu_urlscan); - if (hardKeyboard) - urlscan.setAlphabeticShortcut('u'); + //if (hardKeyboard) + //urlscan.setAlphabeticShortcut('u'); urlscan.setIcon(android.R.drawable.ic_menu_search); urlscan.setEnabled(activeTerminal); urlscan.setOnMenuItemClickListener(new OnMenuItemClickListener() { @@ -736,8 +739,8 @@ public class ConsoleActivity extends Activity { }); resize = menu.add(R.string.console_menu_resize); - if (hardKeyboard) - resize.setAlphabeticShortcut('s'); + //if (hardKeyboard) + //resize.setAlphabeticShortcut('s'); resize.setIcon(android.R.drawable.ic_menu_crop); resize.setEnabled(sessionOpen); resize.setOnMenuItemClickListener(new OnMenuItemClickListener() { diff --git a/src/org/connectbot/service/TerminalKeyListener.java b/src/org/connectbot/service/TerminalKeyListener.java index 952f3cd..8c3ee2c 100644 --- a/src/org/connectbot/service/TerminalKeyListener.java +++ b/src/org/connectbot/service/TerminalKeyListener.java @@ -43,6 +43,14 @@ import de.mud.terminal.vt320; public class TerminalKeyListener implements OnKeyListener, OnSharedPreferenceChangeListener { private static final String TAG = "ConnectBot.OnKeyListener"; + public final static int SCANCODE_DELETE = 111; + public final static int SCANCODE_END = 107; + public final static int SCANCODE_HOME = 102; + public final static int SCANCODE_PAGEDOWN = 109; + public final static int SCANCODE_PAGEUP = 104; + public final static int SCANCODE_PHONE = 169; + public final static int SCANCODE_RIGHTALT = 100; + public final static int META_CTRL_ON = 0x01; public final static int META_CTRL_LOCK = 0x02; public final static int META_ALT_ON = 0x04; @@ -61,6 +69,10 @@ public class TerminalKeyListener implements OnKeyListener, OnSharedPreferenceCha public final static int KEYCODE_ESCAPE = 111; public final static int HC_META_CTRL_ON = 4096; + // HTC Speedy-specific constant + public final static int KEYCODE_SPEEDY_QUESTION = 105; // KeyEvent.KEYCODE_BUTTON_R2 + public final static int KEYCODE_SPEEDY_PERIOD = 99; // KeyEvent.KEYCODE_BUTTON_X + // All the transient key codes public final static int META_TRANSIENT = META_CTRL_ON | META_ALT_ON | META_SHIFT_ON; @@ -111,47 +123,39 @@ public class TerminalKeyListener implements OnKeyListener, OnSharedPreferenceCha * Modify the keys to make more sense to a host then pass it to the transport. */ public boolean onKey(View v, int keyCode, KeyEvent event) { + + Log.d(TAG, String.format("keyCode=%d action=%d flags=%d label=%c scancode=%d", keyCode, event.getAction(), event.getFlags(), event.getDisplayLabel(), event.getScanCode())); try { final boolean hardKeyboardHidden = manager.hardKeyboardHidden; - // Ignore all key-up events except for the special keys - if (event.getAction() == KeyEvent.ACTION_UP) { - // There's nothing here for virtual keyboard users. - if (!hardKeyboard || (hardKeyboard && hardKeyboardHidden)) - return false; - - // skip keys if we aren't connected yet or have been disconnected - if (bridge.isDisconnected() || bridge.transport == null) - return false; - - if (PreferenceConstants.KEYMODE_RIGHT.equals(keymode)) { - if (keyCode == KeyEvent.KEYCODE_ALT_RIGHT - && (metaState & META_SLASH) != 0) { - metaState &= ~(META_SLASH | META_TRANSIENT); - bridge.transport.write('/'); - return true; - } else if (keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT - && (metaState & META_TAB) != 0) { - metaState &= ~(META_TAB | META_TRANSIENT); - bridge.transport.write(0x09); - return true; - } - } else if (PreferenceConstants.KEYMODE_LEFT.equals(keymode)) { - if (keyCode == KeyEvent.KEYCODE_ALT_LEFT - && (metaState & META_SLASH) != 0) { - metaState &= ~(META_SLASH | META_TRANSIENT); - bridge.transport.write('/'); - return true; - } else if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT - && (metaState & META_TAB) != 0) { - metaState &= ~(META_TAB | META_TRANSIENT); - bridge.transport.write(0x09); - return true; - } - } - - return false; - } + { + int metaStateMod = 0; + if (keyCode == KeyEvent.KEYCODE_ALT_RIGHT || keyCode == KeyEvent.KEYCODE_ALT_LEFT) { + metaStateMod = META_ALT_LOCK; + } else if(keyCode == KeyEvent.KEYCODE_SHIFT_LEFT || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT) { + metaStateMod = META_SHIFT_LOCK; + } else if(keyCode == KeyEvent.KEYCODE_CTRL_LEFT || keyCode == KeyEvent.KEYCODE_CTRL_RIGHT + || (keyCode == 0 && event.getScanCode() == SCANCODE_RIGHTALT)) { + metaStateMod = META_CTRL_LOCK; + } + if(metaStateMod != 0) { + int oldMetaState = metaState; + if (event.getAction() == KeyEvent.ACTION_UP) { + metaState &= ~metaStateMod; + } else if(event.getAction() == KeyEvent.ACTION_DOWN) { + metaState |= metaStateMod; + } + if(metaState != oldMetaState) + bridge.redraw(); + + Log.d(TAG, String.format("metaState %o -> %o", oldMetaState, metaState)); + return true; + } + } + + // Otherwise, key releases are not handled + if( event.getAction() == KeyEvent.ACTION_UP ) + return false; // check for terminal resizing keys if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) { @@ -182,16 +186,45 @@ public class TerminalKeyListener implements OnKeyListener, OnSharedPreferenceCha curMetaState |= KeyEvent.META_SHIFT_ON; } - if ((metaState & META_ALT_MASK) != 0) { - curMetaState |= KeyEvent.META_ALT_ON; + //if ((metaState & META_ALT_MASK) != 0) { + //curMetaState |= KeyEvent.META_ALT_ON; + //} + + if ((metaState & META_CTRL_MASK) != 0) { + curMetaState |= KeyEvent.META_CTRL_ON; } - int key = event.getUnicodeChar(curMetaState); - // no hard keyboard? ALT-k should pass through to below - if ((orgMetaState & KeyEvent.META_ALT_ON) != 0 && - (!hardKeyboard || hardKeyboardHidden)) { - key = 0; + // ~ { } [ ] + + int key = event.getUnicodeChar(curMetaState & KeyEvent.META_SHIFT_ON); + if(false) { + if(keyCode == KeyEvent.KEYCODE_COMMA) { + if((metaState & META_CTRL_MASK) != 0) key = '{'; + else if((metaState & META_SHIFT_MASK) != 0) key = '['; + else if((metaState & META_ALT_MASK) != 0) key = '<'; + } + else if(keyCode == KEYCODE_SPEEDY_PERIOD) { + if((metaState & META_CTRL_MASK) != 0) key = '}'; + else if((metaState & META_SHIFT_MASK) != 0) key = ']'; + else if((metaState & META_ALT_MASK) != 0) key = '>'; + } + else if(keyCode == KeyEvent.KEYCODE_AT) { + if((metaState & META_CTRL_MASK) != 0) key = '~'; + else if((metaState & META_SHIFT_MASK) != 0) key = '`'; + else if((metaState & META_ALT_MASK) != 0) key = '^'; + } + else if(keyCode == KEYCODE_SPEEDY_QUESTION) { + if((metaState & META_CTRL_MASK) != 0) { key = '\\'; metaState &= ~META_CTRL_MASK; } + else if((metaState & META_SHIFT_MASK) != 0) key = '!'; + else if((metaState & META_ALT_MASK) != 0) key = '|'; } + } + + // no hard keyboard? ALT-k should pass through to below + //if (false && (orgMetaState & KeyEvent.META_ALT_ON) != 0 && + //(!hardKeyboard || hardKeyboardHidden)) { + //key = 0; + //} if ((key & KeyCharacterMap.COMBINING_ACCENT) != 0) { mDeadKey = key & KeyCharacterMap.COMBINING_ACCENT_MASK; @@ -205,6 +238,7 @@ public class TerminalKeyListener implements OnKeyListener, OnSharedPreferenceCha final boolean printing = (key != 0); + Log.d(TAG, String.format("printing? metaState=0%o key=%d", metaState, key)); // otherwise pass through to existing session // print normal keys if (printing) { @@ -217,6 +251,10 @@ public class TerminalKeyListener implements OnKeyListener, OnSharedPreferenceCha bridge.redraw(); } + if ((lastMetaState & META_ALT_MASK) != 0) { + bridge.transport.write(033); + } + if ((metaState & META_CTRL_MASK) != 0) { metaState &= ~META_CTRL_ON; bridge.redraw(); @@ -231,7 +269,7 @@ public class TerminalKeyListener implements OnKeyListener, OnSharedPreferenceCha } // handle pressing f-keys - if ((hardKeyboard && !hardKeyboardHidden) + if (false && (hardKeyboard && !hardKeyboardHidden) && (curMetaState & KeyEvent.META_SHIFT_ON) != 0 && sendFunctionKey(keyCode)) return true; @@ -319,6 +357,65 @@ public class TerminalKeyListener implements OnKeyListener, OnSharedPreferenceCha // look for special chars switch(keyCode) { + case 0: + switch(event.getScanCode()) { + case SCANCODE_PAGEUP: + bridge.transport.write("\033[5~".getBytes(encoding)); + return true; + case SCANCODE_PAGEDOWN: + bridge.transport.write("\033[6~".getBytes(encoding)); + return true; + case SCANCODE_PHONE: // due to difficulty of using HOME key + case SCANCODE_HOME: + bridge.transport.write("\033[7~".getBytes(encoding)); + return true; + case SCANCODE_END: + bridge.transport.write("\033[8~".getBytes(encoding)); + return true; + case SCANCODE_DELETE: + bridge.transport.write("\033[3~".getBytes(encoding)); + return true; + } + break; + case KeyEvent.KEYCODE_MOVE_END: + bridge.transport.write("\033[8~".getBytes(encoding)); + return true; + case KeyEvent.KEYCODE_F1: + bridge.transport.write("\033[11".getBytes(encoding)); + return true; + case KeyEvent.KEYCODE_F2: + bridge.transport.write("\033[12".getBytes(encoding)); + return true; + case KeyEvent.KEYCODE_F3: + bridge.transport.write("\033[13".getBytes(encoding)); + return true; + case KeyEvent.KEYCODE_F4: + bridge.transport.write("\033[14".getBytes(encoding)); + return true; + case KeyEvent.KEYCODE_F5: + bridge.transport.write("\033[15".getBytes(encoding)); + return true; + case KeyEvent.KEYCODE_F6: + bridge.transport.write("\033[17".getBytes(encoding)); + return true; + case KeyEvent.KEYCODE_F7: + bridge.transport.write("\033[18".getBytes(encoding)); + return true; + case KeyEvent.KEYCODE_F8: + bridge.transport.write("\033[19".getBytes(encoding)); + return true; + case KeyEvent.KEYCODE_F9: + bridge.transport.write("\033[20".getBytes(encoding)); + return true; + case KeyEvent.KEYCODE_F10: + bridge.transport.write("\033[21".getBytes(encoding)); + return true; + case KeyEvent.KEYCODE_F11: + bridge.transport.write("\033[23".getBytes(encoding)); + return true; + case KeyEvent.KEYCODE_F12: + bridge.transport.write("\033[24".getBytes(encoding)); + return true; case KEYCODE_ESCAPE: sendEscape(); return true; @@ -345,6 +442,27 @@ public class TerminalKeyListener implements OnKeyListener, OnSharedPreferenceCha break; + case KeyEvent.KEYCODE_MENU: + if((event.getFlags() & KeyEvent.FLAG_VIRTUAL_HARD_KEY) == 0) { + metaPress(META_CTRL_ON); + return true; + } + break; + + case KeyEvent.KEYCODE_BACK: + if((event.getFlags() & KeyEvent.FLAG_VIRTUAL_HARD_KEY) == 0) { + sendEscape(); + return true; + } + break; + + case KeyEvent.KEYCODE_SEARCH: + if((event.getFlags() & KeyEvent.FLAG_VIRTUAL_HARD_KEY) == 0) { + sendEscape(); + return true; + } + break; + case KeyEvent.KEYCODE_DEL: ((vt320) buffer).keyPressed(vt320.KEY_BACK_SPACE, ' ', getStateForBuffer()); -- 1.7.0.4