mirror of
https://github.com/moparisthebest/keepass2android
synced 2024-11-22 01:02:16 -05:00
updated InputStick API and added more languages (change by Jakub)
updated version code
This commit is contained in:
parent
97bcf753a4
commit
3c5c9105b7
@ -1,3 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.inputstick.api"
|
||||
android:versionCode="1"
|
||||
|
@ -10,11 +10,30 @@ package com.inputstick.api;
|
||||
public final class R {
|
||||
public static final class attr {
|
||||
}
|
||||
public static final class dimen {
|
||||
/** 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.
|
||||
|
||||
*/
|
||||
public static int activity_horizontal_margin=0x7f030000;
|
||||
public static int activity_vertical_margin=0x7f030001;
|
||||
}
|
||||
public static final class drawable {
|
||||
public static int ic_launcher=0x7f020000;
|
||||
}
|
||||
public static final class id {
|
||||
public static int action_settings=0x7f070000;
|
||||
}
|
||||
public static final class menu {
|
||||
public static int install_utility=0x7f060000;
|
||||
}
|
||||
public static final class string {
|
||||
public static int app_name=0x7f030000;
|
||||
public static int action_settings=0x7f040002;
|
||||
public static int app_name=0x7f040000;
|
||||
public static int hello_world=0x7f040003;
|
||||
public static int title_activity_install_utility=0x7f040001;
|
||||
}
|
||||
public static final class style {
|
||||
/**
|
||||
@ -38,10 +57,10 @@ public final class R {
|
||||
|
||||
API 14 theme customizations can go here.
|
||||
*/
|
||||
public static int AppBaseTheme=0x7f040000;
|
||||
public static int AppBaseTheme=0x7f050000;
|
||||
/** Application theme.
|
||||
All customizations that are NOT specific to a particular API-level can go here.
|
||||
*/
|
||||
public static int AppTheme=0x7f040001;
|
||||
public static int AppTheme=0x7f050001;
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
@ -11,5 +11,5 @@
|
||||
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
||||
|
||||
# Project target.
|
||||
target=android-19
|
||||
target=android-20
|
||||
android.library=true
|
||||
|
@ -1,5 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<string name="app_name">InputStickAPI</string>
|
||||
<string name="title_activity_install_utility">Download InputStickUtility</string>
|
||||
<string name="action_settings">Settings</string>
|
||||
<string name="hello_world">Hello world!</string>
|
||||
|
||||
</resources>
|
||||
|
@ -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));
|
||||
ready = true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@ -49,4 +51,7 @@ public class AES {
|
||||
return mCipherDecr.update(data);
|
||||
}
|
||||
|
||||
public boolean isReady() {
|
||||
return ready;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
||||
@ -46,30 +45,11 @@ public class BTConnectionManager extends ConnectionManager implements InitManage
|
||||
case BTService.EVENT_CANCELLED:
|
||||
manager.onDisconnected();
|
||||
break;
|
||||
case BTService.EVENT_CONNECTION_FAILED:
|
||||
manager.onFailure(1);
|
||||
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);
|
||||
case BTService.EVENT_ERROR:
|
||||
manager.onFailure(msg.arg1);
|
||||
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();
|
||||
}
|
||||
|
||||
@ -90,6 +71,7 @@ public class BTConnectionManager extends ConnectionManager implements InitManage
|
||||
private void onFailure(int code) {
|
||||
mErrorCode = code;
|
||||
stateNotify(ConnectionManager.STATE_FAILURE);
|
||||
disconnect();
|
||||
}
|
||||
|
||||
private void onData(byte[] rawData) {
|
||||
@ -97,13 +79,12 @@ 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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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<InputStickStateListener> mStateListeners = new Vector<InputStickStateListener>();
|
||||
protected Vector<InputStickDataListener> mDataListeners = new Vector<InputStickDataListener>();
|
||||
|
||||
@ -47,9 +40,11 @@ public abstract class ConnectionManager {
|
||||
|
||||
public void addStateListener(InputStickStateListener listener) {
|
||||
if (listener != null) {
|
||||
if ( !mStateListeners.contains(listener)) {
|
||||
mStateListeners.add(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeStateListener(InputStickStateListener listener) {
|
||||
if (listener != null) {
|
||||
@ -59,9 +54,11 @@ public abstract class ConnectionManager {
|
||||
|
||||
public void addDataListener(InputStickDataListener listener) {
|
||||
if (listener != null) {
|
||||
if ( !mDataListeners.contains(listener)) {
|
||||
mDataListeners.add(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeDataListener(InputStickDataListener listener) {
|
||||
if (listener != null) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
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);
|
||||
@ -176,5 +173,4 @@ public class IPCConnectionManager extends ConnectionManager {
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -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:");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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");
|
||||
//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]);
|
||||
@ -114,8 +122,10 @@ public class PacketManager {
|
||||
}
|
||||
|
||||
public void sendPacket(Packet p) {
|
||||
if (p != null) {
|
||||
sendPacket(p, mEncryption);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendPacket(Packet p, boolean encrypt) {
|
||||
byte[] result, header, data;
|
||||
@ -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;
|
||||
|
@ -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,12 +33,14 @@ public abstract class Util {
|
||||
|
||||
public static void printHex(byte[] toPrint) {
|
||||
if (debug) {
|
||||
if (toPrint != null) {
|
||||
int cnt = 0;
|
||||
String s;
|
||||
byte b;
|
||||
for (int i = 0; i < toPrint.length; i++) {
|
||||
b = toPrint[i];
|
||||
if ((b < 10) && (b >= 0)) {
|
||||
//0x0..0xF = 0x00..0x0F
|
||||
if ((b < 0x10) && (b >= 0)) {
|
||||
s = Integer.toHexString((int)b);
|
||||
s = "0" + s;
|
||||
} else {
|
||||
@ -43,6 +57,10 @@ public abstract class Util {
|
||||
cnt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
System.out.println("null");
|
||||
}
|
||||
System.out.println("\n#####");
|
||||
}
|
||||
}
|
||||
@ -80,4 +98,17 @@ public abstract class Util {
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -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<InputStickStateListener> mStateListeners = new Vector<InputStickStateListener>();
|
||||
|
||||
|
||||
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,9 +119,11 @@ public class InputStickHID implements InputStickStateListener, InputStickDataLis
|
||||
|
||||
public static void addStateListener(InputStickStateListener listener) {
|
||||
if (listener != null) {
|
||||
if ( !mStateListeners.contains(listener)) {
|
||||
mStateListeners.add(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void removeStateListener(InputStickStateListener listener) {
|
||||
if (listener != null) {
|
||||
@ -100,6 +131,22 @@ public class InputStickHID implements InputStickStateListener, InputStickDataLis
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
@ -123,24 +182,70 @@ public class InputStickHID implements InputStickStateListener, InputStickDataLis
|
||||
|
||||
@Override
|
||||
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.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();
|
||||
keyboardQueue.deviceReady(null, 0);
|
||||
}
|
||||
if (mHIDInfo.isMouseReady()) {
|
||||
mouseQueue.deviceReady();
|
||||
mouseQueue.deviceReady(null, 0);
|
||||
}
|
||||
if (mHIDInfo.isConsumerReady()) {
|
||||
consumerQueue.deviceReady();
|
||||
consumerQueue.deviceReady(null, 0);
|
||||
}
|
||||
}
|
||||
|
||||
InputStickKeyboard.setLEDs(mHIDInfo.getNumLock(), mHIDInfo.getCapsLock(), mHIDInfo.getScrollLock());
|
||||
@ -148,5 +253,40 @@ public class InputStickHID implements InputStickStateListener, InputStickDataLis
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -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,14 +26,25 @@ public class InputStickKeyboard {
|
||||
|
||||
private static Vector<InputStickKeyboardListener> mKeyboardListeners = new Vector<InputStickKeyboardListener>();
|
||||
|
||||
private static final SparseArray<String> ledsMap;
|
||||
static
|
||||
{
|
||||
ledsMap = new SparseArray<String>();
|
||||
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) {
|
||||
if ( !mKeyboardListeners.contains(listener)) {
|
||||
mKeyboardListeners.add(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void removeKeyboardListener(InputStickKeyboardListener listener) {
|
||||
if (listener != null) {
|
||||
@ -115,4 +132,24 @@ public class InputStickKeyboard {
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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<String> buttonsMap;
|
||||
static
|
||||
{
|
||||
buttonsMap = new SparseArray<String>();
|
||||
buttonsMap.put(BUTTON_LEFT, "Left");
|
||||
buttonsMap.put(BUTTON_RIGHT, "Right");
|
||||
buttonsMap.put(BUTTON_MIDDLE, "Middle");
|
||||
}
|
||||
|
||||
private static boolean mReportProtocol;
|
||||
|
||||
private InputStickMouse() {
|
||||
@ -54,4 +65,24 @@ public class InputStickMouse {
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
@ -72,7 +64,6 @@ public class BTService {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
final String action = intent.getAction();
|
||||
System.out.println("ACTION: "+action);
|
||||
if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
|
||||
final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
|
||||
if ((state == BluetoothAdapter.STATE_ON) && (turnBluetoothOn)) {
|
||||
@ -103,11 +94,11 @@ public class BTService {
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -357,10 +348,12 @@ public class BTService {
|
||||
int rxTmp;
|
||||
int lengthByte;
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<String> modifiersMap;
|
||||
static
|
||||
{
|
||||
modifiersMap = new SparseArray<String>();
|
||||
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<String> keyMap;
|
||||
static
|
||||
{
|
||||
keyMap = new SparseArray<String>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -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<HIDTransaction> queue;
|
||||
private final ConnectionManager mConnectionManager;
|
||||
private final byte cmd;
|
||||
private boolean ready;
|
||||
|
||||
private int mInterfaceType;
|
||||
private boolean mustNotify;
|
||||
private Vector<OnEmptyBufferListener> mBufferEmptyListeners = new Vector<OnEmptyBufferListener>();
|
||||
|
||||
private Timer t;
|
||||
private boolean timerCancelled;
|
||||
private boolean sentAhead;
|
||||
private long lastTime;
|
||||
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<HIDTransaction>();
|
||||
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() {
|
||||
private int sendNext(int maxReports) {
|
||||
HIDTransaction transaction;
|
||||
byte reports = 0;
|
||||
ready = false;
|
||||
Packet p = new Packet(false, cmd, reports);
|
||||
|
||||
//assume there is at least 1 element in queue
|
||||
transaction = queue.firstElement();
|
||||
if (transaction.getReportsCount() > BUFFER_SIZE) {
|
||||
//transaction too big! split
|
||||
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,32 +117,182 @@ public class HIDTransactionQueue {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//!! total number of reports must be < 32 ! (max packet limitation)
|
||||
p.modifyByte(1, reports); //set reports count
|
||||
mConnectionManager.sendPacket(p);
|
||||
|
||||
lastReports = reports;
|
||||
lastTime = System.currentTimeMillis();
|
||||
minNextTime = lastTime + (lastReports * 4) + BT_DELAY;
|
||||
|
||||
if (queue.isEmpty()) {
|
||||
notifyOnLocalBufferEmpty();
|
||||
}
|
||||
|
||||
public void addTransaction(HIDTransaction transaction) {
|
||||
if (queue.isEmpty()) {
|
||||
if (System.currentTimeMillis() > lastTime + (lastReports * 8 * 2/*just to be safe*/)) {
|
||||
ready = true;
|
||||
return reports;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
public void deviceReady() {
|
||||
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();
|
||||
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 ++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,7 +169,12 @@ 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
|
||||
@ -139,4 +187,14 @@ public class GermanLayout extends KeyboardLayout {
|
||||
return LOCALE_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[][] getDeadkeyLUT() {
|
||||
return DEADKEY_LUT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getDeadkeys() {
|
||||
return DEADKEYS;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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,7 +236,37 @@ 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;
|
||||
|
||||
@ -242,10 +275,40 @@ public abstract class KeyboardLayout {
|
||||
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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
@ -141,4 +149,14 @@ public class RussianLayout extends KeyboardLayout {
|
||||
return LOCALE_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[][] getDeadkeyLUT() {
|
||||
return DEADKEY_LUT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getDeadkeys() {
|
||||
return DEADKEYS;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
@ -143,4 +151,14 @@ public class UnitedStatesLayout extends KeyboardLayout {
|
||||
return LOCALE_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[][] getDeadkeyLUT() {
|
||||
return DEADKEY_LUT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getDeadkeys() {
|
||||
return DEADKEYS;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5,8 +5,6 @@ import com.inputstick.api.Packet;
|
||||
|
||||
public class BasicInitManager extends InitManager {
|
||||
|
||||
private boolean initDone = false;
|
||||
|
||||
public BasicInitManager(byte[] key) {
|
||||
super(key);
|
||||
}
|
||||
@ -14,38 +12,36 @@ public class BasicInitManager extends InitManager {
|
||||
|
||||
@Override
|
||||
public void onConnected() {
|
||||
/*Packet p = new Packet(false, Packet.RAW_OLD_BOOTLOADER); //compatibility
|
||||
/*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) {
|
||||
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(false, Packet.CMD_HID_STATUS_REPORT));
|
||||
sendPacket(new Packet(true, Packet.CMD_HID_STATUS_REPORT));
|
||||
} else {
|
||||
mListener.onInitFailure(respCode);
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd == Packet.CMD_HID_STATUS) {
|
||||
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();
|
||||
@ -53,9 +49,9 @@ public class BasicInitManager extends InitManager {
|
||||
mListener.onInitNotReady();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
/**
|
||||
|
@ -8,10 +8,17 @@
|
||||
<string name="layout_title">Host keyboard layout</string>
|
||||
|
||||
<string-array name="layout_names">
|
||||
<item>English (United States) - en-US</item>
|
||||
<item>German - de-DE</item>
|
||||
<item>Polish - pl-PL</item>
|
||||
<item>Russian - ru-RU</item>
|
||||
<item>English (US)</item>
|
||||
<item>German</item>
|
||||
<item>Polish</item>
|
||||
<item>Russian</item>
|
||||
<item>Slovak</item>
|
||||
<item>Portuguese (BR)</item>
|
||||
<item>Norwegian</item>
|
||||
<item>Swedish</item>
|
||||
<item>French</item>
|
||||
<item>Spanish</item>
|
||||
<item>English (Dvorak)</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="layout_values">
|
||||
@ -19,6 +26,13 @@
|
||||
<item>de-DE</item>
|
||||
<item>pl-PL</item>
|
||||
<item>ru-RU</item>
|
||||
<item>sk-SK</item>
|
||||
<item>pt-BR</item>
|
||||
<item>nb-NO</item>
|
||||
<item>sv-SE</item>
|
||||
<item>fr-FR</item>
|
||||
<item>es-ES</item>
|
||||
<item>en-DV</item>
|
||||
</string-array>
|
||||
|
||||
</resources>
|
||||
|
Loading…
Reference in New Issue
Block a user