diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/com/trilead/ssh2/crypto/KeyMaterial.java | 9 | ||||
-rw-r--r-- | src/com/trilead/ssh2/crypto/dh/DhGroupExchange.java | 6 | ||||
-rw-r--r-- | src/com/trilead/ssh2/crypto/dh/GenericDhExchange.java | 9 | ||||
-rw-r--r-- | src/com/trilead/ssh2/crypto/digest/HashForSSH2Types.java | 11 | ||||
-rw-r--r-- | src/com/trilead/ssh2/crypto/digest/MAC.java | 57 | ||||
-rw-r--r-- | src/com/trilead/ssh2/signature/ECDSASHA2Verify.java | 4 | ||||
-rw-r--r-- | src/com/trilead/ssh2/transport/KexManager.java | 21 | ||||
-rw-r--r-- | src/org/connectbot/ConsoleActivity.java | 81 | ||||
-rw-r--r-- | src/org/connectbot/GeneratePubkeyActivity.java | 7 | ||||
-rw-r--r-- | src/org/connectbot/HostListActivity.java | 2 | ||||
-rw-r--r-- | src/org/connectbot/service/KeyEventUtil.java | 149 | ||||
-rw-r--r-- | src/org/connectbot/service/TerminalKeyListener.java | 12 | ||||
-rw-r--r-- | src/org/connectbot/util/PreferenceConstants.java | 1 |
13 files changed, 290 insertions, 79 deletions
diff --git a/src/com/trilead/ssh2/crypto/KeyMaterial.java b/src/com/trilead/ssh2/crypto/KeyMaterial.java index 499422f..1dbd6c7 100644 --- a/src/com/trilead/ssh2/crypto/KeyMaterial.java +++ b/src/com/trilead/ssh2/crypto/KeyMaterial.java @@ -3,8 +3,6 @@ package com.trilead.ssh2.crypto; import java.math.BigInteger; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; import com.trilead.ssh2.crypto.digest.HashForSSH2Types; @@ -74,12 +72,7 @@ public class KeyMaterial { KeyMaterial km = new KeyMaterial(); - HashForSSH2Types sh; - try { - sh = new HashForSSH2Types(MessageDigest.getInstance(hashAlgo)); - } catch (NoSuchAlgorithmException e) { - throw new IllegalArgumentException(e); - } + HashForSSH2Types sh = new HashForSSH2Types(hashAlgo); km.initial_iv_client_to_server = calculateKey(sh, K, H, (byte) 'A', SessionID, blockSizeCS); diff --git a/src/com/trilead/ssh2/crypto/dh/DhGroupExchange.java b/src/com/trilead/ssh2/crypto/dh/DhGroupExchange.java index 2922284..a888950 100644 --- a/src/com/trilead/ssh2/crypto/dh/DhGroupExchange.java +++ b/src/com/trilead/ssh2/crypto/dh/DhGroupExchange.java @@ -87,10 +87,10 @@ public class DhGroupExchange this.k = f.modPow(x, p); } - public byte[] calculateH(byte[] clientversion, byte[] serverversion, byte[] clientKexPayload, - byte[] serverKexPayload, byte[] hostKey, DHGexParameters para) + public byte[] calculateH(String hashAlgo, byte[] clientversion, byte[] serverversion, + byte[] clientKexPayload, byte[] serverKexPayload, byte[] hostKey, DHGexParameters para) { - HashForSSH2Types hash = new HashForSSH2Types("SHA1"); + HashForSSH2Types hash = new HashForSSH2Types(hashAlgo); hash.updateByteString(clientversion); hash.updateByteString(serverversion); diff --git a/src/com/trilead/ssh2/crypto/dh/GenericDhExchange.java b/src/com/trilead/ssh2/crypto/dh/GenericDhExchange.java index d65490a..039ff75 100644 --- a/src/com/trilead/ssh2/crypto/dh/GenericDhExchange.java +++ b/src/com/trilead/ssh2/crypto/dh/GenericDhExchange.java @@ -4,8 +4,6 @@ package com.trilead.ssh2.crypto.dh; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.math.BigInteger; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; import com.trilead.ssh2.crypto.digest.HashForSSH2Types; import com.trilead.ssh2.log.Logger; @@ -71,12 +69,7 @@ public abstract class GenericDhExchange public byte[] calculateH(byte[] clientversion, byte[] serverversion, byte[] clientKexPayload, byte[] serverKexPayload, byte[] hostKey) throws UnsupportedEncodingException { - HashForSSH2Types hash; - try { - hash = new HashForSSH2Types(MessageDigest.getInstance(getHashAlgo())); - } catch (NoSuchAlgorithmException e) { - throw new UnsupportedOperationException(e); - } + HashForSSH2Types hash = new HashForSSH2Types(getHashAlgo()); if (log.isEnabled()) { diff --git a/src/com/trilead/ssh2/crypto/digest/HashForSSH2Types.java b/src/com/trilead/ssh2/crypto/digest/HashForSSH2Types.java index 9127d4e..6b0d6e3 100644 --- a/src/com/trilead/ssh2/crypto/digest/HashForSSH2Types.java +++ b/src/com/trilead/ssh2/crypto/digest/HashForSSH2Types.java @@ -16,19 +16,10 @@ public class HashForSSH2Types { MessageDigest md; - public HashForSSH2Types(MessageDigest md) - { - this.md = md; - } - public HashForSSH2Types(String type) { try { - if ("SHA1".equals(type) || "MD5".equals(type)) { - md = MessageDigest.getInstance(type); - } else { - throw new IllegalArgumentException("Unknown algorithm " + type); - } + md = MessageDigest.getInstance(type); } catch (NoSuchAlgorithmException e) { throw new RuntimeException("Unsupported algorithm " + type); } diff --git a/src/com/trilead/ssh2/crypto/digest/MAC.java b/src/com/trilead/ssh2/crypto/digest/MAC.java index 20c52fa..561599c 100644 --- a/src/com/trilead/ssh2/crypto/digest/MAC.java +++ b/src/com/trilead/ssh2/crypto/digest/MAC.java @@ -16,6 +16,36 @@ import javax.crypto.spec.SecretKeySpec; */ public final class MAC { + /** + * From http://tools.ietf.org/html/rfc4253 + */ + private static final String HMAC_MD5 = "hmac-md5"; + + /** + * From http://tools.ietf.org/html/rfc4253 + */ + private static final String HMAC_MD5_96 = "hmac-md5-96"; + + /** + * From http://tools.ietf.org/html/rfc4253 + */ + private static final String HMAC_SHA1 = "hmac-sha1"; + + /** + * From http://tools.ietf.org/html/rfc4253 + */ + private static final String HMAC_SHA1_96 = "hmac-sha1-96"; + + /** + * From http://tools.ietf.org/html/rfc6668 + */ + private static final String HMAC_SHA2_256 = "hmac-sha2-256"; + + /** + * From http://tools.ietf.org/html/rfc6668 + */ + private static final String HMAC_SHA2_512 = "hmac-sha2-512"; + Mac mac; int outSize; int macSize; @@ -23,7 +53,8 @@ public final class MAC /* Higher Priority First */ private static final String[] MAC_LIST = { - "hmac-sha1-96", "hmac-sha1", "hmac-md5-96", "hmac-md5" + HMAC_SHA2_256, HMAC_SHA2_512, + HMAC_SHA1_96, HMAC_SHA1, HMAC_MD5_96, HMAC_MD5 }; public final static String[] getMacList() @@ -39,28 +70,36 @@ public final class MAC public final static int getKeyLen(String type) { - if (type.equals("hmac-sha1")) + if (HMAC_SHA1.equals(type) || HMAC_SHA1_96.equals(type)) return 20; - if (type.equals("hmac-sha1-96")) - return 20; - if (type.equals("hmac-md5")) - return 16; - if (type.equals("hmac-md5-96")) + if (HMAC_MD5.equals(type) || HMAC_MD5_96.equals(type)) return 16; + if (HMAC_SHA2_256.equals(type)) + return 32; + if (HMAC_SHA2_512.equals(type)) + return 64; throw new IllegalArgumentException("Unkown algorithm " + type); } public MAC(String type, byte[] key) { try { - if ("hmac-sha1".equals(type) || "hmac-sha1-96".equals(type)) + if (HMAC_SHA1.equals(type) || HMAC_SHA1_96.equals(type)) { mac = Mac.getInstance("HmacSHA1"); } - else if ("hmac-md5".equals(type) || "hmac-md5-96".equals(type)) + else if (HMAC_MD5.equals(type) || HMAC_MD5_96.equals(type)) { mac = Mac.getInstance("HmacMD5"); } + else if (HMAC_SHA2_256.equals(type)) + { + mac = Mac.getInstance("HmacSHA256"); + } + else if (HMAC_SHA2_512.equals(type)) + { + mac = Mac.getInstance("HmacSHA512"); + } else throw new IllegalArgumentException("Unkown algorithm " + type); } catch (NoSuchAlgorithmException e) { diff --git a/src/com/trilead/ssh2/signature/ECDSASHA2Verify.java b/src/com/trilead/ssh2/signature/ECDSASHA2Verify.java index 49028e6..f139cdf 100644 --- a/src/com/trilead/ssh2/signature/ECDSASHA2Verify.java +++ b/src/com/trilead/ssh2/signature/ECDSASHA2Verify.java @@ -118,11 +118,11 @@ public class ECDSASHA2Verify { KeyFactory kf = KeyFactory.getInstance("EC"); return (ECPublicKey) kf.generatePublic(keySpec); } catch (NoSuchAlgorithmException nsae) { - IOException ioe = new IOException("No RSA KeyFactory available"); + IOException ioe = new IOException("No EC KeyFactory available"); ioe.initCause(nsae); throw ioe; } catch (InvalidKeySpecException ikse) { - IOException ioe = new IOException("No RSA KeyFactory available"); + IOException ioe = new IOException("No EC KeyFactory available"); ioe.initCause(ikse); throw ioe; } diff --git a/src/com/trilead/ssh2/transport/KexManager.java b/src/com/trilead/ssh2/transport/KexManager.java index 230047e..cd26530 100644 --- a/src/com/trilead/ssh2/transport/KexManager.java +++ b/src/com/trilead/ssh2/transport/KexManager.java @@ -61,6 +61,7 @@ public class KexManager KEX_ALGS.add("ecdh-sha2-nistp256"); KEX_ALGS.add("ecdh-sha2-nistp384"); KEX_ALGS.add("ecdh-sha2-nistp521"); + KEX_ALGS.add("diffie-hellman-group-exchange-sha256"); KEX_ALGS.add("diffie-hellman-group-exchange-sha1"); KEX_ALGS.add("diffie-hellman-group14-sha1"); KEX_ALGS.add("diffie-hellman-group1-sha1"); @@ -449,20 +450,24 @@ public class KexManager ignore_next_kex_packet = true; } - if (kxs.np.kex_algo.equals("diffie-hellman-group-exchange-sha1")) + if (kxs.np.kex_algo.equals("diffie-hellman-group-exchange-sha1") + || kxs.np.kex_algo.equals("diffie-hellman-group-exchange-sha256")) { if (kxs.dhgexParameters.getMin_group_len() == 0 || csh.server_versioncomment.matches("OpenSSH_2\\.([0-4]\\.|5\\.[0-2]).*")) { PacketKexDhGexRequestOld dhgexreq = new PacketKexDhGexRequestOld(kxs.dhgexParameters); tm.sendKexMessage(dhgexreq.getPayload()); - } else { PacketKexDhGexRequest dhgexreq = new PacketKexDhGexRequest(kxs.dhgexParameters); tm.sendKexMessage(dhgexreq.getPayload()); } - kxs.hashAlgo = "SHA1"; + if (kxs.np.kex_algo.endsWith("sha1")) { + kxs.hashAlgo = "SHA1"; + } else { + kxs.hashAlgo = "SHA-256"; + } kxs.state = 1; return; } @@ -538,7 +543,8 @@ public class KexManager if ((kxs == null) || (kxs.state == 0)) throw new IOException("Unexpected Kex submessage!"); - if (kxs.np.kex_algo.equals("diffie-hellman-group-exchange-sha1")) + if (kxs.np.kex_algo.equals("diffie-hellman-group-exchange-sha1") + || kxs.np.kex_algo.equals("diffie-hellman-group-exchange-sha256")) { if (kxs.state == 1) { @@ -579,9 +585,10 @@ public class KexManager try { - kxs.H = kxs.dhgx.calculateH(csh.getClientString(), csh.getServerString(), - kxs.localKEX.getPayload(), kxs.remoteKEX.getPayload(), dhgexrpl.getHostKey(), - kxs.dhgexParameters); + kxs.H = kxs.dhgx.calculateH(kxs.hashAlgo, + csh.getClientString(), csh.getServerString(), + kxs.localKEX.getPayload(), kxs.remoteKEX.getPayload(), + dhgexrpl.getHostKey(), kxs.dhgexParameters); } catch (IllegalArgumentException e) { diff --git a/src/org/connectbot/ConsoleActivity.java b/src/org/connectbot/ConsoleActivity.java index 5e34dc6..7aca08c 100644 --- a/src/org/connectbot/ConsoleActivity.java +++ b/src/org/connectbot/ConsoleActivity.java @@ -55,6 +55,7 @@ import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; +import android.view.Window; import android.view.WindowManager; import android.view.MenuItem.OnMenuItemClickListener; import android.view.View.OnClickListener; @@ -111,6 +112,9 @@ public class ConsoleActivity extends Activity { private TextView booleanPrompt; private Button booleanYes, booleanNo; + private RelativeLayout keyboardGroup; + private Runnable keyboardGroupHider; + private TextView empty; private Animation slide_left_in, slide_left_out, slide_right_in, slide_right_out, fade_stay_hidden, fade_out_delayed; @@ -133,6 +137,7 @@ public class ConsoleActivity extends Activity { private ActionBarWrapper actionBar; private boolean inActionBarMenu = false; + private boolean titleBarHide; private ServiceConnection connection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { @@ -260,6 +265,38 @@ public class ConsoleActivity extends Activity { booleanPromptGroup.setVisibility(View.GONE); } + private void showEmulatedKeys() { + keyboardGroup.startAnimation(keyboard_fade_in); + keyboardGroup.setVisibility(View.VISIBLE); + actionBar.show(); + + if (keyboardGroupHider != null) + handler.removeCallbacks(keyboardGroupHider); + keyboardGroupHider = new Runnable() { + public void run() { + if (keyboardGroup.getVisibility() == View.GONE || inActionBarMenu) + return; + + keyboardGroup.startAnimation(keyboard_fade_out); + keyboardGroup.setVisibility(View.GONE); + if (titleBarHide) { + actionBar.hide(); + } + keyboardGroupHider = null; + } + }; + handler.postDelayed(keyboardGroupHider, KEYBOARD_DISPLAY_TIME); + } + + private void hideEmulatedKeys() { + if (keyboardGroupHider != null) + handler.removeCallbacks(keyboardGroupHider); + keyboardGroup.setVisibility(View.GONE); + if (titleBarHide) { + actionBar.hide(); + } + } + // more like configureLaxMode -- enable network IO on UI thread private void configureStrictMode() { try { @@ -275,11 +312,16 @@ public class ConsoleActivity extends Activity { hardKeyboard = getResources().getConfiguration().keyboard == Configuration.KEYBOARD_QWERTY; - this.setContentView(R.layout.act_console); - clipboard = (ClipboardManager)getSystemService(CLIPBOARD_SERVICE); prefs = PreferenceManager.getDefaultSharedPreferences(this); + titleBarHide = prefs.getBoolean(PreferenceConstants.TITLEBARHIDE, false); + if (titleBarHide) { + getWindow().requestFeature(Window.FEATURE_ACTION_BAR_OVERLAY); + } + + this.setContentView(R.layout.act_console); + // hide status bar if requested by user if (prefs.getBoolean(PreferenceConstants.FULLSCREEN, false)) { getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, @@ -358,7 +400,7 @@ public class ConsoleActivity extends Activity { inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); - final RelativeLayout keyboardGroup = (RelativeLayout) findViewById(R.id.keyboard_group); + keyboardGroup = (RelativeLayout) findViewById(R.id.keyboard_group); mKeyboardButton = (ImageView) findViewById(R.id.button_keyboard); mKeyboardButton.setOnClickListener(new OnClickListener() { @@ -368,8 +410,7 @@ public class ConsoleActivity extends Activity { return; inputManager.showSoftInput(flip, InputMethodManager.SHOW_FORCED); - keyboardGroup.setVisibility(View.GONE); - actionBar.hide(); + hideEmulatedKeys(); } }); @@ -382,9 +423,7 @@ public class ConsoleActivity extends Activity { TerminalKeyListener handler = terminal.bridge.getKeyHandler(); handler.metaPress(TerminalKeyListener.OUR_CTRL_ON); - - keyboardGroup.setVisibility(View.GONE); - actionBar.hide(); + hideEmulatedKeys(); } }); @@ -397,21 +436,20 @@ public class ConsoleActivity extends Activity { TerminalKeyListener handler = terminal.bridge.getKeyHandler(); handler.sendEscape(); - - keyboardGroup.setVisibility(View.GONE); - actionBar.hide(); + hideEmulatedKeys(); } }); actionBar = ActionBarWrapper.getActionBar(this); actionBar.setDisplayHomeAsUpEnabled(true); - actionBar.hide(); + if (titleBarHide) { + actionBar.hide(); + } actionBar.addOnMenuVisibilityListener(new ActionBarWrapper.OnMenuVisibilityListener() { public void onMenuVisibilityChanged(boolean isVisible) { inActionBarMenu = isVisible; if (isVisible == false) { - keyboardGroup.setVisibility(View.GONE); - actionBar.hide(); + hideEmulatedKeys(); } } }); @@ -580,20 +618,7 @@ public class ConsoleActivity extends Activity { && event.getEventTime() - event.getDownTime() < CLICK_TIME && Math.abs(event.getX() - lastX) < MAX_CLICK_DISTANCE && Math.abs(event.getY() - lastY) < MAX_CLICK_DISTANCE) { - keyboardGroup.startAnimation(keyboard_fade_in); - keyboardGroup.setVisibility(View.VISIBLE); - actionBar.show(); - - handler.postDelayed(new Runnable() { - public void run() { - if (keyboardGroup.getVisibility() == View.GONE || inActionBarMenu) - return; - - keyboardGroup.startAnimation(keyboard_fade_out); - keyboardGroup.setVisibility(View.GONE); - actionBar.hide(); - } - }, KEYBOARD_DISPLAY_TIME); + showEmulatedKeys(); } // pass any touch events back to detector diff --git a/src/org/connectbot/GeneratePubkeyActivity.java b/src/org/connectbot/GeneratePubkeyActivity.java index 3a438c5..1b8995f 100644 --- a/src/org/connectbot/GeneratePubkeyActivity.java +++ b/src/org/connectbot/GeneratePubkeyActivity.java @@ -22,6 +22,7 @@ import java.security.KeyPairGenerator; import java.security.PrivateKey; import java.security.PublicKey; import java.security.SecureRandom; +import java.security.Security; import org.connectbot.bean.PubkeyBean; import org.connectbot.util.EntropyDialog; @@ -44,6 +45,7 @@ import android.view.View.OnFocusChangeListener; import android.widget.Button; import android.widget.CheckBox; import android.widget.EditText; +import android.widget.RadioButton; import android.widget.RadioGroup; import android.widget.RadioGroup.OnCheckedChangeListener; import android.widget.SeekBar; @@ -113,6 +115,11 @@ public class GeneratePubkeyActivity extends Activity implements OnEntropyGathere password1.addTextChangedListener(textChecker); password2.addTextChangedListener(textChecker); + // TODO add BC to provide EC for devices that don't have it. + if (Security.getProviders("KeyPairGenerator.EC") == null) { + ((RadioButton) findViewById(R.id.ec)).setEnabled(false); + } + keyTypeGroup.setOnCheckedChangeListener(new OnCheckedChangeListener() { public void onCheckedChanged(RadioGroup group, int checkedId) { diff --git a/src/org/connectbot/HostListActivity.java b/src/org/connectbot/HostListActivity.java index 5fa09a9..648b705 100644 --- a/src/org/connectbot/HostListActivity.java +++ b/src/org/connectbot/HostListActivity.java @@ -303,7 +303,7 @@ public class HostListActivity extends ListActivity { keys.setIcon(android.R.drawable.ic_lock_lock); keys.setIntent(new Intent(HostListActivity.this, PubkeyListActivity.class)); - MenuItem colors = menu.add("Colors"); + MenuItem colors = menu.add(R.string.title_colors); colors.setIcon(android.R.drawable.ic_menu_slideshow); colors.setIntent(new Intent(HostListActivity.this, ColorsActivity.class)); diff --git a/src/org/connectbot/service/KeyEventUtil.java b/src/org/connectbot/service/KeyEventUtil.java new file mode 100644 index 0000000..1362afa --- /dev/null +++ b/src/org/connectbot/service/KeyEventUtil.java @@ -0,0 +1,149 @@ +/* + * ConnectBot: simple, powerful, open-source SSH client for Android + * Copyright 2014 Torne Wuff + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.connectbot.service; + +import android.annotation.TargetApi; +import android.os.Build; +import android.view.KeyEvent; + +public class KeyEventUtil { + static final char CONTROL_LIMIT = ' '; + static final char PRINTABLE_LIMIT = '\u007e'; + static final char[] HEX_DIGITS = new char[] { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' + }; + + static String printableRepresentation(String source) { + if (source == null) + return null; + + final StringBuilder sb = new StringBuilder(); + final int limit = source.length(); + char[] hexbuf = null; + int pointer = 0; + + sb.append('"'); + while (pointer < limit) { + int ch = source.charAt(pointer++); + switch (ch) { + case '\0': + sb.append("\\0"); + break; + case '\t': + sb.append("\\t"); + break; + case '\n': + sb.append("\\n"); + break; + case '\r': + sb.append("\\r"); + break; + case '\"': + sb.append("\\\""); + break; + case '\\': + sb.append("\\\\"); + break; + default: + if (CONTROL_LIMIT <= ch && ch <= PRINTABLE_LIMIT) { + sb.append((char) ch); + } else { + sb.append("\\u"); + if (hexbuf == null) + hexbuf = new char[4]; + for (int offs = 4; offs > 0; ) { + hexbuf[--offs] = HEX_DIGITS[ch & 0xf]; + ch >>>= 4; + } + sb.append(hexbuf, 0, 4); + } + } + } + return sb.append('"').toString(); + } + + private static class ClassCompat { + private static final ClassCompat INSTANCE; + static { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) { + INSTANCE = new HCMR2AndNewer(); + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) { + INSTANCE = new HCMR1AndNewer(); + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) { + INSTANCE = new GingerbreadAndNewer(); + } else { + INSTANCE = new ClassCompat(); + } + } + + private ClassCompat() { + } + + public static void appendExtras(StringBuilder d, int keyCode, KeyEvent event) { + INSTANCE.appendForApi(d, keyCode, event); + } + + protected void appendForApi(StringBuilder d, int keyCode, KeyEvent event) { + } + + @TargetApi(9) + private static class GingerbreadAndNewer extends ClassCompat { + @Override + protected void appendForApi(StringBuilder d, int keyCode, KeyEvent event) { + super.appendForApi(d, keyCode, event); + d.append(", source=").append(event.getSource()); + + } + } + @TargetApi(12) + private static class HCMR1AndNewer extends GingerbreadAndNewer { + protected void appendForApi(StringBuilder d, int keyCode, KeyEvent event) { + super.appendForApi(d, keyCode, event); + d.append(", keyCodeToString=").append(KeyEvent.keyCodeToString(keyCode)); + } + } + + @TargetApi(13) + private static class HCMR2AndNewer extends HCMR1AndNewer { + @Override + protected void appendForApi(StringBuilder d, int keyCode, KeyEvent event) { + super.appendForApi(d, keyCode, event); + d.append(", modifiers=").append(Integer.toHexString(event.getModifiers())); + } + } + } + + public static String describeKeyEvent(int keyCode, KeyEvent event) { + StringBuilder d = new StringBuilder(); + d.append("keyCode=").append(keyCode); + d.append(", event.toString=").append(event.toString()); + d.append(", action=").append(event.getAction()); + d.append(", characters=").append(printableRepresentation(event.getCharacters())); + d.append(", deviceId=").append(event.getDeviceId()); + d.append(", displayLabel=").append((int) event.getDisplayLabel()); + d.append(", flags=0x").append(Integer.toHexString(event.getFlags())); + d.append(", printingKey=").append(event.isPrintingKey()); + d.append(", keyCode=").append(event.getKeyCode()); + d.append(", metaState=0x").append(Integer.toHexString(event.getMetaState())); + d.append(", number=").append((int) event.getNumber()); + d.append(", scanCode=").append(event.getScanCode()); + d.append(", unicodeChar=").append(event.getUnicodeChar()); + ClassCompat.appendExtras(d, keyCode, event); + return d.toString(); + } +} diff --git a/src/org/connectbot/service/TerminalKeyListener.java b/src/org/connectbot/service/TerminalKeyListener.java index 3f82259..7ff21df 100644 --- a/src/org/connectbot/service/TerminalKeyListener.java +++ b/src/org/connectbot/service/TerminalKeyListener.java @@ -64,7 +64,11 @@ public class TerminalKeyListener implements OnKeyListener, OnSharedPreferenceCha // backport constants from api level 11 private final static int KEYCODE_ESCAPE = 111; - private final static int HC_META_CTRL_ON = 4096; + private final static int HC_META_CTRL_ON = 0x1000; + private final static int HC_META_CTRL_LEFT_ON = 0x2000; + private final static int HC_META_CTRL_RIGHT_ON = 0x4000; + private final static int HC_META_CTRL_MASK = HC_META_CTRL_ON | HC_META_CTRL_RIGHT_ON + | HC_META_CTRL_LEFT_ON; private final static int HC_META_ALT_MASK = KeyEvent.META_ALT_ON | KeyEvent.META_ALT_LEFT_ON | KeyEvent.META_ALT_RIGHT_ON; @@ -164,6 +168,8 @@ public class TerminalKeyListener implements OnKeyListener, OnSharedPreferenceCha return false; } + //Log.i("CBKeyDebug", KeyEventUtil.describeKeyEvent(keyCode, event)); + if (volumeKeysChangeFontSize) { if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) { bridge.increaseFontSize(); @@ -283,9 +289,9 @@ public class TerminalKeyListener implements OnKeyListener, OnSharedPreferenceCha // Ask the system to use the keymap to give us the unicode character for this key, // with our derived modifier state applied. - int uchar = event.getUnicodeChar(derivedMetaState & ~HC_META_CTRL_ON); + int uchar = event.getUnicodeChar(derivedMetaState & ~HC_META_CTRL_MASK); int ucharWithoutAlt = event.getUnicodeChar( - derivedMetaState & ~(HC_META_ALT_MASK | HC_META_CTRL_ON)); + derivedMetaState & ~(HC_META_ALT_MASK | HC_META_CTRL_MASK)); if (uchar != ucharWithoutAlt) { // The alt key was used to modify the character returned; therefore, drop the alt // modifier from the state so we don't end up sending alt+key. diff --git a/src/org/connectbot/util/PreferenceConstants.java b/src/org/connectbot/util/PreferenceConstants.java index e9fb06c..ad29c39 100644 --- a/src/org/connectbot/util/PreferenceConstants.java +++ b/src/org/connectbot/util/PreferenceConstants.java @@ -50,6 +50,7 @@ public class PreferenceConstants { public static final String ROTATION_AUTOMATIC = "Automatic"; public static final String FULLSCREEN = "fullscreen"; + public static final String TITLEBARHIDE = "titlebarhide"; public static final String KEYMODE = "keymode"; |