diff --git a/src/java/InputStickAPI/AndroidManifest.xml b/src/java/InputStickAPI/AndroidManifest.xml index 0ee5fbb4..4133ae18 100644 --- a/src/java/InputStickAPI/AndroidManifest.xml +++ b/src/java/InputStickAPI/AndroidManifest.xml @@ -1,3 +1,4 @@ + InputStickAPI + Download InputStickUtility + Settings + Hello world! diff --git a/src/java/InputStickAPI/src/com/inputstick/api/AES.java b/src/java/InputStickAPI/src/com/inputstick/api/AES.java index 054dcb6b..e07cadb2 100644 --- a/src/java/InputStickAPI/src/com/inputstick/api/AES.java +++ b/src/java/InputStickAPI/src/com/inputstick/api/AES.java @@ -10,8 +10,10 @@ public class AES { private Cipher mCipherEncr; private Cipher mCipherDecr; private SecretKeySpec mKey; + private boolean ready; public AES() { + ready = false; } public static byte[] getMD5(String s) { @@ -31,10 +33,10 @@ public class AES { mCipherEncr = Cipher.getInstance("AES/CBC/NoPadding"); mCipherEncr.init(Cipher.ENCRYPT_MODE, mKey); iv = mCipherEncr.getIV(); - //System.out.println("AES IV: "); - Util.printHex(iv); + Util.printHex(iv, "AES IV: "); mCipherDecr = Cipher.getInstance("AES/CBC/NoPadding"); - mCipherDecr.init(Cipher.DECRYPT_MODE, mKey, new IvParameterSpec(iv)); + mCipherDecr.init(Cipher.DECRYPT_MODE, mKey, new IvParameterSpec(iv)); + ready = true; } catch (Exception e) { e.printStackTrace(); } @@ -49,4 +51,7 @@ public class AES { return mCipherDecr.update(data); } + public boolean isReady() { + return ready; + } } diff --git a/src/java/InputStickAPI/src/com/inputstick/api/BTConnectionManager.java b/src/java/InputStickAPI/src/com/inputstick/api/BTConnectionManager.java index 4d853bec..c3adf551 100644 --- a/src/java/InputStickAPI/src/com/inputstick/api/BTConnectionManager.java +++ b/src/java/InputStickAPI/src/com/inputstick/api/BTConnectionManager.java @@ -21,7 +21,6 @@ public class BTConnectionManager extends ConnectionManager implements InitManage private Application mApp; private BTService mBTService; private PacketManager mPacketManager; - //private PacketQueue mPacketQueue; private final BTHandler mBTHandler = new BTHandler(this); @@ -45,31 +44,12 @@ public class BTConnectionManager extends ConnectionManager implements InitManage break; case BTService.EVENT_CANCELLED: manager.onDisconnected(); - break; - case BTService.EVENT_CONNECTION_FAILED: - manager.onFailure(1); + break; + case BTService.EVENT_ERROR: + manager.onFailure(msg.arg1); break; - case BTService.EVENT_CONNECTION_LOST: - manager.onFailure(1); - break; - case BTService.EVENT_NO_BT_HW: - manager.onFailure(1); - break; - case BTService.EVENT_INVALID_MAC: - manager.onFailure(1); - break; - case BTService.EVENT_CMD_TIMEOUT: - manager.onFailure(1); - break; - case BTService.EVENT_INTERVAL_TIMEOUT: - manager.onFailure(1); - break; - case BTService.EVENT_TURN_ON_TIMEOUT: - manager.onFailure(1); - break; - case BTService.EVENT_OTHER_ERROR: - manager.onFailure(1); - break; + default: + manager.onFailure(InputStickError.ERROR_BLUETOOTH); } } } @@ -80,6 +60,7 @@ public class BTConnectionManager extends ConnectionManager implements InitManage private void onConnected() { stateNotify(ConnectionManager.STATE_CONNECTED); + //mInitManager.startTimeoutCountdown(InitManager.DEFAULT_INIT_TIMEOUT); mInitManager.onConnected(); } @@ -89,7 +70,8 @@ public class BTConnectionManager extends ConnectionManager implements InitManage private void onFailure(int code) { mErrorCode = code; - stateNotify(ConnectionManager.STATE_FAILURE); + stateNotify(ConnectionManager.STATE_FAILURE); + disconnect(); } private void onData(byte[] rawData) { @@ -97,16 +79,15 @@ public class BTConnectionManager extends ConnectionManager implements InitManage data = mPacketManager.bytesToPacket(rawData); if (data == null) { - //TODO + //TODO failure? return; } mInitManager.onData(data); - - //sendNext(); TODO + for (InputStickDataListener listener : mDataListeners) { listener.onInputStickData(data); - } + } } @@ -124,7 +105,7 @@ public class BTConnectionManager extends ConnectionManager implements InitManage public void connect(boolean reflection, int timeout) { - mErrorCode = ConnectionManager.ERROR_NONE; + mErrorCode = InputStickError.ERROR_NONE; if (mBTService == null) { mBTService = new BTService(mApp, mBTHandler); mPacketManager = new PacketManager(mBTService, mKey); @@ -143,10 +124,14 @@ public class BTConnectionManager extends ConnectionManager implements InitManage } } + public void disconnect(int failureCode) { + onFailure(failureCode); + } + @Override public void sendPacket(Packet p) { - mPacketManager.sendPacket(p); //TODO tmp; zalozmy z beda same NO_RESP ??? + mPacketManager.sendPacket(p); } @@ -162,7 +147,7 @@ public class BTConnectionManager extends ConnectionManager implements InitManage @Override public void onInitFailure(int code) { - onFailure(code); + onFailure(code); } } diff --git a/src/java/InputStickAPI/src/com/inputstick/api/ConnectionManager.java b/src/java/InputStickAPI/src/com/inputstick/api/ConnectionManager.java index d62cdcc4..a47aca63 100644 --- a/src/java/InputStickAPI/src/com/inputstick/api/ConnectionManager.java +++ b/src/java/InputStickAPI/src/com/inputstick/api/ConnectionManager.java @@ -11,13 +11,6 @@ public abstract class ConnectionManager { public static final int STATE_READY = 4; - public static final int ERROR_NONE = 0; - - public static final int ERROR_UNSUPPORTED_FIRMWARE = 10; - public static final int ERROR_PASSWORD_PROTECTED = 11; - public static final int ERROR_INVALID_KEY = 12; - - protected Vector mStateListeners = new Vector(); protected Vector mDataListeners = new Vector(); @@ -47,7 +40,9 @@ public abstract class ConnectionManager { public void addStateListener(InputStickStateListener listener) { if (listener != null) { - mStateListeners.add(listener); + if ( !mStateListeners.contains(listener)) { + mStateListeners.add(listener); + } } } @@ -59,7 +54,9 @@ public abstract class ConnectionManager { public void addDataListener(InputStickDataListener listener) { if (listener != null) { - mDataListeners.add(listener); + if ( !mDataListeners.contains(listener)) { + mDataListeners.add(listener); + } } } diff --git a/src/java/InputStickAPI/src/com/inputstick/api/HIDInfo.java b/src/java/InputStickAPI/src/com/inputstick/api/HIDInfo.java index 6b8f6c4b..b1c2c1d5 100644 --- a/src/java/InputStickAPI/src/com/inputstick/api/HIDInfo.java +++ b/src/java/InputStickAPI/src/com/inputstick/api/HIDInfo.java @@ -15,10 +15,16 @@ public class HIDInfo { private boolean mouseReady; private boolean consumerReady; + // >= 0.93 + private boolean sentToHostInfo; + private int keyboardReportsSentToHost; + private int mouseReportsSentToHost; + private int consumerReportsSentToHost; public HIDInfo() { keyboardReportProtocol = true; mouseReportProtocol = true; + sentToHostInfo = false; } public void update(byte[] data) { @@ -70,6 +76,14 @@ public class HIDInfo { } else { consumerReady = true; } + if (data.length >= 12) { + if (data[11] == (byte)0xFF) { + sentToHostInfo = true; + keyboardReportsSentToHost = data[8] & 0xFF; + mouseReportsSentToHost = data[9] & 0xFF; + consumerReportsSentToHost = data[10] & 0xFF; + } + } } public void setKeyboardBusy() { @@ -112,4 +126,24 @@ public class HIDInfo { return consumerReady; } + + + // > v0.93 firmware only + + public boolean isSentToHostInfoAvailable() { + return sentToHostInfo; + } + + public int getKeyboardReportsSentToHost() { + return keyboardReportsSentToHost; + } + + public int getMouseReportsSentToHost() { + return mouseReportsSentToHost; + } + + public int getConsumerReportsSentToHost() { + return consumerReportsSentToHost; + } + } diff --git a/src/java/InputStickAPI/src/com/inputstick/api/IPCConnectionManager.java b/src/java/InputStickAPI/src/com/inputstick/api/IPCConnectionManager.java index 5548f6f5..cac0d4d9 100644 --- a/src/java/InputStickAPI/src/com/inputstick/api/IPCConnectionManager.java +++ b/src/java/InputStickAPI/src/com/inputstick/api/IPCConnectionManager.java @@ -52,7 +52,6 @@ public class IPCConnectionManager extends ConnectionManager { } break; case SERVICE_CMD_STATE: - //System.out.println("CMD STATE: "+msg.arg1); manager.stateNotify(msg.arg1); break; } @@ -61,7 +60,6 @@ public class IPCConnectionManager extends ConnectionManager { private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { - //System.out.println("onServiceConnected!"); mService = new Messenger(service); mBound = true; sendMessage(SERVICE_CMD_CONNECT, 0, 0); @@ -69,9 +67,10 @@ public class IPCConnectionManager extends ConnectionManager { public void onServiceDisconnected(ComponentName className) { // unexpectedly disconnected from service - //System.out.println("onService DISCONNECTED!"); mService = null; mBound = false; + mErrorCode = InputStickError.ERROR_ANDROID_SERVICE_DISCONNECTED; + stateNotify(STATE_FAILURE); stateNotify(STATE_DISCONNECTED); } }; @@ -130,34 +129,32 @@ public class IPCConnectionManager extends ConnectionManager { } if (exists) { - mErrorCode = ConnectionManager.ERROR_NONE; + mErrorCode = InputStickError.ERROR_NONE; Intent intent = new Intent(); intent.setComponent(new ComponentName("com.inputstick.apps.inputstickutility","com.inputstick.apps.inputstickutility.service.InputStickService")); mCtx.startService(intent); mCtx.bindService(intent, mConnection, Context.BIND_AUTO_CREATE); if (mBound) { - //already bound? - //System.out.println("Service already Connected"); + //already bound sendMessage(SERVICE_CMD_CONNECT, 0, 0); } } else { - mErrorCode = 1; //TODO + mErrorCode = InputStickError.ERROR_ANDROID_NO_UTILITY_APP; stateNotify(STATE_FAILURE); + stateNotify(STATE_DISCONNECTED); } } @Override public void disconnect() { if (mBound) { - //System.out.println("UNBIND"); sendMessage(SERVICE_CMD_DISCONNECT, 0, 0); Intent intent = new Intent(); intent.setComponent(new ComponentName("com.inputstick.apps.inputstickutility","com.inputstick.apps.inputstickutility.service.InputStickService")); mCtx.unbindService(mConnection); - mCtx.stopService(intent); + mCtx.stopService(intent); mBound = false; - //TODO stateNotify - //service will pass notification message + //service will pass notification message (disconnected) } else { //just set state, there is nothing else to do stateNotify(STATE_DISCONNECTED); @@ -172,9 +169,8 @@ public class IPCConnectionManager extends ConnectionManager { } else { sendMessage(IPCConnectionManager.SERVICE_CMD_DATA, 0, 0, p.getBytes()); } - } + } } - } diff --git a/src/java/InputStickAPI/src/com/inputstick/api/Packet.java b/src/java/InputStickAPI/src/com/inputstick/api/Packet.java index 27e0ac93..ddb24ef5 100644 --- a/src/java/InputStickAPI/src/com/inputstick/api/Packet.java +++ b/src/java/InputStickAPI/src/com/inputstick/api/Packet.java @@ -22,6 +22,12 @@ public class Packet { public static final byte CMD_FW_INFO = 0x10; public static final byte CMD_INIT = 0x11; + public static final byte CMD_INIT_AUTH = 0x12; + public static final byte CMD_INIT_CON = 0x13; + //public static final byte CMD_SET_KEY = 0x14; + public static final byte CMD_SET_VALUE = 0x14; + public static final byte CMD_RESTORE_DEFAULTS = 0x15; + public static final byte CMD_RESTORE_STATUS = 0x16; public static final byte CMD_HID_STATUS_REPORT = 0x20; @@ -37,6 +43,7 @@ public class Packet { public static final byte RESP_OK = 0x01; + public static final byte RESP_UNKNOWN_CMD = (byte)0xFF; public static final byte[] RAW_OLD_BOOTLOADER = new byte[] {START_TAG, (byte)0x00, (byte)0x02, (byte)0x83, (byte)0x00, (byte)0xDA}; @@ -119,4 +126,8 @@ public class Packet { return mRespond; } + public void print() { + Util.printHex(mData, "PACKET DATA:"); + } + } diff --git a/src/java/InputStickAPI/src/com/inputstick/api/PacketManager.java b/src/java/InputStickAPI/src/com/inputstick/api/PacketManager.java index 78ae191f..f579c439 100644 --- a/src/java/InputStickAPI/src/com/inputstick/api/PacketManager.java +++ b/src/java/InputStickAPI/src/com/inputstick/api/PacketManager.java @@ -39,9 +39,13 @@ public class PacketManager { } } + public boolean isEncrypted() { + return mEncryption; + } + public Packet encPacket(boolean enable) { Random r = new Random(); - Packet p = new Packet(true, Packet.CMD_INIT); + Packet p = new Packet(true, Packet.CMD_INIT_AUTH); if (enable) { p.addByte((byte)1); } else { @@ -68,13 +72,13 @@ public class PacketManager { initData = mAes.encrypt(initData); p.addBytes(initData); - //Util.printHex(initData, "InitData: "); + Util.printHex(initData, "InitData: "); cmpData = new byte[16]; r.nextBytes(cmpData); p.addBytes(cmpData); - //Util.printHex(cmpData, "CmpData: "); + Util.printHex(cmpData, "CmpData: "); return p; } @@ -87,11 +91,15 @@ public class PacketManager { payload = Arrays.copyOfRange(data, 2, data.length); //remove TAG, info if ((data[1] & Packet.FLAG_ENCRYPTED) != 0) { - Util.log("DECRYPT"); - payload = mAes.decrypt(payload); + //Util.log("DECRYPT"); + if (mAes.isReady()) { + payload = mAes.decrypt(payload); + } else { + return null; + } } - Util.printHex(payload, "DATA IN: "); + //Util.printHex(payload, "DATA IN: "); //check CRC crcCompare = Util.getLong(payload[0], payload[1], payload[2], payload[3]); @@ -104,17 +112,19 @@ public class PacketManager { payload = Arrays.copyOfRange(payload, 4, payload.length); //remove CRC return payload; } else { - return null; //TODO + return null; //TODO } } public void sendRAW(byte[] data) { mBTService.write(data); - } + } public void sendPacket(Packet p) { - sendPacket(p, mEncryption); + if (p != null) { + sendPacket(p, mEncryption); + } } public void sendPacket(Packet p, boolean encrypt) { @@ -137,7 +147,7 @@ public class PacketManager { mCrc.reset(); mCrc.update(result, CRC_OFFSET, result.length - CRC_OFFSET); crcValue = mCrc.getValue(); - Util.log("CRC: "+crcValue); + //Util.log("CRC: "+crcValue); result[3] = (byte)crcValue; crcValue >>= 8; result[2] = (byte)crcValue; diff --git a/src/java/InputStickAPI/src/com/inputstick/api/Util.java b/src/java/InputStickAPI/src/com/inputstick/api/Util.java index 112e3312..57b187c5 100644 --- a/src/java/InputStickAPI/src/com/inputstick/api/Util.java +++ b/src/java/InputStickAPI/src/com/inputstick/api/Util.java @@ -1,13 +1,25 @@ package com.inputstick.api; +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + public abstract class Util { - private static final boolean debug = false; + public static boolean debug = false; public static void log(String msg) { + log(msg, false); + } + + public static void log(String msg, boolean displayTime) { if (debug) { - System.out.println("LOG: " + msg); + System.out.print("LOG: " + msg); + if (displayTime) { + System.out.print(" @ " + System.currentTimeMillis()); + } + System.out.println(); } } @@ -21,29 +33,35 @@ public abstract class Util { public static void printHex(byte[] toPrint) { if (debug) { - int cnt = 0; - String s; - byte b; - for (int i = 0; i < toPrint.length; i++) { - b = toPrint[i]; - if ((b < 10) && (b >= 0)) { - s = Integer.toHexString((int)b); - s = "0" + s; - } else { - s = Integer.toHexString((int)b); - if (s.length() > 2) { - s = s.substring(s.length() - 2); + if (toPrint != null) { + int cnt = 0; + String s; + byte b; + for (int i = 0; i < toPrint.length; i++) { + b = toPrint[i]; + //0x0..0xF = 0x00..0x0F + if ((b < 0x10) && (b >= 0)) { + s = Integer.toHexString((int)b); + s = "0" + s; + } else { + s = Integer.toHexString((int)b); + if (s.length() > 2) { + s = s.substring(s.length() - 2); + } + } + s = s.toUpperCase(); + System.out.print("0x" + s + " "); + cnt++; + if (cnt == 8) { + System.out.println(""); + cnt = 0; } - } - s = s.toUpperCase(); - System.out.print("0x" + s + " "); - cnt++; - if (cnt == 8) { - System.out.println(""); - cnt = 0; - } - } - System.out.println("\n#####"); + } + + } else { + System.out.println("null"); + } + System.out.println("\n#####"); } } @@ -79,5 +97,18 @@ public abstract class Util { return result; } + + public static byte[] getPasswordBytes(String plainText) { + try { + MessageDigest md = MessageDigest.getInstance("MD5"); + return md.digest(plainText.getBytes("UTF-8")); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + return null; + } + } diff --git a/src/java/InputStickAPI/src/com/inputstick/api/basic/InputStickHID.java b/src/java/InputStickAPI/src/com/inputstick/api/basic/InputStickHID.java index cf9adafa..5bc4d5ca 100644 --- a/src/java/InputStickAPI/src/com/inputstick/api/basic/InputStickHID.java +++ b/src/java/InputStickAPI/src/com/inputstick/api/basic/InputStickHID.java @@ -1,35 +1,54 @@ package com.inputstick.api.basic; +import java.util.Timer; +import java.util.TimerTask; import java.util.Vector; +import android.app.AlertDialog; import android.app.Application; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.net.Uri; import com.inputstick.api.BTConnectionManager; import com.inputstick.api.ConnectionManager; import com.inputstick.api.HIDInfo; import com.inputstick.api.IPCConnectionManager; import com.inputstick.api.InputStickDataListener; +import com.inputstick.api.InputStickError; import com.inputstick.api.InputStickStateListener; +import com.inputstick.api.OnEmptyBufferListener; import com.inputstick.api.Packet; +import com.inputstick.api.Util; import com.inputstick.api.hid.HIDTransaction; import com.inputstick.api.hid.HIDTransactionQueue; import com.inputstick.init.InitManager; public class InputStickHID implements InputStickStateListener, InputStickDataListener { - //private static final String mTag = "InputStickBasic"; + public static final int INTERFACE_KEYBOARD = 0; + public static final int INTERFACE_CONSUMER = 1; + public static final int INTERFACE_MOUSE = 2; + + //private static final String mTag = "InputStickBasic"; private static ConnectionManager mConnectionManager; private static Vector mStateListeners = new Vector(); + private static InputStickHID instance = new InputStickHID(); - private static HIDInfo mHIDInfo = new HIDInfo(); + private static HIDInfo mHIDInfo; private static HIDTransactionQueue keyboardQueue; private static HIDTransactionQueue mouseQueue; private static HIDTransactionQueue consumerQueue; + // >= FW 0.93 + private static Timer t1; + private static boolean constantUpdateMode; + private InputStickHID() { } @@ -38,9 +57,11 @@ public class InputStickHID implements InputStickStateListener, InputStickDataLis } private static void init() { - keyboardQueue = new HIDTransactionQueue(HIDTransactionQueue.KEYBOARD, mConnectionManager); - mouseQueue = new HIDTransactionQueue(HIDTransactionQueue.MOUSE, mConnectionManager); - consumerQueue = new HIDTransactionQueue(HIDTransactionQueue.CONSUMER, mConnectionManager); + mHIDInfo = new HIDInfo(); + constantUpdateMode = false; + keyboardQueue = new HIDTransactionQueue(INTERFACE_KEYBOARD, mConnectionManager); + mouseQueue = new HIDTransactionQueue(INTERFACE_MOUSE, mConnectionManager); + consumerQueue = new HIDTransactionQueue(INTERFACE_CONSUMER, mConnectionManager); mConnectionManager.addStateListener(instance); mConnectionManager.addDataListener(instance); @@ -55,8 +76,6 @@ public class InputStickHID implements InputStickStateListener, InputStickDataLis //direct Bluetooth connection public static void connect(Application app, String mac, byte[] key) { - //mConnectionManager = new BTConnectionManager(new BasicInitManager(key), app, mac, reflections, key); - //mConnectionManager = new BTConnectionManager(new BasicInitManager(key), app, mac, key); mConnectionManager = new BTConnectionManager(new InitManager(key), app, mac, key); init(); } @@ -80,6 +99,16 @@ public class InputStickHID implements InputStickStateListener, InputStickDataLis } } + public static int getErrorCode() { + if (mConnectionManager != null) { + return mConnectionManager.getErrorCode(); + } else { + return InputStickError.ERROR_UNKNOWN; + } + } + + + public static boolean isReady() { if (getState() == ConnectionManager.STATE_READY) { return true; @@ -90,7 +119,9 @@ public class InputStickHID implements InputStickStateListener, InputStickDataLis public static void addStateListener(InputStickStateListener listener) { if (listener != null) { - mStateListeners.add(listener); + if ( !mStateListeners.contains(listener)) { + mStateListeners.add(listener); + } } } @@ -99,6 +130,22 @@ public class InputStickHID implements InputStickStateListener, InputStickDataLis mStateListeners.remove(listener); } } + + public static void addBufferEmptyListener(OnEmptyBufferListener listener) { + if (listener != null) { + keyboardQueue.addBufferEmptyListener(listener); + mouseQueue.addBufferEmptyListener(listener); + consumerQueue.addBufferEmptyListener(listener); + } + } + + public static void removeBufferEmptyListener(OnEmptyBufferListener listener) { + if (listener != null) { + keyboardQueue.removeBufferEmptyListener(listener); + mouseQueue.removeBufferEmptyListener(listener); + consumerQueue.removeBufferEmptyListener(listener); + } + } public static void addKeyboardTransaction(HIDTransaction transaction) { keyboardQueue.addTransaction(transaction); @@ -112,6 +159,18 @@ public class InputStickHID implements InputStickStateListener, InputStickDataLis consumerQueue.addTransaction(transaction); } + public static void clearKeyboardBuffer() { + keyboardQueue.clearBuffer(); + } + + public static void clearMouseBuffer() { + mouseQueue.clearBuffer(); + } + + public static void clearConsumerBuffer() { + consumerQueue.clearBuffer(); + } + public static boolean sendPacket(Packet p) { if (mConnectionManager != null) { mConnectionManager.sendPacket(p); @@ -122,31 +181,112 @@ public class InputStickHID implements InputStickStateListener, InputStickDataLis } @Override - public void onStateChanged(int state) { + public void onStateChanged(int state) { + if ((state == ConnectionManager.STATE_DISCONNECTED) && (t1 != null)) { + t1.cancel(); + t1 = null; + } for (InputStickStateListener listener : mStateListeners) { listener.onStateChanged(state); } } + + public static boolean isKeyboardLocalBufferEmpty() { + return keyboardQueue.isLocalBufferEmpty(); + } + public static boolean isMouseLocalBufferEmpty() { + return mouseQueue.isLocalBufferEmpty(); + } + public static boolean isConsumerLocalBufferEmpty() { + return consumerQueue.isLocalBufferEmpty(); + } + + public static boolean isKeyboardRemoteBufferEmpty() { + return keyboardQueue.isRemoteBufferEmpty(); + } + public static boolean isMouseRemoteBufferEmpty() { + return mouseQueue.isRemoteBufferEmpty(); + } + public static boolean isConsumerRemoteBufferEmpty() { + return consumerQueue.isRemoteBufferEmpty(); + } @Override public void onInputStickData(byte[] data) { if (data[0] == Packet.CMD_HID_STATUS) { mHIDInfo.update(data); - - if (mHIDInfo.isKeyboardReady()) { - keyboardQueue.deviceReady(); + + if (mHIDInfo.isSentToHostInfoAvailable()) { + // >= FW 0.93 + keyboardQueue.deviceReady(mHIDInfo, mHIDInfo.getKeyboardReportsSentToHost()); + mouseQueue.deviceReady(mHIDInfo, mHIDInfo.getMouseReportsSentToHost()); + consumerQueue.deviceReady(mHIDInfo, mHIDInfo.getConsumerReportsSentToHost()); + + if ( !constantUpdateMode) { + Util.log("Constatnt update mode enabled"); + constantUpdateMode = true; + t1 = new Timer(); + t1.schedule(new TimerTask() { + @Override + public void run() { + keyboardQueue.sendToBuffer(false); + mouseQueue.sendToBuffer(false); + consumerQueue.sendToBuffer(false); + } + }, 5,5); + } + } else { + //previous FW versions + if (mHIDInfo.isKeyboardReady()) { + keyboardQueue.deviceReady(null, 0); + } + if (mHIDInfo.isMouseReady()) { + mouseQueue.deviceReady(null, 0); + } + if (mHIDInfo.isConsumerReady()) { + consumerQueue.deviceReady(null, 0); + } } - if (mHIDInfo.isMouseReady()) { - mouseQueue.deviceReady(); - } - if (mHIDInfo.isConsumerReady()) { - consumerQueue.deviceReady(); - } InputStickKeyboard.setLEDs(mHIDInfo.getNumLock(), mHIDInfo.getCapsLock(), mHIDInfo.getScrollLock()); } } + public static AlertDialog getDownloadDialog(final Context ctx) { + if (mConnectionManager.getErrorCode() == InputStickError.ERROR_ANDROID_NO_UTILITY_APP) { + AlertDialog.Builder downloadDialog = new AlertDialog.Builder(ctx); + downloadDialog.setTitle("No InputStickUtility app installed"); + downloadDialog.setMessage("InputStickUtility is required to run this application. Download now?"); + downloadDialog.setPositiveButton("Yes", + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + final String appPackageName = "com.inputstick.apps.inputstickutility"; + try { + ctx.startActivity(new Intent( + Intent.ACTION_VIEW, Uri + .parse("market://details?id=" + + appPackageName))); + } catch (android.content.ActivityNotFoundException anfe) { + ctx.startActivity(new Intent( + Intent.ACTION_VIEW, + Uri.parse("http://play.google.com/store/apps/details?id=" + + appPackageName))); + } + } + }); + downloadDialog.setNegativeButton("No", + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + } + }); + return downloadDialog.show(); + } else { + return null; + } + } + } diff --git a/src/java/InputStickAPI/src/com/inputstick/api/basic/InputStickKeyboard.java b/src/java/InputStickAPI/src/com/inputstick/api/basic/InputStickKeyboard.java index 3c902203..9bb05e67 100644 --- a/src/java/InputStickAPI/src/com/inputstick/api/basic/InputStickKeyboard.java +++ b/src/java/InputStickAPI/src/com/inputstick/api/basic/InputStickKeyboard.java @@ -2,6 +2,8 @@ package com.inputstick.api.basic; import java.util.Vector; +import android.util.SparseArray; + import com.inputstick.api.InputStickKeyboardListener; import com.inputstick.api.hid.HIDKeycodes; import com.inputstick.api.hid.HIDTransaction; @@ -13,6 +15,10 @@ public class InputStickKeyboard { private static final byte NONE = (byte)0; + private static final byte LED_NUM_LOCK = 1; + private static final byte LED_CAPS_LOCK = 2; + private static final byte LED_SCROLL_LOCK = 4; + private static boolean mReportProtocol; private static boolean mNumLock; private static boolean mCapsLock; @@ -20,12 +26,23 @@ public class InputStickKeyboard { private static Vector mKeyboardListeners = new Vector(); + private static final SparseArray ledsMap; + static + { + ledsMap = new SparseArray(); + ledsMap.put(LED_NUM_LOCK, "NumLock"); + ledsMap.put(LED_CAPS_LOCK, "CapsLock"); + ledsMap.put(LED_SCROLL_LOCK, "ScrollLock"); + } + private InputStickKeyboard() { } public static void addKeyboardListener(InputStickKeyboardListener listener) { if (listener != null) { - mKeyboardListeners.add(listener); + if ( !mKeyboardListeners.contains(listener)) { + mKeyboardListeners.add(listener); + } } } @@ -114,5 +131,25 @@ public class InputStickKeyboard { t.addReport(report); InputStickHID.addKeyboardTransaction(t); }*/ + + public static String ledsToString(byte leds) { + String result = "None"; + boolean first = true; + byte mod; + for (int i = 0; i < 8; i++) { + mod = (byte)(LED_NUM_LOCK << i); + if ((leds & mod) != 0) { + if ( !first) { + result += ", "; + } else { + result = ""; + } + first = false; + result += ledsMap.get(mod); + } + } + + return result; + } } diff --git a/src/java/InputStickAPI/src/com/inputstick/api/basic/InputStickMouse.java b/src/java/InputStickAPI/src/com/inputstick/api/basic/InputStickMouse.java index a5db55f2..19924a8f 100644 --- a/src/java/InputStickAPI/src/com/inputstick/api/basic/InputStickMouse.java +++ b/src/java/InputStickAPI/src/com/inputstick/api/basic/InputStickMouse.java @@ -1,5 +1,7 @@ package com.inputstick.api.basic; +import android.util.SparseArray; + import com.inputstick.api.hid.HIDTransaction; import com.inputstick.api.hid.MouseReport; @@ -12,6 +14,15 @@ public class InputStickMouse { public static final byte BUTTON_RIGHT = 0x02; public static final byte BUTTON_MIDDLE = 0x04; + private static final SparseArray buttonsMap; + static + { + buttonsMap = new SparseArray(); + buttonsMap.put(BUTTON_LEFT, "Left"); + buttonsMap.put(BUTTON_RIGHT, "Right"); + buttonsMap.put(BUTTON_MIDDLE, "Middle"); + } + private static boolean mReportProtocol; private InputStickMouse() { @@ -53,5 +64,25 @@ public class InputStickMouse { t.addReport(new MouseReport(buttons, x, y, wheel)); InputStickHID.addMouseTransaction(t); } + + public static String buttonsToString(byte buttons) { + String result = "None"; + boolean first = true; + byte mod; + for (int i = 0; i < 8; i++) { + mod = (byte)(BUTTON_LEFT << i); + if ((buttons & mod) != 0) { + if ( !first) { + result += ", "; + } else { + result = ""; + } + first = false; + result += buttonsMap.get(mod); + } + } + + return result; + } } diff --git a/src/java/InputStickAPI/src/com/inputstick/api/bluetooth/BTService.java b/src/java/InputStickAPI/src/com/inputstick/api/bluetooth/BTService.java index fd0098ac..54b46d30 100644 --- a/src/java/InputStickAPI/src/com/inputstick/api/bluetooth/BTService.java +++ b/src/java/InputStickAPI/src/com/inputstick/api/bluetooth/BTService.java @@ -19,6 +19,7 @@ import android.os.Message; import com.inputstick.api.Packet; import com.inputstick.api.Util; +import com.inputstick.api.InputStickError; public class BTService { @@ -28,16 +29,7 @@ public class BTService { public static final int EVENT_DATA = 1; public static final int EVENT_CONNECTED = 2; public static final int EVENT_CANCELLED = 3; - public static final int EVENT_CONNECTION_FAILED = 4; - public static final int EVENT_CONNECTION_LOST = 5; - public static final int EVENT_NO_BT_HW = 6; - public static final int EVENT_INVALID_MAC = 7; - //TODO: - public static final int EVENT_CMD_TIMEOUT = 8; - public static final int EVENT_INTERVAL_TIMEOUT = 9; - public static final int EVENT_TURN_ON_TIMEOUT = 10; - public static final int EVENT_OTHER_ERROR = 11; - + public static final int EVENT_ERROR = 4; private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); //SPP @@ -71,8 +63,7 @@ public class BTService { private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - System.out.println("ACTION: "+action); + final String action = intent.getAction(); if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) { final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR); if ((state == BluetoothAdapter.STATE_ON) && (turnBluetoothOn)) { @@ -102,12 +93,12 @@ public class BTService { public void enableReflection(boolean enabled) { mUseReflection = enabled; } - - private synchronized void event(int event) { + + + private synchronized void event(int event, int arg1) { Util.log("event() " + mLastEvent + " -> " + event); - mLastEvent = event; - - Message msg = Message.obtain(null, mLastEvent, 0, 0); + mLastEvent = event; + Message msg = Message.obtain(null, mLastEvent, arg1, 0); mHandler.sendMessage(msg); } @@ -163,7 +154,7 @@ public class BTService { if (BluetoothAdapter.checkBluetoothAddress(mac)) { BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if (mBluetoothAdapter == null) { - event(EVENT_NO_BT_HW); + event(EVENT_ERROR, InputStickError.ERROR_BLUETOOTH_NOT_SUPPORTED); } else { if (mBluetoothAdapter.isEnabled()) { doConnect(false); @@ -172,7 +163,7 @@ public class BTService { } } } else { - event(EVENT_INVALID_MAC); + event(EVENT_ERROR, InputStickError.ERROR_BLUETOOTH_INVALID_MAC); } } @@ -180,7 +171,7 @@ public class BTService { Util.log("disconnect"); disconnecting = true; cancelThreads(); - event(EVENT_CANCELLED); + event(EVENT_CANCELLED, 0); } @@ -226,7 +217,7 @@ public class BTService { mConnectedThread.start(); connected = true; - event(EVENT_CONNECTED); + event(EVENT_CONNECTED, 0); } @@ -239,7 +230,7 @@ public class BTService { Util.log("RETRY: "+retryCnt + " time left: " + (timeout - System.currentTimeMillis())); doConnect(true); } else { - event(EVENT_CONNECTION_FAILED); + event(EVENT_ERROR, InputStickError.ERROR_BLUETOOTH_CONNECTION_FAILED); } } } @@ -249,7 +240,7 @@ public class BTService { if (disconnecting) { disconnecting = false; } else { - event(EVENT_CONNECTION_LOST); + event(EVENT_ERROR, InputStickError.ERROR_BLUETOOTH_CONNECTION_LOST); } } @@ -356,11 +347,13 @@ public class BTService { byte[] buffer = null; int rxTmp; int lengthByte; - int length; + int length; + int wdgCnt = 0; while (true) { try { rxTmp = mmInStream.read(); if (rxTmp == Packet.START_TAG) { + wdgCnt = 0; lengthByte = mmInStream.read(); length = lengthByte; length &= 0x3F; @@ -373,8 +366,13 @@ public class BTService { } mHandler.obtainMessage(EVENT_DATA, 0, 0, buffer).sendToTarget(); } else { - System.out.println("RX: " + rxTmp); - //possible WDG reset + Util.log("Unexpected RX byte" + rxTmp); + if (rxTmp == 0xAF) { + wdgCnt++; + } + if (wdgCnt > 1024) { + //TODO + } } } catch (IOException e) { connectionLost(); @@ -388,7 +386,7 @@ public class BTService { mmOutStream.write(buffer); mmOutStream.flush(); } catch (IOException e) { - Util.log("Exception during write"); + Util.log("write() exception"); } } @@ -396,7 +394,7 @@ public class BTService { try { mmSocket.close(); } catch (IOException e) { - Util.log("close() of connect socket failed"); + Util.log("socket close() exception"); } } } diff --git a/src/java/InputStickAPI/src/com/inputstick/api/hid/HIDKeycodes.java b/src/java/InputStickAPI/src/com/inputstick/api/hid/HIDKeycodes.java index 3528bdbd..7edec591 100644 --- a/src/java/InputStickAPI/src/com/inputstick/api/hid/HIDKeycodes.java +++ b/src/java/InputStickAPI/src/com/inputstick/api/hid/HIDKeycodes.java @@ -1,5 +1,7 @@ package com.inputstick.api.hid; +import android.util.SparseArray; + public class HIDKeycodes { public static final byte NONE = 0x00; @@ -13,6 +15,7 @@ public class HIDKeycodes { public static final byte ALT_RIGHT = 0x40; public static final byte GUI_RIGHT = (byte)0x80; + public static final byte KEY_ENTER = 0x28; public static final byte KEY_ESCAPE = 0x29; public static final byte KEY_BACKSPACE = 0x2A; @@ -79,6 +82,8 @@ public class HIDKeycodes { public static final byte KEY_NUM_0 = 0x62; public static final byte KEY_NUM_DOT = 0x63; + public static final byte KEY_BACKSLASH_NON_US = 0x64; + public static final byte KEY_A = 0x04; public static final byte KEY_B = 0x05; public static final byte KEY_C = 0x06; @@ -126,6 +131,133 @@ public class HIDKeycodes { + public static final SparseArray modifiersMap; + static + { + modifiersMap = new SparseArray(); + modifiersMap.put(CTRL_LEFT, "Left Ctrl"); + modifiersMap.put(SHIFT_LEFT, "Left Shift"); + modifiersMap.put(ALT_LEFT, "Left Alt"); + modifiersMap.put(GUI_LEFT, "Left GUI"); + modifiersMap.put(CTRL_RIGHT, "Right Ctrl"); + modifiersMap.put(SHIFT_RIGHT, "Right Shift"); + modifiersMap.put(ALT_RIGHT, "Right Alt"); + modifiersMap.put(GUI_RIGHT, "Right GUI"); + } + + public static final SparseArray keyMap; + static + { + keyMap = new SparseArray(); + keyMap.put(0, "None"); + keyMap.put(KEY_ENTER, "Enter"); + keyMap.put(KEY_ESCAPE , "Esc"); + keyMap.put(KEY_BACKSPACE , "Backspace"); + keyMap.put(KEY_TAB , "Tab"); + keyMap.put(KEY_SPACEBAR , "Space"); + + keyMap.put(KEY_CAPS_LOCK , "CapsLock"); + + keyMap.put(KEY_1 , "1"); + keyMap.put(KEY_2 , "2"); + keyMap.put(KEY_3 , "3"); + keyMap.put(KEY_4 , "4"); + keyMap.put(KEY_5 , "5"); + keyMap.put(KEY_6 , "6"); + keyMap.put(KEY_7 , "7"); + keyMap.put(KEY_8 , "8"); + keyMap.put(KEY_9 , "9"); + keyMap.put(KEY_0 , "0"); + + keyMap.put(KEY_F1 , "F1"); + keyMap.put(KEY_F2 , "F2"); + keyMap.put(KEY_F3 , "F3"); + keyMap.put(KEY_F4 , "F4"); + keyMap.put(KEY_F5 , "F5"); + keyMap.put(KEY_F6 , "F6"); + keyMap.put(KEY_F7 , "F7"); + keyMap.put(KEY_F8 , "F8"); + keyMap.put(KEY_F9 , "F9"); + keyMap.put(KEY_F10 , "F10"); + keyMap.put(KEY_F11 , "F11"); + keyMap.put(KEY_F12 , "F12"); + + keyMap.put(KEY_PRINT_SCREEN , "Print Scrn"); + keyMap.put(KEY_SCROLL_LOCK , "ScrollLock"); + keyMap.put(KEY_PASUE , "Pause Break"); + keyMap.put(KEY_INSERT , "Insert"); + keyMap.put(KEY_HOME , "Home"); + keyMap.put(KEY_PAGE_UP , "PageUp"); + keyMap.put(KEY_DELETE , "Delete"); + keyMap.put(KEY_END , "End"); + keyMap.put(KEY_PAGE_DOWN , "PageDown"); + + keyMap.put(KEY_ARROW_RIGHT , "Right Arrow"); + keyMap.put(KEY_ARROW_LEFT , "Left Arrow"); + keyMap.put(KEY_ARROW_DOWN , "Down Arrow"); + keyMap.put(KEY_ARROW_UP , "Up Arrow"); + + keyMap.put(KEY_NUM_LOCK , "NumLock"); + keyMap.put(KEY_NUM_BACKSLASH , "Num /"); + keyMap.put(KEY_NUM_STAR , "Num *"); + keyMap.put(KEY_NUM_MINUS , "Num -"); + keyMap.put(KEY_NUM_PLUS , "Num +"); + keyMap.put(KEY_NUM_ENTER , "Num Enter"); + keyMap.put(KEY_NUM_1 , "Num 1"); + keyMap.put(KEY_NUM_2 , "Num 2"); + keyMap.put(KEY_NUM_3 , "Num 3"); + keyMap.put(KEY_NUM_4 , "Num 4"); + keyMap.put(KEY_NUM_5 , "Num 5"); + keyMap.put(KEY_NUM_6 , "Num 6"); + keyMap.put(KEY_NUM_7 , "Num 7"); + keyMap.put(KEY_NUM_8 , "Num 8"); + keyMap.put(KEY_NUM_9 , "Num 9"); + keyMap.put(KEY_NUM_0 , "Num 0"); + keyMap.put(KEY_NUM_DOT , "Num ."); + + keyMap.put(KEY_A , "A"); + keyMap.put(KEY_B , "B"); + keyMap.put(KEY_C , "C"); + keyMap.put(KEY_D , "D"); + keyMap.put(KEY_E , "E"); + keyMap.put(KEY_F , "F"); + keyMap.put(KEY_G , "G"); + keyMap.put(KEY_H , "H"); + keyMap.put(KEY_I , "I"); + keyMap.put(KEY_J , "J"); + keyMap.put(KEY_K , "K"); + keyMap.put(KEY_L , "L"); + keyMap.put(KEY_M , "M"); + keyMap.put(KEY_N , "N"); + keyMap.put(KEY_O , "O"); + keyMap.put(KEY_P , "P"); + keyMap.put(KEY_Q , "Q"); + keyMap.put(KEY_R , "R"); + keyMap.put(KEY_S , "S"); + keyMap.put(KEY_T , "T"); + keyMap.put(KEY_U , "U"); + keyMap.put(KEY_V , "V"); + keyMap.put(KEY_W , "W"); + keyMap.put(KEY_X , "X"); + keyMap.put(KEY_Y , "Y"); + keyMap.put(KEY_Z , "Z"); + + keyMap.put(KEY_MINUS , "-"); + keyMap.put(KEY_EQUALS , "="); + keyMap.put(KEY_LEFT_BRACKET , "["); + keyMap.put(KEY_RIGHT_BRACKET , "]"); + keyMap.put(KEY_BACKSLASH , "\\"); + //keyMap.put(KEY_GRAVE , "`"); + keyMap.put(KEY_SEMICOLON , ";"); + keyMap.put(KEY_APOSTROPHE , "'"); + keyMap.put(KEY_GRAVE , "`"); + keyMap.put(KEY_COMA , ","); + keyMap.put(KEY_DOT , "."); + keyMap.put(KEY_SLASH , "/"); + + keyMap.put(KEY_APPLICATION , "Application"); + } + public static final int[] ASCIItoHID = { 0, //000 0, //001 @@ -257,6 +389,14 @@ public class HIDKeycodes { 0 //127 just in case... }; + public static char getChar(byte keyCode) { + for (int i = 0; i < ASCIItoHID.length; i++) { + if (ASCIItoHID[i] == keyCode) { + return (char)i; + } + } + return 0; + } public static byte getKeyCode(char c) { return (byte)ASCIItoHID[c]; //TODO range @@ -266,7 +406,31 @@ public class HIDKeycodes { return ASCIItoHID[c]; //TODO range } + public static String modifiersToString(byte modifiers) { + String result = "None"; + boolean first = true; + byte mod; + for (int i = 0; i < 8; i++) { + mod = (byte)(CTRL_LEFT << i); + if ((modifiers & mod) != 0) { + if ( !first) { + result += ", "; + } else { + result = ""; + } + first = false; + result += modifiersMap.get(mod); + } + } + + return result; + } - - + public static String keyToString(byte key) { + String result = keyMap.get(key); + if (result == null) { + result = "Unknown"; + } + return result; + } } diff --git a/src/java/InputStickAPI/src/com/inputstick/api/hid/HIDTransactionQueue.java b/src/java/InputStickAPI/src/com/inputstick/api/hid/HIDTransactionQueue.java index 64b174ee..f6cb57d0 100644 --- a/src/java/InputStickAPI/src/com/inputstick/api/hid/HIDTransactionQueue.java +++ b/src/java/InputStickAPI/src/com/inputstick/api/hid/HIDTransactionQueue.java @@ -1,39 +1,71 @@ package com.inputstick.api.hid; +import java.util.Timer; +import java.util.TimerTask; import java.util.Vector; + import com.inputstick.api.ConnectionManager; +import com.inputstick.api.HIDInfo; +import com.inputstick.api.OnEmptyBufferListener; import com.inputstick.api.Packet; +import com.inputstick.api.basic.InputStickHID; public class HIDTransactionQueue { - public static final int KEYBOARD = 1; - public static final int MOUSE = 2; - public static final int CONSUMER = 3; - private static final int BUFFER_SIZE = 32; + private static final int BT_DELAY = 50; //additional delay for BT overhead + + private static final int MAX_PACKETS_PER_UPDATE = 10; + private static final int MAX_IMMEDIATE_PACKETS = 3; private final Vector queue; private final ConnectionManager mConnectionManager; private final byte cmd; private boolean ready; + private int mInterfaceType; + private boolean mustNotify; + private Vector mBufferEmptyListeners = new Vector(); + private Timer t; + private boolean timerCancelled; + private boolean sentAhead; private long lastTime; - private int lastReports; + private long minNextTime; + private int lastReports; - public HIDTransactionQueue(int type, ConnectionManager connectionManager) { + // >= FW 0.93 + private boolean bufferInitDone; + private boolean constantUpdateMode; + private int bufferFreeSpace; + private int immediatePacketsLeft; + //private int reportsSentSinceLastUpdate; + private int packetsSentSinceLastUpdate; + + + + public HIDTransactionQueue(int interfaceType, ConnectionManager connectionManager) { + constantUpdateMode = false; + bufferFreeSpace = BUFFER_SIZE; + queue = new Vector(); mConnectionManager = connectionManager; ready = false; - switch (type) { - case KEYBOARD: + sentAhead = false; + minNextTime = 0; + + mustNotify = false; + + mInterfaceType = interfaceType; + switch (interfaceType) { + case InputStickHID.INTERFACE_KEYBOARD: cmd = Packet.CMD_HID_DATA_KEYB; break; - case MOUSE: + case InputStickHID.INTERFACE_MOUSE: cmd = Packet.CMD_HID_DATA_MOUSE; break; - case CONSUMER: + case InputStickHID.INTERFACE_CONSUMER: cmd = Packet.CMD_HID_DATA_CONSUMER; break; default: @@ -41,26 +73,32 @@ public class HIDTransactionQueue { } } - private void sendNext() { - HIDTransaction transaction; - byte reports = 0; - ready = false; - Packet p = new Packet(false, cmd, reports); + private int sendNext(int maxReports) { + HIDTransaction transaction; //assume there is at least 1 element in queue transaction = queue.firstElement(); - if (transaction.getReportsCount() > BUFFER_SIZE) { - //transaction too big! split - transaction = transaction.split(BUFFER_SIZE); + if (transaction.getReportsCount() > maxReports) { + // v0.92 + if (maxReports < BUFFER_SIZE) { + //don't split transactions until there is no other way left! + return 0; + } + + //transaction too big to fit single packet! split + transaction = transaction.split(BUFFER_SIZE); } else { queue.removeElementAt(0); } + + byte reports = 0; + ready = false; + Packet p = new Packet(false, cmd, reports); while (transaction.hasNext()) { p.addBytes(transaction.getNextReport()); reports++; } - //TODO add next transactions if possible while(true) { if (queue.isEmpty()) { @@ -68,7 +106,7 @@ public class HIDTransactionQueue { } transaction = queue.firstElement(); - if (reports + transaction.getReportsCount() < BUFFER_SIZE) { + if (reports + transaction.getReportsCount() < maxReports) { queue.removeElementAt(0); while (transaction.hasNext()) { p.addBytes(transaction.getNextReport()); @@ -79,33 +117,183 @@ public class HIDTransactionQueue { } } - + //!! total number of reports must be < 32 ! (max packet limitation) p.modifyByte(1, reports); //set reports count - mConnectionManager.sendPacket(p); + mConnectionManager.sendPacket(p); lastReports = reports; lastTime = System.currentTimeMillis(); + minNextTime = lastTime + (lastReports * 4) + BT_DELAY; + + if (queue.isEmpty()) { + notifyOnLocalBufferEmpty(); + } + + return reports; } - public void addTransaction(HIDTransaction transaction) { - if (queue.isEmpty()) { - if (System.currentTimeMillis() > lastTime + (lastReports * 8 * 2/*just to be safe*/)) { - ready = true; + public void addBufferEmptyListener(OnEmptyBufferListener listener) { + if (listener != null) { + if ( !mBufferEmptyListeners.contains(listener)) { + mBufferEmptyListeners.add(listener); } - } + } + } + + public void removeBufferEmptyListener(OnEmptyBufferListener listener) { + if (listener != null) { + mBufferEmptyListeners.remove(listener); + } + } + + private void notifyOnRemoteBufferEmpty() { + for (OnEmptyBufferListener listener : mBufferEmptyListeners) { + listener.onRemoteBufferEmpty(mInterfaceType); + } + } + + private void notifyOnLocalBufferEmpty() { + for (OnEmptyBufferListener listener : mBufferEmptyListeners) { + listener.onRemoteBufferEmpty(mInterfaceType); + } + } + + public synchronized boolean isLocalBufferEmpty() { + return queue.isEmpty(); + } + + public synchronized boolean isRemoteBufferEmpty() { + if ((queue.isEmpty()) && (bufferFreeSpace == BUFFER_SIZE)) { + return true; + } + + if (queue.isEmpty() && ( !mustNotify)) { + return true; + } else { + return false; + } + } + + public synchronized void clearBuffer() { + queue.removeAllElements(); + } + + public synchronized void addTransaction(HIDTransaction transaction) { + if ( !bufferInitDone) { + queue.add(transaction); + return; + } + + + if (constantUpdateMode) { + queue.add(transaction); + sendToBuffer(true); + return; + } + + + mustNotify = true; + //using sentAhead will slow down mouse. FW0.92 will solve the problems + if ((queue.isEmpty()) && (System.currentTimeMillis() > minNextTime) /*&& ( !sentAhead)*/) { + sentAhead = true; + ready = true; + } queue.add(transaction); if (ready) { - sendNext(); + sendNext(BUFFER_SIZE); } + } + + private synchronized void timerAction() { + if ( !timerCancelled) { + if (sentAhead) { + deviceReady(null, 0); //will set sentAhead to false; + sentAhead = true; //restore value + } else { + deviceReady(null, 0); + } + } + } + + public synchronized void deviceReady(HIDInfo hidInfo, int reportsSentToHost) { + //it is possible that in the meantime some packets has been sent to IS!!! + + bufferInitDone = true; + + if (hidInfo != null) { + if (hidInfo.isSentToHostInfoAvailable()) { + constantUpdateMode = true; + // >= FW 0.93 + bufferFreeSpace += reportsSentToHost; + if ((bufferFreeSpace == BUFFER_SIZE) && (queue.isEmpty())) { + notifyOnRemoteBufferEmpty(); + } + immediatePacketsLeft = MAX_IMMEDIATE_PACKETS; + //reportsSentSinceLastUpdate = 0; + packetsSentSinceLastUpdate = 0; + sendToBuffer(false); + return; + } + } + + + + long now = System.currentTimeMillis(); + //System.out.println("v90 HID update"); + if (now < minNextTime) { + //set timer, just in case if deviceReady won't be called again + timerCancelled = false; + t = new Timer(); + t.schedule(new TimerTask() { + @Override + public void run() { + timerAction(); + } + }, (minNextTime - now + 1)); + } else { + timerCancelled = true; + sentAhead = false; + if (!queue.isEmpty()) { + sendNext(BUFFER_SIZE); + } else { + ready = true; + //queue is empty, InputStick reported that buffer is empty, data was added since last notification + if (mustNotify) { + notifyOnRemoteBufferEmpty(); + mustNotify = false; + } + } + } + } + + public synchronized void sendToBuffer(boolean justAdded) { + if ((justAdded) && (immediatePacketsLeft <= 0)) { + return; + } + + if ( !InputStickHID.isReady()) { + return; + } + + if (queue.isEmpty()) { + return; + } + if (bufferFreeSpace <= 0) { + return; + } + if (packetsSentSinceLastUpdate >= MAX_PACKETS_PER_UPDATE) { + return; + } + + int reportsSent = sendNext(bufferFreeSpace); + if (reportsSent > 0) { + if (justAdded) { + immediatePacketsLeft --; + } + bufferFreeSpace -= reportsSent; + packetsSentSinceLastUpdate ++; + } } - public void deviceReady() { - if (!queue.isEmpty()) { - sendNext(); - } else { - ready = true; - } - } - } diff --git a/src/java/InputStickAPI/src/com/inputstick/api/layout/GermanLayout.java b/src/java/InputStickAPI/src/com/inputstick/api/layout/GermanLayout.java index b5c56677..a5717d6c 100644 --- a/src/java/InputStickAPI/src/com/inputstick/api/layout/GermanLayout.java +++ b/src/java/InputStickAPI/src/com/inputstick/api/layout/GermanLayout.java @@ -110,6 +110,49 @@ public class GermanLayout extends KeyboardLayout { }; + public static final int DEADKEYS[] = { + 0x0060, 0x00b4, 0x005e + }; + + public static final int DEADKEY_LUT[][] = { + { 0x00b4 , 0x0079 , 0x00fd } , + { 0x00b4 , 0x0061 , 0x00e1 } , + { 0x00b4 , 0x0065 , 0x00e9 } , + { 0x00b4 , 0x0075 , 0x00fa } , + { 0x00b4 , 0x0069 , 0x00ed } , + { 0x00b4 , 0x006f , 0x00f3 } , + { 0x00b4 , 0x0059 , 0x00dd } , + { 0x00b4 , 0x0041 , 0x00c1 } , + { 0x00b4 , 0x0045 , 0x00c9 } , + { 0x00b4 , 0x0055 , 0x00da } , + { 0x00b4 , 0x0049 , 0x00cd } , + { 0x00b4 , 0x004f , 0x00d3 } , + { 0x00b4 , 0x0020 , 0x00b4 } , + { 0x0060 , 0x0061 , 0x00e0 } , + { 0x0060 , 0x0065 , 0x00e8 } , + { 0x0060 , 0x0075 , 0x00f9 } , + { 0x0060 , 0x0069 , 0x00ec } , + { 0x0060 , 0x006f , 0x00f2 } , + { 0x0060 , 0x0041 , 0x00c0 } , + { 0x0060 , 0x0045 , 0x00c8 } , + { 0x0060 , 0x0055 , 0x00d9 } , + { 0x0060 , 0x0049 , 0x00cc } , + { 0x0060 , 0x004f , 0x00d2 } , + { 0x0060 , 0x0020 , 0x0060 } , + { 0x005e , 0x0061 , 0x00e2 } , + { 0x005e , 0x0065 , 0x00ea } , + { 0x005e , 0x0075 , 0x00fb } , + { 0x005e , 0x0069 , 0x00ee } , + { 0x005e , 0x006f , 0x00f4 } , + { 0x005e , 0x0041 , 0x00c2 } , + { 0x005e , 0x0045 , 0x00ca } , + { 0x005e , 0x0055 , 0x00db } , + { 0x005e , 0x0049 , 0x00ce } , + { 0x005e , 0x004f , 0x00d4 } , + { 0x005e , 0x0020 , 0x005e } , + + }; + private static GermanLayout instance = new GermanLayout(); private GermanLayout() { @@ -126,9 +169,14 @@ public class GermanLayout extends KeyboardLayout { @Override public void type(String text) { - super.type(LUT, text); + super.type(LUT, DEADKEY_LUT, DEADKEYS, text, (byte)0); } + @Override + public void type(String text, byte modifiers) { + super.type(LUT, DEADKEY_LUT, DEADKEYS, text, modifiers); + } + @Override public char getChar(int scanCode, boolean capsLock, boolean shift, boolean altGr) { return super.getChar(LUT, scanCode, capsLock, shift, altGr); @@ -137,6 +185,16 @@ public class GermanLayout extends KeyboardLayout { @Override public String getLocaleName() { return LOCALE_NAME; - } + } + + @Override + public int[][] getDeadkeyLUT() { + return DEADKEY_LUT; + } + + @Override + public int[] getDeadkeys() { + return DEADKEYS; + } } diff --git a/src/java/InputStickAPI/src/com/inputstick/api/layout/KeyboardLayout.java b/src/java/InputStickAPI/src/com/inputstick/api/layout/KeyboardLayout.java index 20cbd121..c5a741bb 100644 --- a/src/java/InputStickAPI/src/com/inputstick/api/layout/KeyboardLayout.java +++ b/src/java/InputStickAPI/src/com/inputstick/api/layout/KeyboardLayout.java @@ -101,7 +101,7 @@ public abstract class KeyboardLayout { /* 0x53 */ HIDKeycodes.KEY_DELETE, /* 0x54 */ 0, /* 0x55 */ 0, - /* 0x56 */ 0, + /* 0x56 */ HIDKeycodes.KEY_BACKSLASH_NON_US, //GERMAN LAYOUT! /* 0x57 */ HIDKeycodes.KEY_F11, /* 0x58 */ HIDKeycodes.KEY_F12, /* 0x59 */ 0, @@ -117,16 +117,19 @@ public abstract class KeyboardLayout { public static final int LAYOUT_CODE = 0; public abstract int[][] getLUT(); + public abstract int[][] getDeadkeyLUT(); + public abstract int[] getDeadkeys(); public abstract String getLocaleName(); public abstract void type(String text); + public abstract void type(String text, byte modifiers); public abstract char getChar(int scanCode, boolean capsLock, boolean shift, boolean altGr); - public void type(int[][] lut, String text) { + public void type(int[][] lut, int[][] deadkeyLUT, int[] deadkeys, String text, byte modifiers) { if (InputStickHID.getState() == ConnectionManager.STATE_READY) { char[] chars = text.toCharArray(); HIDTransaction t; for (char c : chars) { - t = getHIDTransaction(lut, c); + t = getHIDTransaction(lut, deadkeyLUT, deadkeys, c, modifiers); if (t != null) { InputStickHID.addKeyboardTransaction(t); } @@ -194,7 +197,7 @@ public abstract class KeyboardLayout { } public static int getScanCode(int[][] lut, char c) { - for (int scanCode = 0; scanCode < 80; scanCode++) { + for (int scanCode = 0; scanCode < 0x60; scanCode++) { if (lut[scanCode][0] == -1) { continue; } else { @@ -233,19 +236,79 @@ public abstract class KeyboardLayout { } - public static HIDTransaction getHIDTransaction(int[][] lut, char c) { + public static boolean isDeadkey(int[] deadkeys, char c) { + if (deadkeys != null) { + for (int key : deadkeys) { + if (key == (int)c) { + return true; + } + } + } + return false; + } + + public static int searchLUT(int[][] deadkeyLUT, char c, int returnIndex) { + if (deadkeyLUT != null) { + for (int i = 0; i < deadkeyLUT.length; i++) { + if (deadkeyLUT[i][2] == (int)c) { + return deadkeyLUT[i][returnIndex]; + } + } + } + return -1; + } + + public static int findDeadKey(int[][] deadkeyLUT, char c) { + return searchLUT(deadkeyLUT, c, 0); + } + + public static int findFollowingKey(int[][] deadkeyLUT, char c) { + return searchLUT(deadkeyLUT, c, 1); + } + + public static HIDTransaction getHIDTransaction(int[][] lut, int[][] deadkeyLUT, int[] deadkeys, char c, byte additionalModifierKeys) { byte modifiers, key; int scanCode; HIDTransaction t = new HIDTransaction(); scanCode = getScanCode(lut, c); - if (scanCode > 0) { + if (scanCode > 0) { key = getKey(scanCode); modifiers = getModifiers(lut, scanCode, c); + modifiers |= additionalModifierKeys; t.addReport(new KeyboardReport(modifiers, (byte)0)); t.addReport(new KeyboardReport(modifiers, key)); t.addReport(new KeyboardReport()); + + //add space after deadkey! + if (isDeadkey(deadkeys, c)) { + t.addReport(new KeyboardReport((byte)0, HIDKeycodes.KEY_SPACEBAR)); //this won't work if modifiers are present! + t.addReport(new KeyboardReport()); + } + + } else { + //check if character can be obtained using deadkey: + int deadkey = findDeadKey(deadkeyLUT, c); + if (deadkey > 0) { + //yes it can + int following = findFollowingKey(deadkeyLUT, c); + + scanCode = getScanCode(lut, (char)deadkey); + key = getKey(scanCode); + modifiers = getModifiers(lut, scanCode, (char)deadkey); + t.addReport(new KeyboardReport(modifiers, (byte)0)); + t.addReport(new KeyboardReport(modifiers, key)); + t.addReport(new KeyboardReport()); + + scanCode = getScanCode(lut, (char)following); + key = getKey(scanCode); + modifiers = getModifiers(lut, scanCode, (char)following); + t.addReport(new KeyboardReport(modifiers, (byte)0)); + t.addReport(new KeyboardReport(modifiers, key)); + t.addReport(new KeyboardReport()); + } + } return t; } @@ -260,7 +323,22 @@ public abstract class KeyboardLayout { return RussianLayout.getInstance(); } else if (locale.equals(GermanLayout.getInstance().getLocaleName())) { return GermanLayout.getInstance(); - } + } else if (locale.equals(SlovakLayout.getInstance().getLocaleName())) { + return SlovakLayout.getInstance(); + } else if (locale.equals(PortugueseBrazilianLayout.getInstance().getLocaleName())) { + return PortugueseBrazilianLayout.getInstance(); + } else if (locale.equals(DvorakLayout.getInstance().getLocaleName())) { + return DvorakLayout.getInstance(); + } else if (locale.equals(NorwegianLayout.getInstance().getLocaleName())) { + return NorwegianLayout.getInstance(); + } else if (locale.equals(SwedishLayout.getInstance().getLocaleName())) { + return SwedishLayout.getInstance(); + } else if (locale.equals(FrenchLayout.getInstance().getLocaleName())) { + return FrenchLayout.getInstance(); + } else if (locale.equals(SpanishLayout.getInstance().getLocaleName())) { + return SpanishLayout.getInstance(); + } + } return UnitedStatesLayout.getInstance(); diff --git a/src/java/InputStickAPI/src/com/inputstick/api/layout/PolishLayout.java b/src/java/InputStickAPI/src/com/inputstick/api/layout/PolishLayout.java index e9a3ec4b..b06ec3cc 100644 --- a/src/java/InputStickAPI/src/com/inputstick/api/layout/PolishLayout.java +++ b/src/java/InputStickAPI/src/com/inputstick/api/layout/PolishLayout.java @@ -111,6 +111,32 @@ public class PolishLayout extends KeyboardLayout { }; + public static final int DEADKEYS[] = { + 0x007e + }; + + public static final int DEADKEY_LUT[][] = { + { 0x007e , 0x006e , 0x0144 } , + { 0x007e , 0x0063 , 0x0107 } , + { 0x007e , 0x0078 , 0x017a } , + { 0x007e , 0x007a , 0x017c } , + { 0x007e , 0x0061 , 0x0105 } , + { 0x007e , 0x0073 , 0x015b } , + { 0x007e , 0x006c , 0x0142 } , + { 0x007e , 0x0065 , 0x0119 } , + { 0x007e , 0x006f , 0x00f3 } , + { 0x007e , 0x004e , 0x0143 } , + { 0x007e , 0x0043 , 0x0106 } , + { 0x007e , 0x0058 , 0x0179 } , + { 0x007e , 0x005a , 0x017b } , + { 0x007e , 0x0041 , 0x0104 } , + { 0x007e , 0x0053 , 0x015a } , + { 0x007e , 0x004c , 0x0141 } , + { 0x007e , 0x0045 , 0x0118 } , + { 0x007e , 0x004f , 0x00d3 } , + { 0x007e , 0x0020 , 0x007e } , + }; + private static PolishLayout instance = new PolishLayout(); private PolishLayout() { @@ -127,7 +153,12 @@ public class PolishLayout extends KeyboardLayout { @Override public void type(String text) { - super.type(LUT, text); + super.type(LUT, DEADKEY_LUT, DEADKEYS, text, (byte)0); + } + + @Override + public void type(String text, byte modifiers) { + super.type(LUT, DEADKEY_LUT, DEADKEYS, text, modifiers); } @Override @@ -140,5 +171,14 @@ public class PolishLayout extends KeyboardLayout { return LOCALE_NAME; } + @Override + public int[][] getDeadkeyLUT() { + return DEADKEY_LUT; + } + + @Override + public int[] getDeadkeys() { + return DEADKEYS; + } } diff --git a/src/java/InputStickAPI/src/com/inputstick/api/layout/RussianLayout.java b/src/java/InputStickAPI/src/com/inputstick/api/layout/RussianLayout.java index 0000d097..f75debb1 100644 --- a/src/java/InputStickAPI/src/com/inputstick/api/layout/RussianLayout.java +++ b/src/java/InputStickAPI/src/com/inputstick/api/layout/RussianLayout.java @@ -112,6 +112,9 @@ public class RussianLayout extends KeyboardLayout { }; + public static final int DEADKEYS[] = null; + public static final int DEADKEY_LUT[][] = null; + private static RussianLayout instance = new RussianLayout(); private RussianLayout() { @@ -128,7 +131,12 @@ public class RussianLayout extends KeyboardLayout { @Override public void type(String text) { - super.type(LUT, text); + super.type(LUT, DEADKEY_LUT, DEADKEYS, text, (byte)0); + } + + @Override + public void type(String text, byte modifiers) { + super.type(LUT, DEADKEY_LUT, DEADKEYS, text, modifiers); } @Override @@ -140,5 +148,15 @@ public class RussianLayout extends KeyboardLayout { public String getLocaleName() { return LOCALE_NAME; } + + @Override + public int[][] getDeadkeyLUT() { + return DEADKEY_LUT; + } + + @Override + public int[] getDeadkeys() { + return DEADKEYS; + } } diff --git a/src/java/InputStickAPI/src/com/inputstick/api/layout/UnitedStatesLayout.java b/src/java/InputStickAPI/src/com/inputstick/api/layout/UnitedStatesLayout.java index 7f16d907..1790a11b 100644 --- a/src/java/InputStickAPI/src/com/inputstick/api/layout/UnitedStatesLayout.java +++ b/src/java/InputStickAPI/src/com/inputstick/api/layout/UnitedStatesLayout.java @@ -98,10 +98,10 @@ public class UnitedStatesLayout extends KeyboardLayout { /* 50 */ { -1 , 0 , 0 , 0 , 0 , 0 } , /* 51 */ { -1 , 0 , 0 , 0 , 0 , 0 } , /* 52 */ { -1 , 0 , 0 , 0 , 0 , 0 } , - /* 53 */ { 0 , 0x002e , 0x002e , -1 , -1 , -1 } , + /* 53 */ { 0 , 0x002e , 0x002e , -1 , -1 , -1 } , /* 54 */ { -1 , 0 , 0 , 0 , 0 , 0 } , /* 55 */ { -1 , 0 , 0 , 0 , 0 , 0 } , - /* 56 */ { 0 , 0x005c , 0x007c , 0x001c , -1 , -1 } , + /* 56 */ { 0 , 0x005c , 0x007c , 0x001c , -1 , -1 } , /* 57 */ { -1 , 0 , 0 , 0 , 0 , 0 } , /* 58 */ { -1 , 0 , 0 , 0 , 0 , 0 } , /* 59 */ { -1 , 0 , 0 , 0 , 0 , 0 } , @@ -114,6 +114,9 @@ public class UnitedStatesLayout extends KeyboardLayout { }; + public static final int DEADKEYS[] = null; + public static final int DEADKEY_LUT[][] = null; + private static UnitedStatesLayout instance = new UnitedStatesLayout(); private UnitedStatesLayout() { @@ -130,7 +133,12 @@ public class UnitedStatesLayout extends KeyboardLayout { @Override public void type(String text) { - super.type(LUT, text); + super.type(LUT, DEADKEY_LUT, DEADKEYS, text, (byte)0); + } + + @Override + public void type(String text, byte modifiers) { + super.type(LUT, DEADKEY_LUT, DEADKEYS, text, modifiers); } @Override @@ -141,6 +149,16 @@ public class UnitedStatesLayout extends KeyboardLayout { @Override public String getLocaleName() { return LOCALE_NAME; - } + } + + @Override + public int[][] getDeadkeyLUT() { + return DEADKEY_LUT; + } + + @Override + public int[] getDeadkeys() { + return DEADKEYS; + } } diff --git a/src/java/InputStickAPI/src/com/inputstick/init/BasicInitManager.java b/src/java/InputStickAPI/src/com/inputstick/init/BasicInitManager.java index 413da8e2..621b6945 100644 --- a/src/java/InputStickAPI/src/com/inputstick/init/BasicInitManager.java +++ b/src/java/InputStickAPI/src/com/inputstick/init/BasicInitManager.java @@ -3,9 +3,7 @@ package com.inputstick.init; import com.inputstick.api.Packet; -public class BasicInitManager extends InitManager { - - private boolean initDone = false; +public class BasicInitManager extends InitManager { public BasicInitManager(byte[] key) { super(key); @@ -14,48 +12,46 @@ public class BasicInitManager extends InitManager { @Override public void onConnected() { - /*Packet p = new Packet(false, Packet.RAW_OLD_BOOTLOADER); //compatibility - sendPacket(p);*/ - + /*Packet p = new Packet(false, Packet.RAW_OLD_BOOTLOADER); //compatibility with old protocol version + sendPacket(p);*/ sendPacket(new Packet(true, Packet.CMD_RUN_FW)); } - @Override public void onData(byte[] data) { byte cmd = data[0]; byte respCode = data[1]; byte param = data[1]; - if (cmd == Packet.CMD_RUN_FW) { - sendPacket(new Packet(true, Packet.CMD_GET_INFO)); - } - - if (cmd == Packet.CMD_GET_INFO) { - //store info - sendPacket(new Packet(true, Packet.CMD_INIT)); //TODO params! - } - - if (cmd == Packet.CMD_INIT) { - if (respCode == Packet.RESP_OK) { - initDone = true; - sendPacket(new Packet(false, Packet.CMD_HID_STATUS_REPORT)); - } else { - mListener.onInitFailure(respCode); - } - } - - if (cmd == Packet.CMD_HID_STATUS) { - if (initDone) { - if (param == 0x05) { - mListener.onInitReady(); + switch (cmd) { + case Packet.CMD_RUN_FW: + sendPacket(new Packet(true, Packet.CMD_FW_INFO)); + break; + case Packet.CMD_FW_INFO: + onFWInfo(data, true, true, new Packet(true, Packet.CMD_INIT)); //TODO next FW: params! + break; + case Packet.CMD_INIT: + if (respCode == Packet.RESP_OK) { + initDone = true; + sendPacket(new Packet(true, Packet.CMD_HID_STATUS_REPORT)); } else { - mListener.onInitNotReady(); - } - } + mListener.onInitFailure(respCode); + } + break; + case Packet.CMD_INIT_AUTH: + onAuth(data, true, new Packet(true, Packet.CMD_INIT)); //TODO next FW: params! + break; + case Packet.CMD_HID_STATUS: + if (initDone) { + if (param == 0x05) { + mListener.onInitReady(); + } else { + mListener.onInitNotReady(); + } + } + break; } } - } diff --git a/src/java/InputStickAPI/src/com/inputstick/init/InitManager.java b/src/java/InputStickAPI/src/com/inputstick/init/InitManager.java index 7d8907ab..0cdd0c25 100644 --- a/src/java/InputStickAPI/src/com/inputstick/init/InitManager.java +++ b/src/java/InputStickAPI/src/com/inputstick/init/InitManager.java @@ -1,33 +1,125 @@ package com.inputstick.init; +import java.util.Timer; +import java.util.TimerTask; + +import com.inputstick.api.InputStickError; import com.inputstick.api.Packet; import com.inputstick.api.PacketManager; public class InitManager { + public static final int DEFAULT_INIT_TIMEOUT = 60000; //60s init timeout + protected PacketManager mPacketManager; protected InitManagerListener mListener; protected byte[] mKey; + protected DeviceInfo mInfo; + protected boolean initDone; + + //private Timer t; public InitManager(byte[] key) { - mKey = key; + mKey = key; } - public void init(InitManagerListener listener, PacketManager packetManager) { + + public DeviceInfo getDeviceInfo() { + return mInfo; + } + + public boolean isEncrypted() { + return mPacketManager.isEncrypted(); + } + + + public void init(InitManagerListener listener, PacketManager packetManager) { mListener = listener; mPacketManager = packetManager; + + initDone = false; } + //WRONG THREAD! + /*public void startTimeoutCountdown(int timeout) { + t = new Timer(); + t.schedule(new TimerTask() { + @Override + public void run() { + if ( !initDone) { + mListener.onInitFailure(InputStickError.ERROR_INIT_TIMEDOUT); + } + } + }, timeout); + }*/ + public void onConnected() { mListener.onInitReady(); } public void onData(byte[] data) { - + //byte cmd = data[0]; + //byte param = data[1]; } public void sendPacket(Packet p) { mPacketManager.sendPacket(p); } + public void onFWInfo(byte[] data, boolean authenticate, boolean enableEncryption, Packet sendNext) { + mInfo = new DeviceInfo(data); + + if (authenticate) { + if (mInfo.isPasswordProtected()) { + if (mKey != null) { + //authenticate + sendPacket(mPacketManager.encPacket(enableEncryption)); + } else { + mListener.onInitFailure(InputStickError.ERROR_SECURITY_NO_KEY); + } + } else { + if (mKey != null) { + //possible scenarios: FW upgrade / password removed using other device/app / tampering! + mListener.onInitFailure(InputStickError.ERROR_SECURITY_NOT_PROTECTED); + } + sendPacket(sendNext); + } + } else { + sendPacket(sendNext); + } + } + + public void onAuth(byte[] data, boolean enableOutEncryption, Packet sendNext) { + byte respCode = data[1]; + + switch (respCode) { + case Packet.RESP_OK: + byte[] cmp = new byte[16]; + //TODO check length! + System.arraycopy(data, 2, cmp, 0, 16); + if (mPacketManager.setEncryption(cmp, enableOutEncryption)) { + sendPacket(sendNext); + } else { + mListener.onInitFailure(InputStickError.ERROR_SECURITY_CHALLENGE); + } + break; + + case 0x20: + mListener.onInitFailure(InputStickError.ERROR_SECURITY_INVALID_KEY); + break; + + case 0x21: + mListener.onInitFailure(InputStickError.ERROR_SECURITY_NOT_PROTECTED); + break; + + case Packet.RESP_UNKNOWN_CMD: + mListener.onInitFailure(InputStickError.ERROR_SECURITY_NOT_SUPPORTED); + break; + + default: + mListener.onInitFailure(InputStickError.ERROR_SECURITY); + } + + } + } diff --git a/src/java/PluginInputStick/gen/com/inputstick/api/R.java b/src/java/PluginInputStick/gen/com/inputstick/api/R.java index f6c5a1d2..5d18b108 100644 --- a/src/java/PluginInputStick/gen/com/inputstick/api/R.java +++ b/src/java/PluginInputStick/gen/com/inputstick/api/R.java @@ -7,11 +7,24 @@ package com.inputstick.api; public final class R { + public static final class dimen { + public static final int activity_horizontal_margin = 0x7f050000; + public static final int activity_vertical_margin = 0x7f050001; + } public static final class drawable { public static final int ic_launcher = 0x7f020000; } + public static final class id { + public static final int action_settings = 0x7f0a0003; + } + public static final class menu { + public static final int install_utility = 0x7f090000; + } public static final class string { + public static final int action_settings = 0x7f060002; public static final int app_name = 0x7f060000; + public static final int hello_world = 0x7f060003; + public static final int title_activity_install_utility = 0x7f060001; } public static final class style { public static final int AppBaseTheme = 0x7f070000; diff --git a/src/java/PluginInputStick/gen/keepass2android/plugin/inputstick/R.java b/src/java/PluginInputStick/gen/keepass2android/plugin/inputstick/R.java index 92e28f87..08789a03 100644 --- a/src/java/PluginInputStick/gen/keepass2android/plugin/inputstick/R.java +++ b/src/java/PluginInputStick/gen/keepass2android/plugin/inputstick/R.java @@ -21,6 +21,11 @@ public final class R { (such as screen margins) for screens with more than 820dp of available width. This would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). + Default screen margins, per the Android Design guidelines. + + Customize dimensions originally defined in res/values/dimens.xml (such as + screen margins) for sw720dp devices (e.g. 10" tablets) in landscape here. + Default screen margins, per the Android Design guidelines. Example customization of dimensions originally defined in res/values/dimens.xml @@ -46,23 +51,26 @@ public final class R { public static final int fragment_main=0x7f030001; } public static final class menu { - public static final int main=0x7f090000; + public static final int install_utility=0x7f090000; + public static final int main=0x7f090001; } public static final class string { - public static final int action_input_stick=0x7f060005; - public static final int action_settings=0x7f060001; - public static final int action_type_enter=0x7f060007; - public static final int action_type_tab=0x7f060006; - public static final int action_type_user_tab_pass_enter=0x7f060008; + public static final int action_input_stick=0x7f060007; + public static final int action_settings=0x7f060002; + public static final int action_type_enter=0x7f060009; + public static final int action_type_tab=0x7f060008; + public static final int action_type_user_tab_pass_enter=0x7f06000a; public static final int app_name=0x7f060000; /** Strings related to Settings */ - public static final int configure_plugin=0x7f06000a; - public static final int kp2aplugin_author=0x7f060004; - public static final int kp2aplugin_shortdesc=0x7f060003; - public static final int kp2aplugin_title=0x7f060002; - public static final int layout_title=0x7f06000b; - public static final int title_activity_settings=0x7f060009; + public static final int configure_plugin=0x7f06000c; + public static final int hello_world=0x7f060003; + public static final int kp2aplugin_author=0x7f060006; + public static final int kp2aplugin_shortdesc=0x7f060005; + public static final int kp2aplugin_title=0x7f060004; + public static final int layout_title=0x7f06000d; + public static final int title_activity_install_utility=0x7f060001; + public static final int title_activity_settings=0x7f06000b; } public static final class style { /** diff --git a/src/java/PluginInputStick/res/values/strings_activity_settings.xml b/src/java/PluginInputStick/res/values/strings_activity_settings.xml index d3adfd6e..31bace40 100644 --- a/src/java/PluginInputStick/res/values/strings_activity_settings.xml +++ b/src/java/PluginInputStick/res/values/strings_activity_settings.xml @@ -8,17 +8,31 @@ Host keyboard layout - English (United States) - en-US - German - de-DE - Polish - pl-PL - Russian - ru-RU + English (US) + German + Polish + Russian + Slovak + Portuguese (BR) + Norwegian + Swedish + French + Spanish + English (Dvorak) - en-US + en-US de-DE pl-PL ru-RU + sk-SK + pt-BR + nb-NO + sv-SE + fr-FR + es-ES + en-DV