+InputStick plugin

+ "PluginA" (sample plugin)
+ icons and updated text for PluginQR
This commit is contained in:
Philipp Crocoll 2014-06-01 07:06:58 +02:00
parent ba954c0aa0
commit 52c5c5aa89
111 changed files with 5103 additions and 2 deletions

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>InputStickAPI</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,4 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.source=1.6

View File

@ -0,0 +1,17 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.inputstick.api"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="9"
android:targetSdkVersion="17" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
</application>
</manifest>

View File

@ -0,0 +1,6 @@
/** Automatically generated file. DO NOT MODIFY */
package com.inputstick.api;
public final class BuildConfig {
public final static boolean DEBUG = true;
}

View File

@ -0,0 +1,47 @@
/* AUTO-GENERATED FILE. DO NOT MODIFY.
*
* This class was automatically generated by the
* aapt tool from the resource data it found. It
* should not be modified by hand.
*/
package com.inputstick.api;
public final class R {
public static final class attr {
}
public static final class drawable {
public static int ic_launcher=0x7f020000;
}
public static final class string {
public static int app_name=0x7f030000;
}
public static final class style {
/**
Base application theme, dependent on API level. This theme is replaced
by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
Theme customizations available in newer API levels can go in
res/values-vXX/styles.xml, while customizations related to
backward-compatibility can go here.
Base application theme for API 11+. This theme completely replaces
AppBaseTheme from res/values/styles.xml on API 11+ devices.
API 11 theme customizations can go here.
Base application theme for API 14+. This theme completely replaces
AppBaseTheme from BOTH res/values/styles.xml and
res/values-v11/styles.xml on API 14+ devices.
API 14 theme customizations can go here.
*/
public static int AppBaseTheme=0x7f040000;
/** Application theme.
All customizations that are NOT specific to a particular API-level can go here.
*/
public static int AppTheme=0x7f040001;
}
}

Binary file not shown.

View File

@ -0,0 +1,20 @@
# To enable ProGuard in your project, edit project.properties
# to define the proguard.config property as described in that file.
#
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in ${sdk.dir}/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the ProGuard
# include property in project.properties.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

View File

@ -0,0 +1,15 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system edit
# "ant.properties", and override values to adapt the script to your
# project structure.
#
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
# Project target.
target=android-19
android.library=true

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -0,0 +1,11 @@
<resources>
<!--
Base application theme for API 11+. This theme completely replaces
AppBaseTheme from res/values/styles.xml on API 11+ devices.
-->
<style name="AppBaseTheme" parent="android:Theme.Holo.Light">
<!-- API 11 theme customizations can go here. -->
</style>
</resources>

View File

@ -0,0 +1,12 @@
<resources>
<!--
Base application theme for API 14+. This theme completely replaces
AppBaseTheme from BOTH res/values/styles.xml and
res/values-v11/styles.xml on API 14+ devices.
-->
<style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
<!-- API 14 theme customizations can go here. -->
</style>
</resources>

View File

@ -0,0 +1,5 @@
<resources>
<string name="app_name">InputStickAPI</string>
</resources>

View File

@ -0,0 +1,20 @@
<resources>
<!--
Base application theme, dependent on API level. This theme is replaced
by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
-->
<style name="AppBaseTheme" parent="android:Theme.Light">
<!--
Theme customizations available in newer API levels can go in
res/values-vXX/styles.xml, while customizations related to
backward-compatibility can go here.
-->
</style>
<!-- Application theme. -->
<style name="AppTheme" parent="AppBaseTheme">
<!-- All customizations that are NOT specific to a particular API-level can go here. -->
</style>
</resources>

View File

@ -0,0 +1,52 @@
package com.inputstick.api;
import java.security.MessageDigest;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class AES {
private Cipher mCipherEncr;
private Cipher mCipherDecr;
private SecretKeySpec mKey;
public AES() {
}
public static byte[] getMD5(String s) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
return md.digest(s.getBytes("UTF-8"));
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public byte[] init(byte[] key) {
byte[] iv = null;
try {
mKey = new SecretKeySpec(key, "AES");
mCipherEncr = Cipher.getInstance("AES/CBC/NoPadding");
mCipherEncr.init(Cipher.ENCRYPT_MODE, mKey);
iv = mCipherEncr.getIV();
//System.out.println("AES IV: ");
Util.printHex(iv);
mCipherDecr = Cipher.getInstance("AES/CBC/NoPadding");
mCipherDecr.init(Cipher.DECRYPT_MODE, mKey, new IvParameterSpec(iv));
} catch (Exception e) {
e.printStackTrace();
}
return iv;
}
public byte[] encrypt(byte[] data) {
return mCipherEncr.update(data);
}
public byte[] decrypt(byte[] data) {
return mCipherDecr.update(data);
}
}

View File

@ -0,0 +1,168 @@
package com.inputstick.api;
import java.lang.ref.WeakReference;
import android.app.Application;
import android.os.Handler;
import android.os.Message;
import com.inputstick.api.bluetooth.BTService;
import com.inputstick.init.InitManager;
import com.inputstick.init.InitManagerListener;
public class BTConnectionManager extends ConnectionManager implements InitManagerListener {
//private static final String mTag = "BTConnectionManager";
private String mMac;
private byte[] mKey;
private InitManager mInitManager;
private Application mApp;
private BTService mBTService;
private PacketManager mPacketManager;
//private PacketQueue mPacketQueue;
private final BTHandler mBTHandler = new BTHandler(this);
private static class BTHandler extends Handler {
private final WeakReference<BTConnectionManager> ref;
BTHandler(BTConnectionManager manager) {
ref = new WeakReference<BTConnectionManager>(manager);
}
@Override
public void handleMessage(Message msg) {
BTConnectionManager manager = ref.get();
switch (msg.what) {
case BTService.EVENT_DATA:
manager.onData((byte[])msg.obj);
break;
case BTService.EVENT_CONNECTED:
manager.onConnected();
break;
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);
break;
}
}
}
private void onConnecting() {
stateNotify(ConnectionManager.STATE_CONNECTING);
}
private void onConnected() {
stateNotify(ConnectionManager.STATE_CONNECTED);
mInitManager.onConnected();
}
private void onDisconnected() {
stateNotify(ConnectionManager.STATE_DISCONNECTED);
}
private void onFailure(int code) {
mErrorCode = code;
stateNotify(ConnectionManager.STATE_FAILURE);
}
private void onData(byte[] rawData) {
byte[] data;
data = mPacketManager.bytesToPacket(rawData);
if (data == null) {
//TODO
return;
}
mInitManager.onData(data);
//sendNext(); TODO
for (InputStickDataListener listener : mDataListeners) {
listener.onInputStickData(data);
}
}
public BTConnectionManager(InitManager initManager, Application app, String mac, byte[] key) {
mInitManager = initManager;
mMac = mac;
mKey = key;
mApp = app;
}
@Override
public void connect() {
connect(false, BTService.DEFAULT_CONNECT_TIMEOUT);
}
public void connect(boolean reflection, int timeout) {
mErrorCode = ConnectionManager.ERROR_NONE;
if (mBTService == null) {
mBTService = new BTService(mApp, mBTHandler);
mPacketManager = new PacketManager(mBTService, mKey);
mInitManager.init(this, mPacketManager);
}
mBTService.setConnectTimeout(timeout);
mBTService.enableReflection(reflection);
mBTService.connect(mMac);
onConnecting();
}
@Override
public void disconnect() {
if (mBTService != null) {
mBTService.disconnect();
}
}
@Override
public void sendPacket(Packet p) {
mPacketManager.sendPacket(p); //TODO tmp; zalozmy z beda same NO_RESP ???
}
@Override
public void onInitReady() {
stateNotify(ConnectionManager.STATE_READY);
}
@Override
public void onInitNotReady() {
stateNotify(ConnectionManager.STATE_CONNECTED);
}
@Override
public void onInitFailure(int code) {
onFailure(code);
}
}

View File

@ -0,0 +1,72 @@
package com.inputstick.api;
import java.util.Vector;
public abstract class ConnectionManager {
public static final int STATE_DISCONNECTED = 0;
public static final int STATE_FAILURE = 1;
public static final int STATE_CONNECTING = 2;
public static final int STATE_CONNECTED = 3;
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>();
protected int mState;
protected int mErrorCode;
public abstract void connect();
public abstract void disconnect();
public abstract void sendPacket(Packet p);
protected void stateNotify(int state) {
if (mState != state) {
mState = state;
for (InputStickStateListener listener : mStateListeners) {
listener.onStateChanged(state);
}
}
}
public int getState() {
return mState;
}
public int getErrorCode() {
return mErrorCode;
}
public void addStateListener(InputStickStateListener listener) {
if (listener != null) {
mStateListeners.add(listener);
}
}
public void removeStateListener(InputStickStateListener listener) {
if (listener != null) {
mStateListeners.remove(listener);
}
}
public void addDataListener(InputStickDataListener listener) {
if (listener != null) {
mDataListeners.add(listener);
}
}
public void removeDataListener(InputStickDataListener listener) {
if (listener != null) {
mDataListeners.remove(listener);
}
}
}

View File

@ -0,0 +1,115 @@
package com.inputstick.api;
public class HIDInfo {
private int state;
private boolean numLock;
private boolean capsLock;
private boolean scrollLock;
private boolean keyboardReportProtocol;
private boolean mouseReportProtocol;
private boolean keyboardReady;
private boolean mouseReady;
private boolean consumerReady;
public HIDInfo() {
keyboardReportProtocol = true;
mouseReportProtocol = true;
}
public void update(byte[] data) {
state = data[1];
int leds = data[2];
if ((leds & 0x01) != 0) {
numLock = true;
} else {
numLock = false;
}
if ((leds & 0x02) != 0) {
capsLock = true;
} else {
capsLock = false;
}
if ((leds & 0x04) != 0) {
scrollLock = true;
} else {
scrollLock = false;
}
if (data[3] == 0) {
keyboardReportProtocol = true;
} else {
keyboardReportProtocol = false;
}
if (data[4] == 0) {
keyboardReady = false;
} else {
keyboardReady = true;
}
if (data[5] == 0) {
mouseReportProtocol = true;
} else {
mouseReportProtocol = false;
}
if (data[6] == 0) {
mouseReady = false;
} else {
mouseReady = true;
}
if (data[7] == 0) {
consumerReady = false;
} else {
consumerReady = true;
}
}
public void setKeyboardBusy() {
keyboardReady = false;
}
public int getState() {
return state;
}
public boolean getNumLock() {
return numLock;
}
public boolean getCapsLock() {
return capsLock;
}
public boolean getScrollLock() {
return scrollLock;
}
public boolean isKeyboardReportProtocol() {
return keyboardReportProtocol;
}
public boolean isMouseReportProtocol() {
return mouseReportProtocol;
}
public boolean isKeyboardReady() {
return keyboardReady;
}
public boolean isMouseReady() {
return mouseReady;
}
public boolean isConsumerReady() {
return consumerReady;
}
}

View File

@ -0,0 +1,180 @@
package com.inputstick.api;
import java.lang.ref.WeakReference;
import android.app.Application;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
public class IPCConnectionManager extends ConnectionManager {
//private static final String mTag = "IPCConnectionManager";
public static final int SERVICE_CMD_CONNECT = 1;
public static final int SERVICE_CMD_DISCONNECT = 2;
public static final int SERVICE_CMD_DATA = 3;
public static final int SERVICE_CMD_STATE = 4;
Context mCtx;
Messenger mService = null;
boolean mBound;
boolean initSent;
final Messenger mMessenger = new Messenger(new IncomingHandler(this));
private static class IncomingHandler extends Handler {
private final WeakReference<IPCConnectionManager> ref;
IncomingHandler(IPCConnectionManager manager) {
ref = new WeakReference<IPCConnectionManager>(manager);
}
@Override
public void handleMessage(Message msg) {
IPCConnectionManager manager = ref.get();
switch (msg.what) {
case SERVICE_CMD_DATA:
byte[] data = null;
Bundle b = msg.getData();
if (b != null) {
data = b.getByteArray("data");
manager.onData(data);
}
break;
case SERVICE_CMD_STATE:
//System.out.println("CMD STATE: "+msg.arg1);
manager.stateNotify(msg.arg1);
break;
}
}
}
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);
}
public void onServiceDisconnected(ComponentName className) {
// unexpectedly disconnected from service
//System.out.println("onService DISCONNECTED!");
mService = null;
mBound = false;
stateNotify(STATE_DISCONNECTED);
}
};
//SERVICE=========================================================
private void sendMessage(int what, int arg1, int arg2, Bundle b) {
Message msg;
try {
msg = Message.obtain(null, what, arg1, 0, null);
msg.replyTo = mMessenger;
msg.setData(b);
mService.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
private void sendMessage(int what, int arg1, int arg2, byte[] data) {
Bundle b;
b = new Bundle();
b.putByteArray("data", data);
sendMessage(what, arg1, arg2, b);
}
private void sendMessage(int what, int arg1, int arg2) {
sendMessage(what, arg1, arg2, (Bundle)null);
}
private void onData(byte[] data) {
for (InputStickDataListener listener : mDataListeners) {
listener.onInputStickData(data);
}
}
public IPCConnectionManager(Application app) {
mCtx = app.getApplicationContext();
}
@Override
public void connect() {
PackageManager pm = mCtx.getPackageManager();
boolean exists = true;
try {
pm.getPackageInfo("com.inputstick.apps.inputstickutility", PackageManager.GET_META_DATA);
} catch (NameNotFoundException e) {
exists = false;
}
if (exists) {
mErrorCode = ConnectionManager.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");
sendMessage(SERVICE_CMD_CONNECT, 0, 0);
}
} else {
mErrorCode = 1; //TODO
stateNotify(STATE_FAILURE);
}
}
@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
} else {
//just set state, there is nothing else to do
stateNotify(STATE_DISCONNECTED);
}
}
@Override
public void sendPacket(Packet p) {
if (mState == ConnectionManager.STATE_READY) {
if (p.getRespond()) {
sendMessage(IPCConnectionManager.SERVICE_CMD_DATA, 1, 0, p.getBytes());
} else {
sendMessage(IPCConnectionManager.SERVICE_CMD_DATA, 0, 0, p.getBytes());
}
}
}
}

View File

@ -0,0 +1,7 @@
package com.inputstick.api;
public interface InputStickDataListener {
public void onInputStickData(byte[] data);
}

View File

@ -0,0 +1,7 @@
package com.inputstick.api;
public interface InputStickKeyboardListener {
public void onLEDsChanged(boolean numLock, boolean capsLock, boolean scrollLock);
}

View File

@ -0,0 +1,7 @@
package com.inputstick.api;
public interface InputStickStateListener {
public void onStateChanged(int state);
}

View File

@ -0,0 +1,122 @@
package com.inputstick.api;
public class Packet {
public static final byte NONE = 0x00;
public static final byte START_TAG = 0x55;
public static final byte FLAG_RESPOND = (byte)0x80;
public static final byte FLAG_ENCRYPTED = 0x40;
public static final int MAX_SUBPACKETS = 17;
public static final int MAX_LENGTH = MAX_SUBPACKETS * 16;
public static final byte CMD_IDENTIFY = 0x01;
public static final byte CMD_LED = 0x02;
public static final byte CMD_RUN_BL = 0x03;
public static final byte CMD_RUN_FW = 0x04;
public static final byte CMD_GET_INFO = 0x05;
public static final byte CMD_BL_ERASE = 0x06;
public static final byte CMD_ADD_DATA = 0x07;
public static final byte CMD_BL_WRITE = 0x08;
public static final byte CMD_FW_INFO = 0x10;
public static final byte CMD_INIT = 0x11;
public static final byte CMD_HID_STATUS_REPORT = 0x20;
public static final byte CMD_HID_DATA_KEYB = 0x21;
public static final byte CMD_HID_DATA_CONSUMER = 0x22;
public static final byte CMD_HID_DATA_MOUSE = 0x23;
//out
public static final byte CMD_HID_STATUS = 0x2F;
public static final byte CMD_DUMMY = (byte)0xFF;
public static final byte RESP_OK = 0x01;
public static final byte[] RAW_OLD_BOOTLOADER = new byte[] {START_TAG, (byte)0x00, (byte)0x02, (byte)0x83, (byte)0x00, (byte)0xDA};
public static final byte[] RAW_DELAY_1_MS = new byte[] {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01};
private byte[] mData;
private int mPos;
private boolean mRespond;
//do not modify
public Packet(boolean respond, byte[] data) {
mRespond = respond;
mData = data;
mPos = data.length;
}
public Packet(boolean respond, byte cmd, byte param, byte[] data) {
mRespond = respond;
mData = new byte[MAX_LENGTH];
mData[0] = cmd;
mData[1] = param;
mPos = 2;
if (data != null) {
addBytes(data);
}
}
public Packet(boolean respond, byte cmd, byte param) {
this(respond, cmd, param, null);
}
public Packet(boolean respond, byte cmd) {
mRespond = respond;
mData = new byte[MAX_LENGTH];
mData[0] = cmd;
mPos = 1;
}
public void modifyByte(int pos, byte b) {
mData[pos] = b;
}
public void addBytes(byte[] data) {
//TODO check null pointer / available size (MAX_PAYLOAD - mPos)
System.arraycopy(data, 0, mData, mPos, data.length);
mPos += data.length;
}
public void addByte(byte b) {
mData[mPos++] = b;
}
public void addInt16(int val) {
mData[mPos + 0] = Util.getMSB(val);
mData[mPos + 1] = Util.getLSB(val);
mPos += 2;
}
public void addInt32(long val) {
mData[mPos + 3] = (byte)val;
val >>= 8;
mData[mPos + 2] = (byte)val;
val >>= 8;
mData[mPos + 1] = (byte)val;
val >>= 8;
mData[mPos + 0] = (byte)val;
val >>= 8;
mPos += 4;
}
public byte[] getBytes() {
byte[] result;
result = new byte[mPos];
System.arraycopy(mData, 0, result, 0, mPos);
return result;
}
public boolean getRespond() {
return mRespond;
}
}

View File

@ -0,0 +1,169 @@
package com.inputstick.api;
import java.util.Arrays;
import java.util.Random;
import java.util.zip.CRC32;
import com.inputstick.api.bluetooth.BTService;
public class PacketManager {
public static final int MAX_PAYLAOD = 64;
public static final int HEADER_OFFSET = 2;
public static final int CRC_OFFSET = 4;
public static final int PACKET_SIZE = 16;
private final BTService mBTService;
private final AES mAes;
private final byte[] mKey;
private byte[] cmpData;
private final CRC32 mCrc;
private boolean mEncryption;
public PacketManager(BTService btService, byte[] key) {
mBTService = btService;
mCrc = new CRC32();
mAes = new AES();
mKey = key;
mEncryption = false;
}
public boolean setEncryption(byte[] cmp, boolean encryptOut) {
byte[] cmpDec = mAes.decrypt(cmp);
if (Arrays.equals(cmpDec, cmpData)) {
mEncryption = encryptOut;
return true;
} else {
mEncryption = false;
return false;
}
}
public Packet encPacket(boolean enable) {
Random r = new Random();
Packet p = new Packet(true, Packet.CMD_INIT);
if (enable) {
p.addByte((byte)1);
} else {
p.addByte((byte)0);
}
byte[] iv = mAes.init(mKey);
p.addBytes(iv);
Util.printHex(iv, "IV: ");
byte[] initData = new byte[16];
r.nextBytes(initData);
mCrc.reset();
mCrc.update(initData, 4, 12); //only 12 bytes!
long crcValue = mCrc.getValue();
initData[3] = (byte)crcValue;
crcValue >>= 8;
initData[2] = (byte)crcValue;
crcValue >>= 8;
initData[1] = (byte)crcValue;
crcValue >>= 8;
initData[0] = (byte)crcValue;
initData = mAes.encrypt(initData);
p.addBytes(initData);
//Util.printHex(initData, "InitData: ");
cmpData = new byte[16];
r.nextBytes(cmpData);
p.addBytes(cmpData);
//Util.printHex(cmpData, "CmpData: ");
return p;
}
public byte[] bytesToPacket(byte[] data) {
byte[] payload;
//boolean decrypt = false;
long crcValue, crcCompare;
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.printHex(payload, "DATA IN: ");
//check CRC
crcCompare = Util.getLong(payload[0], payload[1], payload[2], payload[3]);
mCrc.reset();
mCrc.update(payload, CRC_OFFSET, payload.length - CRC_OFFSET);
crcValue = mCrc.getValue();
//System.out.println("CMP: " + crcCompare + " VAL: " + crcValue);
if (crcValue == crcCompare) {
payload = Arrays.copyOfRange(payload, 4, payload.length); //remove CRC
return payload;
} else {
return null; //TODO
}
}
public void sendRAW(byte[] data) {
mBTService.write(data);
}
public void sendPacket(Packet p) {
sendPacket(p, mEncryption);
}
public void sendPacket(Packet p, boolean encrypt) {
byte[] result, header, data;
int length;
int packets;
long crcValue;
//if data > MAX_PAYLAOD -> error
data = p.getBytes();
length = data.length + CRC_OFFSET; //include 4bytes for CRC32
packets = ((length - 1) >> 4) + 1; //how many 16 bytes data sub-packets are necessary
result = new byte[packets * PACKET_SIZE];
System.arraycopy(data, 0, result, CRC_OFFSET, data.length);
//add CRC32
mCrc.reset();
mCrc.update(result, CRC_OFFSET, result.length - CRC_OFFSET);
crcValue = mCrc.getValue();
Util.log("CRC: "+crcValue);
result[3] = (byte)crcValue;
crcValue >>= 8;
result[2] = (byte)crcValue;
crcValue >>= 8;
result[1] = (byte)crcValue;
crcValue >>= 8;
result[0] = (byte)crcValue;
//Util.printHex(result);
if (encrypt) {
result = mAes.encrypt(result);
//Util.printHex(result);
}
header = new byte[2];
header[0] = Packet.START_TAG;
header[1] = (byte)packets;
if (encrypt) {
header[1] |= Packet.FLAG_ENCRYPTED;
}
if (p.getRespond()) {
header[1] |= Packet.FLAG_RESPOND;
}
mBTService.write(header);
mBTService.write(result);
}
}

View File

@ -0,0 +1,83 @@
package com.inputstick.api;
public abstract class Util {
private static final boolean debug = false;
public static void log(String msg) {
if (debug) {
System.out.println("LOG: " + msg);
}
}
public static void printHex(byte[] toPrint, String info) {
if (debug) {
System.out.println(info);
printHex(toPrint);
}
}
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);
}
}
s = s.toUpperCase();
System.out.print("0x" + s + " ");
cnt++;
if (cnt == 8) {
System.out.println("");
cnt = 0;
}
}
System.out.println("\n#####");
}
}
public static byte getLSB(int n) {
return (byte)(n & 0x00FF);
}
public static byte getMSB(int n) {
return (byte)((n & 0xFF00) >> 8);
}
public static int getInt(byte b) {
int bInt = b & 0xFF;
return bInt;
}
public static int getInt(byte msb, byte lsb) {
int msbInt = msb & 0xFF;
int lsbInt = lsb & 0xFF;
return (msbInt << 8) + lsbInt;
}
public static long getLong(byte b0, byte b1, byte b2, byte b3) {
long result;
result = (b0) & 0xFF;
result <<= 8;
result += (b1) & 0xFF;
result <<= 8;
result += (b2) & 0xFF;
result <<= 8;
result += (b3) & 0xFF;
return result;
}
}

View File

@ -0,0 +1,40 @@
package com.inputstick.api.basic;
import com.inputstick.api.hid.ConsumerReport;
import com.inputstick.api.hid.HIDTransaction;
public class InputStickConsumer {
//CONSUMER PAGE
public static final int VOL_UP = 0x00E9;
public static final int VOL_DOWN = 0x00EA;
public static final int VOL_MUTE = 0x00E2;
public static final int TRACK_NEXT = 0x00B5;
public static final int TRACK_PREV = 0x00B6;
public static final int STOP = 0x00B7;
public static final int PLAY_PAUSE = 0x00CD;
public static final int LAUNCH_BROWSER = 0x0196;
public static final int LAUNCH_EMAIL = 0x018A;
public static final int LAUNCH_CALC = 0x0192;
//SYSTEM CONTROL
public static final int POWER_DOWN = 0x81;
public static final int SLEEP = 0x82;
public static final int WAKEUP = 0x83;
private InputStickConsumer() {
}
/*public static void systemAction(int action) {
}*/
public static void consumerAction(int action) {
HIDTransaction t = new HIDTransaction();
t.addReport(new ConsumerReport(action));
t.addReport(new ConsumerReport());
InputStickHID.addConsumerTransaction(t);
}
}

View File

@ -0,0 +1,152 @@
package com.inputstick.api.basic;
import java.util.Vector;
import android.app.Application;
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.InputStickStateListener;
import com.inputstick.api.Packet;
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";
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 HIDTransactionQueue keyboardQueue;
private static HIDTransactionQueue mouseQueue;
private static HIDTransactionQueue consumerQueue;
private InputStickHID() {
}
public static InputStickHID getInstance() {
return instance;
}
private static void init() {
keyboardQueue = new HIDTransactionQueue(HIDTransactionQueue.KEYBOARD, mConnectionManager);
mouseQueue = new HIDTransactionQueue(HIDTransactionQueue.MOUSE, mConnectionManager);
consumerQueue = new HIDTransactionQueue(HIDTransactionQueue.CONSUMER, mConnectionManager);
mConnectionManager.addStateListener(instance);
mConnectionManager.addDataListener(instance);
mConnectionManager.connect();
}
//direct Bluetooth connection, custom InitManager
public static void connect(Application app, String mac, byte[] key, InitManager initManager) {
mConnectionManager = new BTConnectionManager(initManager, app, mac, key);
init();
}
//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();
}
//use background service & DeviceManager
public static void connect(Application app) {
mConnectionManager = new IPCConnectionManager(app);
init();
}
public static void disconnect() {
//TODO check state?
mConnectionManager.disconnect();
}
public static int getState() {
if (mConnectionManager != null) {
return mConnectionManager.getState();
} else {
return ConnectionManager.STATE_DISCONNECTED;
}
}
public static boolean isReady() {
if (getState() == ConnectionManager.STATE_READY) {
return true;
} else {
return false;
}
}
public static void addStateListener(InputStickStateListener listener) {
if (listener != null) {
mStateListeners.add(listener);
}
}
public static void removeStateListener(InputStickStateListener listener) {
if (listener != null) {
mStateListeners.remove(listener);
}
}
public static void addKeyboardTransaction(HIDTransaction transaction) {
keyboardQueue.addTransaction(transaction);
}
public static void addMouseTransaction(HIDTransaction transaction) {
mouseQueue.addTransaction(transaction);
}
public static void addConsumerTransaction(HIDTransaction transaction) {
consumerQueue.addTransaction(transaction);
}
public static boolean sendPacket(Packet p) {
if (mConnectionManager != null) {
mConnectionManager.sendPacket(p);
return true;
} else {
return false;
}
}
@Override
public void onStateChanged(int state) {
for (InputStickStateListener listener : mStateListeners) {
listener.onStateChanged(state);
}
}
@Override
public void onInputStickData(byte[] data) {
if (data[0] == Packet.CMD_HID_STATUS) {
mHIDInfo.update(data);
if (mHIDInfo.isKeyboardReady()) {
keyboardQueue.deviceReady();
}
if (mHIDInfo.isMouseReady()) {
mouseQueue.deviceReady();
}
if (mHIDInfo.isConsumerReady()) {
consumerQueue.deviceReady();
}
InputStickKeyboard.setLEDs(mHIDInfo.getNumLock(), mHIDInfo.getCapsLock(), mHIDInfo.getScrollLock());
}
}
}

View File

@ -0,0 +1,118 @@
package com.inputstick.api.basic;
import java.util.Vector;
import com.inputstick.api.InputStickKeyboardListener;
import com.inputstick.api.hid.HIDKeycodes;
import com.inputstick.api.hid.HIDTransaction;
import com.inputstick.api.hid.KeyboardReport;
public class InputStickKeyboard {
//private static final String mTag = "InputStickKeyboard";
private static final byte NONE = (byte)0;
private static boolean mReportProtocol;
private static boolean mNumLock;
private static boolean mCapsLock;
private static boolean mScrollLock;
private static Vector<InputStickKeyboardListener> mKeyboardListeners = new Vector<InputStickKeyboardListener>();
private InputStickKeyboard() {
}
public static void addKeyboardListener(InputStickKeyboardListener listener) {
if (listener != null) {
mKeyboardListeners.add(listener);
}
}
public static void removeKeyboardListener(InputStickKeyboardListener listener) {
if (listener != null) {
mKeyboardListeners.remove(listener);
}
}
protected void setReportProtocol(boolean reportProtocol) {
mReportProtocol = reportProtocol;
}
public boolean isReportProtocol() {
return mReportProtocol;
}
protected static void setLEDs(boolean numLock, boolean capsLock, boolean scrollLock) {
mNumLock = numLock;
mCapsLock = capsLock;
mScrollLock = scrollLock;
for (InputStickKeyboardListener listener : mKeyboardListeners) {
listener.onLEDsChanged(mNumLock, mCapsLock, mScrollLock);
}
}
public static boolean isNumLock() {
return mNumLock;
}
public static boolean isCapsLock() {
return mCapsLock;
}
public static boolean isScrollLock() {
return mScrollLock;
}
public static void toggleNumLock() {
pressAndRelease(NONE, HIDKeycodes.KEY_NUM_LOCK);
}
public static void toggleCapsLock() {
pressAndRelease(NONE, HIDKeycodes.KEY_CAPS_LOCK);
}
public static void toggleScrollLock() {
pressAndRelease(NONE, HIDKeycodes.KEY_SCROLL_LOCK);
}
public static void pressAndRelease(byte modifier, byte key) {
HIDTransaction t = new HIDTransaction();
t.addReport(new KeyboardReport(modifier, NONE));
t.addReport(new KeyboardReport(modifier, key));
t.addReport(new KeyboardReport(NONE, NONE));
InputStickHID.addKeyboardTransaction(t);
}
public static void typeASCII(String toType) {
int keyCode;
int index;
for (int i = 0; i < toType.length(); i++) {
index = toType.charAt(i);
if (index > 127) {
index = 127;
}
keyCode = HIDKeycodes.getKeyCode(index);
if (keyCode > 128) {
keyCode -= 128;
pressAndRelease(HIDKeycodes.SHIFT_LEFT, (byte)keyCode);
} else {
pressAndRelease(NONE, (byte)keyCode);
}
}
}
public static void customReport(byte modifier, byte key0, byte key1, byte key2, byte key3, byte key4, byte key5) {
HIDTransaction t = new HIDTransaction();
t.addReport(new KeyboardReport(modifier, key0, key1, key2, key3, key4, key5));
InputStickHID.addKeyboardTransaction(t);
}
/*public static void customReport(byte[] report) {
HIDTransaction t = new HIDTransaction();
t.addReport(report);
InputStickHID.addKeyboardTransaction(t);
}*/
}

View File

@ -0,0 +1,57 @@
package com.inputstick.api.basic;
import com.inputstick.api.hid.HIDTransaction;
import com.inputstick.api.hid.MouseReport;
public class InputStickMouse {
private static final byte NONE = 0x00;
public static final byte BUTTON_NONE = 0x00;
public static final byte BUTTON_LEFT = 0x01;
public static final byte BUTTON_RIGHT = 0x02;
public static final byte BUTTON_MIDDLE = 0x04;
private static boolean mReportProtocol;
private InputStickMouse() {
}
protected void setReportProtocol(boolean reportProtocol) {
mReportProtocol = reportProtocol;
}
public boolean isReportProtocol() {
return mReportProtocol;
}
public static void click(byte button, int n) {
HIDTransaction t = new HIDTransaction();
t.addReport(new MouseReport()); //release
for (int i = 0; i < n; i++) {
t.addReport(new MouseReport(button, NONE, NONE, NONE)); //press
t.addReport(new MouseReport()); //release
}
InputStickHID.addMouseTransaction(t);
}
public static void move(byte x, byte y) {
HIDTransaction t = new HIDTransaction();
t.addReport(new MouseReport(NONE, x, y, NONE));
InputStickHID.addMouseTransaction(t);
}
public static void scroll(byte wheel) {
HIDTransaction t = new HIDTransaction();
t.addReport(new MouseReport(NONE, NONE, NONE, wheel));
InputStickHID.addMouseTransaction(t);
}
public static void customReport(byte buttons, byte x, byte y, byte wheel) {
HIDTransaction t = new HIDTransaction();
t.addReport(new MouseReport(buttons, x, y, wheel));
InputStickHID.addMouseTransaction(t);
}
}

View File

@ -0,0 +1,404 @@
package com.inputstick.api.bluetooth;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.util.UUID;
import android.app.Application;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
import android.os.Message;
import com.inputstick.api.Packet;
import com.inputstick.api.Util;
public class BTService {
public static final int DEFAULT_CONNECT_TIMEOUT = 30000;
public static final int EVENT_NONE = 0;
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;
private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); //SPP
//private final String dTag = "BTService";
private final BluetoothAdapter mAdapter;
private final Handler mHandler;
private ConnectThread mConnectThread;
private ConnectedThread mConnectedThread;
private int mLastEvent;
private String mMac;
private boolean mReflection;
private final Application mApp;
private final Context mCtx;
private boolean mUseReflection;
private int mConnectTimeout;
private boolean turnBluetoothOn;
private boolean receiverRegistered;
private long timeout;
private int retryCnt;
private boolean disconnecting;
private boolean connected;
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@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)) {
turnBluetoothOn = false;
doConnect(false);
}
}
}
};
public BTService(Application app, Handler handler) {
mAdapter = BluetoothAdapter.getDefaultAdapter();
mLastEvent = EVENT_NONE;
mHandler = handler;
mApp = app;
mCtx = app.getApplicationContext();
mConnectTimeout = DEFAULT_CONNECT_TIMEOUT; //30s - default value
}
public void setConnectTimeout(int timeout) {
mConnectTimeout = timeout;
}
public void enableReflection(boolean enabled) {
mUseReflection = enabled;
}
private synchronized void event(int event) {
Util.log("event() " + mLastEvent + " -> " + event);
mLastEvent = event;
Message msg = Message.obtain(null, mLastEvent, 0, 0);
mHandler.sendMessage(msg);
}
public synchronized int getLastEvent() {
return mLastEvent;
}
private void enableBluetooth() {
if (mApp != null) {
turnBluetoothOn = true;
if ( !receiverRegistered) {
IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
mCtx.registerReceiver(mReceiver, filter);
receiverRegistered = true;
}
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
enableBtIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mApp.startActivity(enableBtIntent);
}
}
private void doConnect(boolean reconnecting) {
if (reconnecting) {
retryCnt++;
} else {
retryCnt = 0;
timeout = System.currentTimeMillis() + mConnectTimeout;
}
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
mConnectThread = new ConnectThread(mAdapter.getRemoteDevice(mMac), mReflection);
mConnectThread.start();
}
public synchronized void connect(String mac) {
Util.log("connect to: " + mac + " REFLECTION: " + mUseReflection);
disconnecting = false;
connected = false;
mMac = mac;
if (BluetoothAdapter.checkBluetoothAddress(mac)) {
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null) {
event(EVENT_NO_BT_HW);
} else {
if (mBluetoothAdapter.isEnabled()) {
doConnect(false);
} else {
enableBluetooth();
}
}
} else {
event(EVENT_INVALID_MAC);
}
}
public synchronized void disconnect() {
Util.log("disconnect");
disconnecting = true;
cancelThreads();
event(EVENT_CANCELLED);
}
public synchronized void write(byte[] out) {
// Create temporary object
/*
ConnectedThread r;
// Synchronize a copy of the ConnectedThread
synchronized (this) {
r = mConnectedThread;
}
// Perform the write unsynchronized
if (connected) {
r.write(out);
}*/
if (connected) {
mConnectedThread.write(out);
}
}
private synchronized void cancelThreads() {
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
}
private synchronized void connected(BluetoothSocket socket, BluetoothDevice device) {
timeout = 0;
cancelThreads();
if (receiverRegistered) {
mCtx.unregisterReceiver(mReceiver);
receiverRegistered = false;
}
// Start the thread to manage the connection and perform transmissions
mConnectedThread = new ConnectedThread(socket);
mConnectedThread.start();
connected = true;
event(EVENT_CONNECTED);
}
private void connectionFailed() {
connected = false;
if (disconnecting) {
disconnecting = false;
} else {
if ((timeout > 0) && (System.currentTimeMillis() < timeout)) {
Util.log("RETRY: "+retryCnt + " time left: " + (timeout - System.currentTimeMillis()));
doConnect(true);
} else {
event(EVENT_CONNECTION_FAILED);
}
}
}
private void connectionLost() {
connected = false;
if (disconnecting) {
disconnecting = false;
} else {
event(EVENT_CONNECTION_LOST);
}
}
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device, boolean useReflection) {
mmDevice = device;
BluetoothSocket tmp = null;
try {
if (useReflection) {
Method m = device.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
tmp = (BluetoothSocket) m.invoke(device, 1);
} else {
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
}
} catch (IOException e) {
Util.log("Socket create() failed");
} catch (Exception e) {
Util.log("Socket create() REFLECTION failed");
e.printStackTrace();
}
mmSocket = tmp;
}
public void run() {
Util.log("BEGIN mConnectThread");
mAdapter.cancelDiscovery(); //else it will slow down connection
try {
mmSocket.connect();
} catch (IOException e) {
try {
mmSocket.close();
} catch (IOException e2) {
Util.log("unable to close() socket during connection failure");
}
connectionFailed();
return;
}
// Reset the ConnectThread
synchronized (BTService.this) {
mConnectThread = null;
}
connected(mmSocket, mmDevice);
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Util.log("close() of connect socket failed");
}
}
}
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
Util.log("create ConnectedThread");
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Util.log("temp sockets not created");
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
Util.log("BEGIN mConnectedThread");
byte[] buffer = null;
int rxTmp;
int lengthByte;
int length;
while (true) {
try {
rxTmp = mmInStream.read();
if (rxTmp == Packet.START_TAG) {
lengthByte = mmInStream.read();
length = lengthByte;
length &= 0x3F;
length *= 16;
buffer = new byte[length + 2];
buffer[0] = Packet.START_TAG;
buffer[1] = (byte)lengthByte;
for (int i = 2; i < length + 2; i++) {
buffer[i] = (byte)mmInStream.read();
}
mHandler.obtainMessage(EVENT_DATA, 0, 0, buffer).sendToTarget();
} else {
System.out.println("RX: " + rxTmp);
//possible WDG reset
}
} catch (IOException e) {
connectionLost();
break;
}
}
}
public void write(byte[] buffer) {
try {
mmOutStream.write(buffer);
mmOutStream.flush();
} catch (IOException e) {
Util.log("Exception during write");
}
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Util.log("close() of connect socket failed");
}
}
}
}

View File

@ -0,0 +1,30 @@
package com.inputstick.api.hid;
import com.inputstick.api.Util;
public class ConsumerReport extends HIDReport {
public static final int SIZE = 3;
private byte[] data;
public ConsumerReport(int usage) {
data = new byte[SIZE];
data[0] = 1;
data[1] = Util.getLSB(usage);
data[2] = Util.getMSB(usage);
}
public ConsumerReport() {
this(0);
}
public byte[] getBytes() {
return data;
}
public int getBytesCount() {
return SIZE;
}
}

View File

@ -0,0 +1,272 @@
package com.inputstick.api.hid;
public class HIDKeycodes {
public static final byte NONE = 0x00;
public static final byte CTRL_LEFT = 0x01;
public static final byte SHIFT_LEFT = 0x02;
public static final byte ALT_LEFT = 0x04;
public static final byte GUI_LEFT = 0x08;
public static final byte CTRL_RIGHT = 0x10;
public static final byte SHIFT_RIGHT = 0x20;
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;
public static final byte KEY_TAB = 0x2B;
public static final byte KEY_SPACEBAR = 0x2C;
public static final byte KEY_CAPS_LOCK = 0x39;
public static final byte KEY_1 = 0x1E;
public static final byte KEY_2 = 0x1F;
public static final byte KEY_3 = 0x20;
public static final byte KEY_4 = 0x21;
public static final byte KEY_5 = 0x22;
public static final byte KEY_6 = 0x23;
public static final byte KEY_7 = 0x24;
public static final byte KEY_8 = 0x25;
public static final byte KEY_9 = 0x26;
public static final byte KEY_0 = 0x27;
public static final byte KEY_F1 = 0x3A;
public static final byte KEY_F2 = 0x3B;
public static final byte KEY_F3 = 0x3C;
public static final byte KEY_F4 = 0x3D;
public static final byte KEY_F5 = 0x3E;
public static final byte KEY_F6 = 0x3F;
public static final byte KEY_F7 = 0x40;
public static final byte KEY_F8 = 0x41;
public static final byte KEY_F9 = 0x42;
public static final byte KEY_F10 = 0x43;
public static final byte KEY_F11 = 0x44;
public static final byte KEY_F12 = 0x45;
public static final byte KEY_PRINT_SCREEN = 0x46;
public static final byte KEY_SCROLL_LOCK = 0x47;
public static final byte KEY_PASUE = 0x48;
public static final byte KEY_INSERT = 0x49;
public static final byte KEY_HOME = 0x4A;
public static final byte KEY_PAGE_UP = 0x4B;
public static final byte KEY_DELETE = 0x4C;
public static final byte KEY_END = 0x4D;
public static final byte KEY_PAGE_DOWN = 0x4E;
public static final byte KEY_ARROW_RIGHT = 0x4F;
public static final byte KEY_ARROW_LEFT = 0x50;
public static final byte KEY_ARROW_DOWN = 0x51;
public static final byte KEY_ARROW_UP = 0x52;
public static final byte KEY_NUM_LOCK = 0x53;
public static final byte KEY_NUM_BACKSLASH = 0x54;
public static final byte KEY_NUM_STAR = 0x55;
public static final byte KEY_NUM_MINUS = 0x56;
public static final byte KEY_NUM_PLUS = 0x57;
public static final byte KEY_NUM_ENTER = 0x58;
public static final byte KEY_NUM_1 = 0x59;
public static final byte KEY_NUM_2 = 0x5A;
public static final byte KEY_NUM_3 = 0x5B;
public static final byte KEY_NUM_4 = 0x5C;
public static final byte KEY_NUM_5 = 0x5D;
public static final byte KEY_NUM_6 = 0x5E;
public static final byte KEY_NUM_7 = 0x5F;
public static final byte KEY_NUM_8 = 0x60;
public static final byte KEY_NUM_9 = 0x61;
public static final byte KEY_NUM_0 = 0x62;
public static final byte KEY_NUM_DOT = 0x63;
public static final byte KEY_A = 0x04;
public static final byte KEY_B = 0x05;
public static final byte KEY_C = 0x06;
public static final byte KEY_D = 0x07;
public static final byte KEY_E = 0x08;
public static final byte KEY_F = 0x09;
public static final byte KEY_G = 0x0A;
public static final byte KEY_H = 0x0B;
public static final byte KEY_I = 0x0C;
public static final byte KEY_J = 0x0D;
public static final byte KEY_K = 0x0E;
public static final byte KEY_L = 0x0F;
public static final byte KEY_M = 0x10;
public static final byte KEY_N = 0x11;
public static final byte KEY_O = 0x12;
public static final byte KEY_P = 0x13;
public static final byte KEY_Q = 0x14;
public static final byte KEY_R = 0x15;
public static final byte KEY_S = 0x16;
public static final byte KEY_T = 0x17;
public static final byte KEY_U = 0x18;
public static final byte KEY_V = 0x19;
public static final byte KEY_W = 0x1A;
public static final byte KEY_X = 0x1B;
public static final byte KEY_Y = 0x1C;
public static final byte KEY_Z = 0x1D;
public static final byte KEY_MINUS = 0x2D;
public static final byte KEY_EQUALS = 0x2E;
public static final byte KEY_LEFT_BRACKET = 0x2F;
public static final byte KEY_RIGHT_BRACKET = 0x30;
public static final byte KEY_BACKSLASH = 0x31;
//public static final byte KEY_GRAVE = 0x32;
public static final byte KEY_SEMICOLON = 0x33;
public static final byte KEY_APOSTROPHE = 0x34;
public static final byte KEY_GRAVE = 0x35;
public static final byte KEY_COMA = 0x36;
public static final byte KEY_DOT = 0x37;
public static final byte KEY_SLASH = 0x38;
public static final byte KEY_APPLICATION = 0x65;
public static final int[] ASCIItoHID = {
0, //000
0, //001
0, //002
0, //003
0, //004
0, //005
0, //006
0, //007
0, //008
0, //009
0, //010
0, //011
0, //012
0, //013
0, //014
0, //015
0, //016
0, //017
0, //018
0, //019
0, //020
0, //021
0, //022
0, //023
0, //024
0, //025
0, //026
0, //027
0, //028
0, //029
0, //030
0, //031
44, //032 space
128 + 30, //033 ! [SHIFT]
128 + 52, //034 " [SHIFT]
128 + 32, //035 # [SHIFT]
128 + 33, //036 $ [SHIFT]
128 + 34, //037 % [SHIFT]
128 + 36, //038 & [SHIFT]
52, //039 '
128 + 38, //040 ( [SHIFT]
128 + 39, //041 ) [SHIFT]
128 + 37, //042 * [SHIFT]
128 + 46, //043 + [SHIFT]
54, //044 ,
45, //045 - (-)
55, //046 . (.)
56, //047 /
39, //048 0
30, //049 1
31, //050 2
32, //051 3
33, //052 4
34, //053 5
35, //054 6
36, //055 7
37, //056 8
38, //057 9
128 + 51, //058 : [SHIFT]
51, //059 ;
128 + 54, //060 < [SHIFT]
46, //061 =
128 + 55, //062 > [SHIFT]
128 + 56, //063 ? [SHIFT]
128 + 31, //064 @ [SHIFT]
128 + 4, //065 A [SHIFT]
128 + 5, //066 B [SHIFT]
128 + 6, //067 C [SHIFT]
128 + 7, //068 D [SHIFT]
128 + 8, //069 E [SHIFT]
128 + 9, //070 F [SHIFT]
128 + 10, //071 G [SHIFT]
128 + 11, //072 H [SHIFT]
128 + 12, //073 I [SHIFT]
128 + 13, //074 J [SHIFT]
128 + 14, //075 K [SHIFT]
128 + 15, //076 L [SHIFT]
128 + 16, //077 M [SHIFT]
128 + 17, //078 N [SHIFT]
128 + 18, //079 O [SHIFT]
128 + 19, //080 P [SHIFT]
128 + 20, //081 Q [SHIFT]
128 + 21, //082 R [SHIFT]
128 + 22, //083 S [SHIFT]
128 + 23, //084 T [SHIFT]
128 + 24, //085 U [SHIFT]
128 + 25, //086 V [SHIFT]
128 + 26, //087 W [SHIFT]
128 + 27, //088 X [SHIFT]
128 + 28, //089 Y [SHIFT]
128 + 29, //090 Z [SHIFT]
47, //091 [
49, /*092 \ */
48, //093 ]
128 + 35, //094 ^ [SHIFT]
128 + 45, //095 _ [SHIFT] (underscore)
128 + 53, //096 ` [SHIFT] (grave accent)
4, //097 a
5, //098 b
6, //099 c
7, //100 d
8, //101 e
9, //102 f
10, //103 g
11, //104 h
12, //105 i
13, //106 j
14, //107 k
15, //108 l
16, //109 m
17, //110 n
18, //111 o
19, //112 p
20, //113 q
21, //114 r
22, //115 s
23, //116 t
24, //117 u
25, //118 v
26, //119 w
27, //120 x
28, //121 y
29, //122 z
128 + 47, //123 { [SHIFT]
128 + 49, //124 | [SHIFT]
128 + 48, //125 } [SHIFT]
128 + 53, //126 ~ [SHIFT]
0 //127 just in case...
};
public static byte getKeyCode(char c) {
return (byte)ASCIItoHID[c]; //TODO range
}
public static int getKeyCode(int c) {
return ASCIItoHID[c]; //TODO range
}
}

View File

@ -0,0 +1,8 @@
package com.inputstick.api.hid;
public abstract class HIDReport {
public abstract byte[] getBytes();
public abstract int getBytesCount();
}

View File

@ -0,0 +1,56 @@
package com.inputstick.api.hid;
import java.util.Vector;
public class HIDTransaction {
private int mID;
private Vector<HIDReport> reports;
public HIDTransaction() {
reports = new Vector<HIDReport>();
}
public void addReport(HIDReport report) {
reports.add(report);
}
public int getReportsCount() {
return reports.size();
}
public void setID(int id) {
mID = id;
}
public int getID() {
return mID;
}
public boolean hasNext() {
return !reports.isEmpty();
}
public byte[] getNextReport() {
byte[] report;
report = reports.elementAt(0).getBytes();
reports.removeElementAt(0);
return report;
}
public HIDTransaction split(int n) {
HIDTransaction result = new HIDTransaction();
HIDReport report;
if (n <= reports.size()) {
while(n > 0) {
report = reports.firstElement();
reports.remove(0);
result.addReport(report);
n--;
}
}
return result;
}
}

View File

@ -0,0 +1,111 @@
package com.inputstick.api.hid;
import java.util.Vector;
import com.inputstick.api.ConnectionManager;
import com.inputstick.api.Packet;
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 final Vector<HIDTransaction> queue;
private final ConnectionManager mConnectionManager;
private final byte cmd;
private boolean ready;
private long lastTime;
private int lastReports;
public HIDTransactionQueue(int type, ConnectionManager connectionManager) {
queue = new Vector<HIDTransaction>();
mConnectionManager = connectionManager;
ready = false;
switch (type) {
case KEYBOARD:
cmd = Packet.CMD_HID_DATA_KEYB;
break;
case MOUSE:
cmd = Packet.CMD_HID_DATA_MOUSE;
break;
case CONSUMER:
cmd = Packet.CMD_HID_DATA_CONSUMER;
break;
default:
cmd = Packet.CMD_DUMMY;
}
}
private void sendNext() {
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
transaction = transaction.split(BUFFER_SIZE);
} else {
queue.removeElementAt(0);
}
while (transaction.hasNext()) {
p.addBytes(transaction.getNextReport());
reports++;
}
//TODO add next transactions if possible
while(true) {
if (queue.isEmpty()) {
break;
}
transaction = queue.firstElement();
if (reports + transaction.getReportsCount() < BUFFER_SIZE) {
queue.removeElementAt(0);
while (transaction.hasNext()) {
p.addBytes(transaction.getNextReport());
reports++;
}
} else {
break;
}
}
p.modifyByte(1, reports); //set reports count
mConnectionManager.sendPacket(p);
lastReports = reports;
lastTime = System.currentTimeMillis();
}
public void addTransaction(HIDTransaction transaction) {
if (queue.isEmpty()) {
if (System.currentTimeMillis() > lastTime + (lastReports * 8 * 2/*just to be safe*/)) {
ready = true;
}
}
queue.add(transaction);
if (ready) {
sendNext();
}
}
public void deviceReady() {
if (!queue.isEmpty()) {
sendNext();
} else {
ready = true;
}
}
}

View File

@ -0,0 +1,36 @@
package com.inputstick.api.hid;
public class KeyboardReport extends HIDReport {
public static final int SIZE = 8;
private byte[] data;
public KeyboardReport(byte modifier, byte key0, byte key1, byte key2, byte key3, byte key4, byte key5) {
data = new byte[SIZE];
data[0] = modifier;
data[2] = key0;
data[3] = key1;
data[4] = key2;
data[5] = key3;
data[6] = key4;
data[7] = key5;
}
public KeyboardReport() {
this((byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0);
}
public KeyboardReport(byte modifier, byte key) {
this(modifier, key, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0);
}
public byte[] getBytes() {
return data;
}
public int getBytesCount() {
return SIZE;
}
}

View File

@ -0,0 +1,29 @@
package com.inputstick.api.hid;
public class MouseReport extends HIDReport {
public static final int SIZE = 4;
private byte[] data;
public MouseReport(byte buttons, byte x, byte y, byte wheel) {
data = new byte[SIZE];
data[0] = buttons;
data[1] = x;
data[2] = y;
data[3] = wheel;
}
public MouseReport() {
this((byte)0, (byte)0, (byte)0, (byte)0);
}
public byte[] getBytes() {
return data;
}
public int getBytesCount() {
return SIZE;
}
}

View File

@ -0,0 +1,142 @@
package com.inputstick.api.layout;
public class GermanLayout extends KeyboardLayout {
public static final String LOCALE_NAME = "de-DE";
public static final int LUT[][] = {
/* 0 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 1 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 2 */ { 0 , (int)'1' , 0x21 , -1 , -1 , -1 } ,
/* 3 */ { 0 , (int)'2' , 0x22 , -1 , 0x00b2 , 0x00b2 } ,
/* 4 */ { 0 , (int)'3' , 0x00a7 , -1 , 0x00b3 , 0x00b3 } ,
/* 5 */ { 0 , (int)'4' , 0x24 , -1 , -1 , -1 } ,
/* 6 */ { 0 , (int)'5' , 0x25 , -1 , -1 , -1 } ,
/* 7 */ { 0 , (int)'6' , 0x26 , -1 , -1 , -1 } ,
/* 8 */ { 0 , (int)'7' , 0x002f , -1 , 0x007b , 0x007b } ,
/* 9 */ { 0 , (int)'8' , 0x28 , -1 , 0x005b , 0x005b } ,
/* 0a */ { 0 , (int)'9' , 0x29 , -1 , 0x005d , 0x005d } ,
/* 0b */ { 0 , (int)'0' , 0x003d , -1 , 0x007d , 0x007d } ,
/* 0c */ { 0 , 0x00df , 0x003f , -1 , 0x005c , 0x005c } ,
/* 0d */ { 0 , 0x00b4 , 0x0060 , -1 , -1 , -1 } ,
/* 0e */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 0f */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 10 */ { 1 , (int)'q' , (int)'Q' , -1 , 0x40 , 0x40 } ,
/* 11 */ { 1 , (int)'w' , (int)'W' , -1 , -1 , -1 } ,
/* 12 */ { 1 , (int)'e' , (int)'E' , -1 , 0x20ac , -1 } ,
/* 13 */ { 1 , (int)'r' , (int)'R' , -1 , -1 , -1 } ,
/* 14 */ { 1 , (int)'t' , (int)'T' , -1 , -1 , -1 } ,
/* 15 */ { 1 , (int)'z' , (int)'Z' , -1 , -1 , -1 } ,
/* 16 */ { 1 , (int)'u' , (int)'U' , -1 , -1 , -1 } ,
/* 17 */ { 1 , (int)'i' , (int)'I' , -1 , -1 , -1 } ,
/* 18 */ { 1 , (int)'o' , (int)'O' , -1 , -1 , -1 } ,
/* 19 */ { 1 , (int)'p' , (int)'P' , -1 , -1 , -1 } ,
/* 1a */ { 1 , 0x00fc , 0x00dc , 0x001b , -1 , -1 } ,
/* 1b */ { 0 , 0x002b , 0x002a , 0x001d , 0x007e , 0x007e } ,
/* 1c */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 1d */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 1e */ { 1 , (int)'a' , (int)'A' , -1 , -1 , -1 } ,
/* 1f */ { 1 , (int)'s' , (int)'S' , -1 , -1 , -1 } ,
/* 20 */ { 1 , (int)'d' , (int)'D' , -1 , -1 , -1 } ,
/* 21 */ { 1 , (int)'f' , (int)'F' , -1 , -1 , -1 } ,
/* 22 */ { 1 , (int)'g' , (int)'G' , -1 , -1 , -1 } ,
/* 23 */ { 1 , (int)'h' , (int)'H' , -1 , -1 , -1 } ,
/* 24 */ { 1 , (int)'j' , (int)'J' , -1 , -1 , -1 } ,
/* 25 */ { 1 , (int)'k' , (int)'K' , -1 , -1 , -1 } ,
/* 26 */ { 1 , (int)'l' , (int)'L' , -1 , -1 , -1 } ,
/* 27 */ { 1 , 0x00f6 , 0x00d6 , -1 , -1 , -1 } ,
/* 28 */ { 1 , 0x00e4 , 0x00c4 , -1 , -1 , -1 } ,
/* 29 */ { 0 , 0x005e , 0x00b0 , -1 , -1 , -1 } ,
/* 2a */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 2b */ { 0 , 0x23 , 0x27 , 0x001c , -1 , -1 } ,
/* 2c */ { 1 , (int)'y' , (int)'Y' , -1 , -1 , -1 } ,
/* 2d */ { 1 , (int)'x' , (int)'X' , -1 , -1 , -1 } ,
/* 2e */ { 1 , (int)'c' , (int)'C' , -1 , -1 , -1 } ,
/* 2f */ { 1 , (int)'v' , (int)'V' , -1 , -1 , -1 } ,
/* 30 */ { 1 , (int)'b' , (int)'B' , -1 , -1 , -1 } ,
/* 31 */ { 1 , (int)'n' , (int)'N' , -1 , -1 , -1 } ,
/* 32 */ { 1 , (int)'m' , (int)'M' , -1 , 0x00b5 , 0x00b5 } ,
/* 33 */ { 0 , 0x002c , 0x003b , -1 , -1 , -1 } ,
/* 34 */ { 0 , 0x002e , 0x003a , -1 , -1 , -1 } ,
/* 35 */ { 0 , 0x002d , 0x005f , -1 , -1 , -1 } ,
/* 36 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 37 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 38 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 39 */ { 0 , 0x20 , 0x20 , 0x20 , -1 , -1 } ,
/* 3a */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 3b */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 3c */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 3d */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 3e */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 3f */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 40 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 41 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 42 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 43 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 44 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 45 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 46 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 47 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 48 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 49 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 4a */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 4b */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 4c */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 4d */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 4e */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 4f */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 50 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 51 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 52 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 53 */ { 0 , 0x002c , 0x002c , -1 , -1 , -1 } ,
/* 54 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 55 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 56 */ { 0 , 0x003c , 0x003e , -1 , 0x007c , 0x007c } ,
/* 57 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 58 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 59 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 5a */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 5b */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 5c */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 5d */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 5e */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 5f */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
};
private static GermanLayout instance = new GermanLayout();
private GermanLayout() {
}
public static GermanLayout getInstance() {
return instance;
}
@Override
public int[][] getLUT() {
return LUT;
}
@Override
public void type(String text) {
super.type(LUT, text);
}
@Override
public char getChar(int scanCode, boolean capsLock, boolean shift, boolean altGr) {
return super.getChar(LUT, scanCode, capsLock, shift, altGr);
}
@Override
public String getLocaleName() {
return LOCALE_NAME;
}
}

View File

@ -0,0 +1,269 @@
package com.inputstick.api.layout;
import com.inputstick.api.ConnectionManager;
import com.inputstick.api.basic.InputStickHID;
import com.inputstick.api.hid.HIDKeycodes;
import com.inputstick.api.hid.HIDTransaction;
import com.inputstick.api.hid.KeyboardReport;
public abstract class KeyboardLayout {
public static final byte[] scanCodeToHID = {
/* 0x00 */ 0,
/* 0x01 */ HIDKeycodes.KEY_ESCAPE,
/* 0x02 */ HIDKeycodes.KEY_1,
/* 0x03 */ HIDKeycodes.KEY_2,
/* 0x04 */ HIDKeycodes.KEY_3,
/* 0x05 */ HIDKeycodes.KEY_4,
/* 0x06 */ HIDKeycodes.KEY_5,
/* 0x07 */ HIDKeycodes.KEY_6,
/* 0x08 */ HIDKeycodes.KEY_7,
/* 0x09 */ HIDKeycodes.KEY_8,
/* 0x0a */ HIDKeycodes.KEY_9,
/* 0x0b */ HIDKeycodes.KEY_0,
/* 0x0c */ HIDKeycodes.KEY_MINUS,
/* 0x0d */ HIDKeycodes.KEY_EQUALS,
/* 0x0e */ HIDKeycodes.KEY_BACKSPACE,
/* 0x0f */ HIDKeycodes.KEY_TAB,
/* 0x10 */ HIDKeycodes.KEY_Q,
/* 0x11 */ HIDKeycodes.KEY_W,
/* 0x12 */ HIDKeycodes.KEY_E,
/* 0x13 */ HIDKeycodes.KEY_R,
/* 0x14 */ HIDKeycodes.KEY_T,
/* 0x15 */ HIDKeycodes.KEY_Y,
/* 0x16 */ HIDKeycodes.KEY_U,
/* 0x17 */ HIDKeycodes.KEY_I,
/* 0x18 */ HIDKeycodes.KEY_O,
/* 0x19 */ HIDKeycodes.KEY_P,
/* 0x1a */ HIDKeycodes.KEY_LEFT_BRACKET,
/* 0x1b */ HIDKeycodes.KEY_RIGHT_BRACKET,
/* 0x1c */ HIDKeycodes.KEY_ENTER,
/* 0x1d */ 0, //RL CTRL
/* 0x1e */ HIDKeycodes.KEY_A,
/* 0x1f */ HIDKeycodes.KEY_S,
/* 0x20 */ HIDKeycodes.KEY_D,
/* 0x21 */ HIDKeycodes.KEY_F,
/* 0x22 */ HIDKeycodes.KEY_G,
/* 0x23 */ HIDKeycodes.KEY_H,
/* 0x24 */ HIDKeycodes.KEY_J,
/* 0x25 */ HIDKeycodes.KEY_K,
/* 0x26 */ HIDKeycodes.KEY_L,
/* 0x27 */ HIDKeycodes.KEY_SEMICOLON,
/* 0x28 */ HIDKeycodes.KEY_APOSTROPHE,
/* 0x29 */ HIDKeycodes.KEY_GRAVE,
/* 0x2a */ 0, //L SHIFT
/* 0x2b */ HIDKeycodes.KEY_BACKSLASH,
/* 0x2c */ HIDKeycodes.KEY_Z,
/* 0x2d */ HIDKeycodes.KEY_X,
/* 0x2e */ HIDKeycodes.KEY_C,
/* 0x2f */ HIDKeycodes.KEY_V,
/* 0x30 */ HIDKeycodes.KEY_B,
/* 0x31 */ HIDKeycodes.KEY_N,
/* 0x32 */ HIDKeycodes.KEY_M,
/* 0x33 */ HIDKeycodes.KEY_COMA,
/* 0x34 */ HIDKeycodes.KEY_DOT,
/* 0x35 */ HIDKeycodes.KEY_SLASH,
/* 0x36 */ 0, //R SHIFT
/* 0x37 */ HIDKeycodes.KEY_PRINT_SCREEN,
/* 0x38 */ 0, //RL ALT
/* 0x39 */ HIDKeycodes.KEY_SPACEBAR,
/* 0x3a */ HIDKeycodes.KEY_CAPS_LOCK,
/* 0x3b */ HIDKeycodes.KEY_F1,
/* 0x3c */ HIDKeycodes.KEY_F2,
/* 0x3d */ HIDKeycodes.KEY_F3,
/* 0x3e */ HIDKeycodes.KEY_F4,
/* 0x3f */ HIDKeycodes.KEY_F5,
/* 0x40 */ HIDKeycodes.KEY_F6,
/* 0x41 */ HIDKeycodes.KEY_F7,
/* 0x42 */ HIDKeycodes.KEY_F8,
/* 0x43 */ HIDKeycodes.KEY_F9,
/* 0x44 */ HIDKeycodes.KEY_F10,
/* 0x45 */ HIDKeycodes.KEY_NUM_LOCK,
/* 0x46 */ HIDKeycodes.KEY_SCROLL_LOCK,
/* 0x47 */ HIDKeycodes.KEY_HOME,
/* 0x48 */ HIDKeycodes.KEY_ARROW_UP,
/* 0x49 */ HIDKeycodes.KEY_PAGE_UP,
/* 0x4a */ 0, //-
/* 0x4b */ HIDKeycodes.KEY_ARROW_LEFT,
/* 0x4c */ 0, //CENTER
/* 0x4d */ HIDKeycodes.KEY_ARROW_RIGHT,
/* 0x4e */ 0, //+
/* 0x4f */ HIDKeycodes.KEY_END,
/* 0x50 */ HIDKeycodes.KEY_ARROW_DOWN,
/* 0x51 */ HIDKeycodes.KEY_PAGE_DOWN,
/* 0x52 */ HIDKeycodes.KEY_INSERT,
/* 0x53 */ HIDKeycodes.KEY_DELETE,
/* 0x54 */ 0,
/* 0x55 */ 0,
/* 0x56 */ 0,
/* 0x57 */ HIDKeycodes.KEY_F11,
/* 0x58 */ HIDKeycodes.KEY_F12,
/* 0x59 */ 0,
/* 0x5a */ 0,
/* 0x5b */ 0,
/* 0x5c */ 0,
/* 0x5d */ 0,
/* 0x5e */ 0,
/* 0x5f */ 0,
};
public static final int LAYOUT_CODE = 0;
public abstract int[][] getLUT();
public abstract String getLocaleName();
public abstract void type(String text);
public abstract char getChar(int scanCode, boolean capsLock, boolean shift, boolean altGr);
public void type(int[][] lut, String text) {
if (InputStickHID.getState() == ConnectionManager.STATE_READY) {
char[] chars = text.toCharArray();
HIDTransaction t;
for (char c : chars) {
t = getHIDTransaction(lut, c);
if (t != null) {
InputStickHID.addKeyboardTransaction(t);
}
}
}
}
public static int hidToScanCode(byte key) {
for (int scanCode = 0; scanCode < 80; scanCode++) {
if (scanCodeToHID[scanCode] == key) {
return scanCode;
}
}
return -1;
}
public static char getChar(int[][] lut, int scanCode, boolean capsLock, boolean shift, boolean altGr) {
if ((scanCode > 80) || (scanCode < 0)) {
return (char)0;
}
int index = 1;
if ((capsLock) && (lut[scanCode][0] > 0)) {
//capslock is on and it affects current key
if (lut[scanCode][0] == 1) {
if (shift) {
index = 1; //caps + shift = default
} else {
index = 2; //shift
}
} else {
// >1
if (shift) {
if (altGr) {
index = 4; //caps + shift + alt = alt
} else {
index = 1; //caps + shift = default
}
} else {
if (altGr) {
index = 5; //caps + alt = shift + alt
} else {
index = 2; //caps = shift
}
}
}
} else {
if (shift) {
index = 2;
}
if (altGr) {
if (shift) {
index = 5;
} else {
index = 4;
}
}
}
if (lut[scanCode][index] == -1) {
index = 1;
}
return (char)lut[scanCode][index];
}
public static int getScanCode(int[][] lut, char c) {
for (int scanCode = 0; scanCode < 80; scanCode++) {
if (lut[scanCode][0] == -1) {
continue;
} else {
for (int i = 1; i < 6; i++) {
if (lut[scanCode][i] == (int)c) {
return scanCode;
}
}
}
}
return -1;
}
public static byte getKey(int scanCode) {
return scanCodeToHID[scanCode];
}
public static byte getModifiers(int[][] lut, int scanCode, char c) {
if (lut[scanCode][1] == (int)c) {
return 0;
}
if (lut[scanCode][2] == (int)c) {
return HIDKeycodes.SHIFT_LEFT;
}
if (lut[scanCode][3] == (int)c) {
return HIDKeycodes.CTRL_LEFT;
}
if (lut[scanCode][4] == (int)c) {
return HIDKeycodes.ALT_RIGHT;
}
if (lut[scanCode][5] == (int)c) {
return HIDKeycodes.SHIFT_LEFT | HIDKeycodes.ALT_RIGHT;
}
return 0;
}
public static HIDTransaction getHIDTransaction(int[][] lut, char c) {
byte modifiers, key;
int scanCode;
HIDTransaction t = new HIDTransaction();
scanCode = getScanCode(lut, c);
if (scanCode > 0) {
key = getKey(scanCode);
modifiers = getModifiers(lut, scanCode, c);
t.addReport(new KeyboardReport(modifiers, (byte)0));
t.addReport(new KeyboardReport(modifiers, key));
t.addReport(new KeyboardReport());
}
return t;
}
public static KeyboardLayout getLayout(String locale) {
if (locale != null) {
if (locale.equals(UnitedStatesLayout.getInstance().getLocaleName())) {
return UnitedStatesLayout.getInstance();
} else if (locale.equals(PolishLayout.getInstance().getLocaleName())) {
return PolishLayout.getInstance();
} else if (locale.equals(RussianLayout.getInstance().getLocaleName())) {
return RussianLayout.getInstance();
} else if (locale.equals(GermanLayout.getInstance().getLocaleName())) {
return GermanLayout.getInstance();
}
}
return UnitedStatesLayout.getInstance();
}
}

View File

@ -0,0 +1,144 @@
package com.inputstick.api.layout;
public class PolishLayout extends KeyboardLayout {
public static final String LOCALE_NAME = "pl-PL";
public static final int LUT[][] = {
/* 0 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 1 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 2 */ { 0 , (int)'1' , 0x21 , -1 , -1 , -1 } ,
/* 3 */ { 0 , (int)'2' , 0x40 , -1 , -1 , -1 } ,
/* 4 */ { 0 , (int)'3' , 0x23 , -1 , -1 , -1 } ,
/* 5 */ { 0 , (int)'4' , 0x24 , -1 , -1 , -1 } ,
/* 6 */ { 0 , (int)'5' , 0x25 , -1 , -1 , -1 } ,
/* 7 */ { 0 , (int)'6' , 0x005e , -1 , -1 , -1 } ,
/* 8 */ { 0 , (int)'7' , 0x26 , -1 , -1 , -1 } ,
/* 9 */ { 0 , (int)'8' , 0x002a , -1 , -1 , -1 } ,
/* 0a */ { 0 , (int)'9' , 0x28 , -1 , -1 , -1 } ,
/* 0b */ { 0 , (int)'0' , 0x29 , -1 , -1 , -1 } ,
/* 0c */ { 0 , 0x002d , 0x005f , -1 , -1 , -1 } ,
/* 0d */ { 0 , 0x003d , 0x002b , -1 , -1 , -1 } ,
/* 0e */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 0f */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 10 */ { 1 , (int)'q' , (int)'Q' , -1 , -1 , -1 } ,
/* 11 */ { 1 , (int)'w' , (int)'W' , -1 , -1 , -1 } ,
/* 12 */ { 5 , (int)'e' , (int)'E' , -1 , 0x119 , 0x118 } ,
/* 13 */ { 1 , (int)'r' , (int)'R' , -1 , -1 , -1 } ,
/* 14 */ { 1 , (int)'t' , (int)'T' , -1 , -1 , -1 } ,
/* 15 */ { 1 , (int)'y' , (int)'Y' , -1 , -1 , -1 } ,
/* 16 */ { 1 , (int)'u' , (int)'U' , -1 , 0x20ac , -1 } ,
/* 17 */ { 1 , (int)'i' , (int)'I' , -1 , -1 , -1 } ,
/* 18 */ { 5 , (int)'o' , (int)'O' , -1 , 0x00f3 , 0x00d3 } ,
/* 19 */ { 1 , (int)'p' , (int)'P' , -1 , -1 , -1 } ,
/* 1a */ { 0 , 0x005b , 0x007b , 0x001b , -1 , -1 } ,
/* 1b */ { 0 , 0x005d , 0x007d , 0x001d , -1 , -1 } ,
/* 1c */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 1d */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 1e */ { 5 , (int)'a' , (int)'A' , -1 , 0x105 , 0x104 } ,
/* 1f */ { 5 , (int)'s' , (int)'S' , -1 , 0x015b , 0x015a } ,
/* 20 */ { 1 , (int)'d' , (int)'D' , -1 , -1 , -1 } ,
/* 21 */ { 1 , (int)'f' , (int)'F' , -1 , -1 , -1 } ,
/* 22 */ { 1 , (int)'g' , (int)'G' , -1 , -1 , -1 } ,
/* 23 */ { 1 , (int)'h' , (int)'H' , -1 , -1 , -1 } ,
/* 24 */ { 1 , (int)'j' , (int)'J' , -1 , -1 , -1 } ,
/* 25 */ { 1 , (int)'k' , (int)'K' , -1 , -1 , -1 } ,
/* 26 */ { 5 , (int)'l' , (int)'L' , -1 , 0x142 , 0x141 } ,
/* 27 */ { 0 , 0x003b , 0x003a , 0x001d , -1 , -1 } ,
/* 28 */ { 0 , 0x27 , 0x22 , -1 , -1 , -1 } ,
/* 29 */ { 0 , 0x60 , 0x007e , -1 , -1 , -1 } , //@
/* 2a */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 2b */ { 0 , 0x005c , 0x007c , 0x001c , -1 , -1 } ,
/* 2c */ { 5 , (int)'z' , (int)'Z' , -1 , 0x017c , 0x017b } ,
/* 2d */ { 5 , (int)'x' , (int)'X' , -1 , 0x017a , 0x179 } ,
/* 2e */ { 5 , (int)'c' , (int)'C' , -1 , 0x107 , 0x106 } ,
/* 2f */ { 1 , (int)'v' , (int)'V' , -1 , -1 , -1 } ,
/* 30 */ { 1 , (int)'b' , (int)'B' , -1 , -1 , -1 } ,
/* 31 */ { 5 , (int)'n' , (int)'N' , -1 , 0x144 , 0x143 } ,
/* 32 */ { 1 , (int)'m' , (int)'M' , -1 , -1 , -1 } ,
/* 33 */ { 0 , 0x002c , 0x003c , -1 , -1 , -1 } ,
/* 34 */ { 0 , 0x002e , 0x003e , -1 , -1 , -1 } ,
/* 35 */ { 0 , 0x002f , 0x003f , -1 , -1 , -1 } ,
/* 36 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 37 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 38 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 39 */ { 0 , 0x20 , 0x20 , 0x20 , -1 , -1 } ,
/* 3a */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 3b */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 3c */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 3d */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 3e */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 3f */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 40 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 41 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 42 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 43 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 44 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 45 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 46 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 47 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 48 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 49 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 4a */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 4b */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 4c */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 4d */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 4e */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 4f */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 50 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 51 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 52 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 53 */ { 0 , 0x002c , 0x002c , -1 , -1 , -1 } ,
/* 54 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 55 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 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 } ,
/* 5a */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 5b */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 5c */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 5d */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 5e */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 5f */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
};
private static PolishLayout instance = new PolishLayout();
private PolishLayout() {
}
public static PolishLayout getInstance() {
return instance;
}
@Override
public int[][] getLUT() {
return LUT;
}
@Override
public void type(String text) {
super.type(LUT, text);
}
@Override
public char getChar(int scanCode, boolean capsLock, boolean shift, boolean altGr) {
return super.getChar(LUT, scanCode, capsLock, shift, altGr);
}
@Override
public String getLocaleName() {
return LOCALE_NAME;
}
}

View File

@ -0,0 +1,144 @@
package com.inputstick.api.layout;
public class RussianLayout extends KeyboardLayout {
public static final String LOCALE_NAME = "ru-RU";
public static final int LUT[][] = {
/* 0 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 1 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 2 */ { 0 , (int)'1' , 0x21 , -1 , -1 , -1 } ,
/* 3 */ { 0 , (int)'2' , 0x22 , -1 , -1 , -1 } ,
/* 4 */ { 0 , (int)'3' , 0x2116 , -1 , -1 , -1 } ,
/* 5 */ { 0 , (int)'4' , 0x003b , -1 , -1 , -1 } ,
/* 6 */ { 0 , (int)'5' , 0x25 , -1 , -1 , -1 } ,
/* 7 */ { 0 , (int)'6' , 0x003a , -1 , -1 , -1 } ,
/* 8 */ { 0 , (int)'7' , 0x003f , -1 , -1 , -1 } ,
/* 9 */ { 0 , (int)'8' , 0x002a , -1 , -1 , -1 } ,
/* 0a */ { 0 , (int)'9' , 0x28 , -1 , -1 , -1 } ,
/* 0b */ { 0 , (int)'0' , 0x29 , -1 , -1 , -1 } ,
/* 0c */ { 0 , 0x002d , 0x005f , -1 , -1 , -1 } ,
/* 0d */ { 0 , 0x003d , 0x002b , -1 , -1 , -1 } ,
/* 0e */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 0f */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 10 */ { 1 , 0x439 , 0x419 , -1 , -1 , -1 } ,
/* 11 */ { 1 , 0x446 , 0x426 , -1 , -1 , -1 } ,
/* 12 */ { 1 , 0x443 , 0x423 , -1 , -1 , -1 } ,
/* 13 */ { 1 , 0x043a , 0x041a , -1 , -1 , -1 } ,
/* 14 */ { 1 , 0x435 , 0x415 , -1 , -1 , -1 } ,
/* 15 */ { 1 , 0x043d , 0x041d , -1 , -1 , -1 } ,
/* 16 */ { 1 , 0x433 , 0x413 , -1 , -1 , -1 } ,
/* 17 */ { 1 , 0x448 , 0x428 , -1 , -1 , -1 } ,
/* 18 */ { 1 , 0x449 , 0x429 , -1 , -1 , -1 } ,
/* 19 */ { 1 , 0x437 , 0x417 , -1 , -1 , -1 } ,
/* 1a */ { 1 , 0x445 , 0x425 , -1 , -1 , -1 } ,
/* 1b */ { 1 , 0x044a , 0x042a , -1 , -1 , -1 } ,
/* 1c */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 1d */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 1e */ { 1 , 0x444 , 0x424 , -1 , -1 , -1 } ,
/* 1f */ { 1 , 0x044b , 0x042b , -1 , -1 , -1 } ,
/* 20 */ { 1 , 0x432 , 0x412 , -1 , -1 , -1 } ,
/* 21 */ { 1 , 0x430 , 0x410 , -1 , -1 , -1 } ,
/* 22 */ { 1 , 0x043f , 0x041f , -1 , -1 , -1 } ,
/* 23 */ { 1 , 0x440 , 0x420 , -1 , -1 , -1 } ,
/* 24 */ { 1 , 0x043e , 0x041e , -1 , -1 , -1 } ,
/* 25 */ { 1 , 0x043b , 0x041b , -1 , -1 , -1 } ,
/* 26 */ { 1 , 0x434 , 0x414 , -1 , -1 , -1 } ,
/* 27 */ { 1 , 0x436 , 0x416 , -1 , -1 , -1 } ,
/* 28 */ { 1 , 0x044d , 0x042d , -1 , -1 , -1 } ,
/* 29 */ { 1 , 0x451 , 0x401 , -1 , -1 , -1 } ,
/* 2a */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 2b */ { 0 , 0x005c , 0x002f , 0x001c , -1 , -1 } ,
/* 2c */ { 1 , 0x044f , 0x042f , -1 , -1 , -1 } ,
/* 2d */ { 1 , 0x447 , 0x427 , -1 , -1 , -1 } ,
/* 2e */ { 1 , 0x441 , 0x421 , -1 , -1 , -1 } ,
/* 2f */ { 1 , 0x043c , 0x041c , -1 , -1 , -1 } ,
/* 30 */ { 1 , 0x438 , 0x418 , -1 , -1 , -1 } ,
/* 31 */ { 1 , 0x442 , 0x422 , -1 , -1 , -1 } ,
/* 32 */ { 1 , 0x044c , 0x042c , -1 , -1 , -1 } ,
/* 33 */ { 1 , 0x431 , 0x411 , -1 , -1 , -1 } ,
/* 34 */ { 1 , 0x044e , 0x042e , -1 , -1 , -1 } ,
/* 35 */ { 0 , 0x002e , 0x002c , -1 , -1 , -1 } ,
/* 36 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 37 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 38 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 39 */ { 0 , 0x20 , 0x20 , 0x20 , -1 , -1 } ,
/* 3a */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 3b */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 3c */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 3d */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 3e */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 3f */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 40 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 41 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 42 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 43 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 44 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 45 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 46 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 47 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 48 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 49 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 4a */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 4b */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 4c */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 4d */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 4e */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 4f */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 50 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 51 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 52 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 53 */ { 0 , 0x002c , 0x002c , -1 , -1 , -1 } ,
/* 54 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 55 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 56 */ { 0 , 0x005c , 0x002f , 0x001c , -1 , -1 } ,
/* 57 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 58 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 59 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 5a */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 5b */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 5c */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 5d */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 5e */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 5f */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
};
private static RussianLayout instance = new RussianLayout();
private RussianLayout() {
}
public static RussianLayout getInstance() {
return instance;
}
@Override
public int[][] getLUT() {
return LUT;
}
@Override
public void type(String text) {
super.type(LUT, text);
}
@Override
public char getChar(int scanCode, boolean capsLock, boolean shift, boolean altGr) {
return super.getChar(LUT, scanCode, capsLock, shift, altGr);
}
@Override
public String getLocaleName() {
return LOCALE_NAME;
}
}

View File

@ -0,0 +1,146 @@
package com.inputstick.api.layout;
public class UnitedStatesLayout extends KeyboardLayout {
public static final String LOCALE_NAME = "en-US";
public static final int LUT[][] = {
/* 0 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 1 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 2 */ { 0 , (int)'1' , 0x21 , -1 , -1 , -1 } ,
/* 3 */ { 0 , (int)'2' , 0x40 , -1 , -1 , -1 } ,
/* 4 */ { 0 , (int)'3' , 0x23 , -1 , -1 , -1 } ,
/* 5 */ { 0 , (int)'4' , 0x24 , -1 , -1 , -1 } ,
/* 6 */ { 0 , (int)'5' , 0x25 , -1 , -1 , -1 } ,
/* 7 */ { 0 , (int)'6' , 0x005e , -1 , -1 , -1 } ,
/* 8 */ { 0 , (int)'7' , 0x26 , -1 , -1 , -1 } ,
/* 9 */ { 0 , (int)'8' , 0x002a , -1 , -1 , -1 } ,
/* 0a */ { 0 , (int)'9' , 0x28 , -1 , -1 , -1 } ,
/* 0b */ { 0 , (int)'0' , 0x29 , -1 , -1 , -1 } ,
/* 0c */ { 0 , 0x002d , 0x005f , -1 , -1 , -1 } ,
/* 0d */ { 0 , 0x003d , 0x002b , -1 , -1 , -1 } ,
/* 0e */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 0f */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 10 */ { 1 , (int)'q' , (int)'Q' , -1 , -1 , -1 } ,
/* 11 */ { 1 , (int)'w' , (int)'W' , -1 , -1 , -1 } ,
/* 12 */ { 1 , (int)'e' , (int)'E' , -1 , -1 , -1 } ,
/* 13 */ { 1 , (int)'r' , (int)'R' , -1 , -1 , -1 } ,
/* 14 */ { 1 , (int)'t' , (int)'T' , -1 , -1 , -1 } ,
/* 15 */ { 1 , (int)'y' , (int)'Y' , -1 , -1 , -1 } ,
/* 16 */ { 1 , (int)'u' , (int)'U' , -1 , -1 , -1 } ,
/* 17 */ { 1 , (int)'i' , (int)'I' , -1 , -1 , -1 } ,
/* 18 */ { 1 , (int)'o' , (int)'O' , -1 , -1 , -1 } ,
/* 19 */ { 1 , (int)'p' , (int)'P' , -1 , -1 , -1 } ,
/* 1a */ { 0 , 0x005b , 0x007b , 0x001b , -1 , -1 } ,
/* 1b */ { 0 , 0x005d , 0x007d , 0x001d , -1 , -1 } ,
/* 1c */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 1d */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 1e */ { 1 , (int)'a' , (int)'A' , -1 , -1 , -1 } ,
/* 1f */ { 1 , (int)'s' , (int)'S' , -1 , -1 , -1 } ,
/* 20 */ { 1 , (int)'d' , (int)'D' , -1 , -1 , -1 } ,
/* 21 */ { 1 , (int)'f' , (int)'F' , -1 , -1 , -1 } ,
/* 22 */ { 1 , (int)'g' , (int)'G' , -1 , -1 , -1 } ,
/* 23 */ { 1 , (int)'h' , (int)'H' , -1 , -1 , -1 } ,
/* 24 */ { 1 , (int)'j' , (int)'J' , -1 , -1 , -1 } ,
/* 25 */ { 1 , (int)'k' , (int)'K' , -1 , -1 , -1 } ,
/* 26 */ { 1 , (int)'l' , (int)'L' , -1 , -1 , -1 } ,
/* 27 */ { 0 , 0x003b , 0x003a , -1 , -1 , -1 } ,
/* 28 */ { 0 , 0x27 , 0x22 , -1 , -1 , -1 } ,
/* 29 */ { 0 , 0x60 , 0x007e , -1 , -1 , -1 } ,
/* 2a */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 2b */ { 0 , 0x005c , 0x007c , 0x001c , -1 , -1 } ,
/* 2c */ { 1 , (int)'z' , (int)'Z' , -1 , -1 , -1 } ,
/* 2d */ { 1 , (int)'x' , (int)'X' , -1 , -1 , -1 } ,
/* 2e */ { 1 , (int)'c' , (int)'C' , -1 , -1 , -1 } ,
/* 2f */ { 1 , (int)'v' , (int)'V' , -1 , -1 , -1 } ,
/* 30 */ { 1 , (int)'b' , (int)'B' , -1 , -1 , -1 } ,
/* 31 */ { 1 , (int)'n' , (int)'N' , -1 , -1 , -1 } ,
/* 32 */ { 1 , (int)'m' , (int)'M' , -1 , -1 , -1 } ,
/* 33 */ { 0 , 0x002c , 0x003c , -1 , -1 , -1 } ,
/* 34 */ { 0 , 0x002e , 0x003e , -1 , -1 , -1 } ,
/* 35 */ { 0 , 0x002f , 0x003f , -1 , -1 , -1 } ,
/* 36 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 37 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 38 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 39 */ { 0 , 0x20 , 0x20 , 0x20 , -1 , -1 } ,
/* 3a */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 3b */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 3c */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 3d */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 3e */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 3f */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 40 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 41 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 42 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 43 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 44 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 45 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 46 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 47 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 48 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 49 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 4a */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 4b */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 4c */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 4d */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 4e */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 4f */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 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 } ,
/* 54 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 55 */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 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 } ,
/* 5a */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 5b */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 5c */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 5d */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 5e */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
/* 5f */ { -1 , 0 , 0 , 0 , 0 , 0 } ,
};
private static UnitedStatesLayout instance = new UnitedStatesLayout();
private UnitedStatesLayout() {
}
public static UnitedStatesLayout getInstance() {
return instance;
}
@Override
public int[][] getLUT() {
return LUT;
}
@Override
public void type(String text) {
super.type(LUT, text);
}
@Override
public char getChar(int scanCode, boolean capsLock, boolean shift, boolean altGr) {
return super.getChar(LUT, scanCode, capsLock, shift, altGr);
}
@Override
public String getLocaleName() {
return LOCALE_NAME;
}
}

View File

@ -0,0 +1,61 @@
package com.inputstick.init;
import com.inputstick.api.Packet;
public class BasicInitManager extends InitManager {
private boolean initDone = false;
public BasicInitManager(byte[] key) {
super(key);
}
@Override
public void onConnected() {
/*Packet p = new Packet(false, Packet.RAW_OLD_BOOTLOADER); //compatibility
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();
} else {
mListener.onInitNotReady();
}
}
}
}
}

View File

@ -0,0 +1,28 @@
package com.inputstick.init;
import com.inputstick.api.Packet;
public class BootloaderInitManager extends InitManager {
public BootloaderInitManager(byte[] key) {
super(key);
}
@Override
public void onConnected() {
//TODO key
sendPacket(new Packet(true, Packet.CMD_RUN_BL));
}
@Override
public void onData(byte[] data) {
byte cmd = data[0];
//byte respCode = data[1];
//byte param = data[1];
if (cmd == Packet.CMD_RUN_BL) {
mListener.onInitReady();
}
}
}

View File

@ -0,0 +1,33 @@
package com.inputstick.init;
import com.inputstick.api.Packet;
import com.inputstick.api.PacketManager;
public class InitManager {
protected PacketManager mPacketManager;
protected InitManagerListener mListener;
protected byte[] mKey;
public InitManager(byte[] key) {
mKey = key;
}
public void init(InitManagerListener listener, PacketManager packetManager) {
mListener = listener;
mPacketManager = packetManager;
}
public void onConnected() {
mListener.onInitReady();
}
public void onData(byte[] data) {
}
public void sendPacket(Packet p) {
mPacketManager.sendPacket(p);
}
}

View File

@ -0,0 +1,9 @@
package com.inputstick.init;
public interface InitManagerListener {
public void onInitReady();
public void onInitNotReady();
public void onInitFailure(int code);
}

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>

33
src/java/PluginA/.project Normal file
View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>PluginA</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,4 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.source=1.6

View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="keepass2android.plugina"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="19" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="keepass2android.plugina.PlugInA"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name="PluginAAccessReceiver" android:exported="true">
<intent-filter>
<action android:name="keepass2android.ACTION_TRIGGER_REQUEST_ACCESS" />
<action android:name="keepass2android.ACTION_RECEIVE_ACCESS" />
<action android:name="keepass2android.ACTION_REVOKE_ACCESS" />
</intent-filter>
</receiver>
<receiver android:name="PluginAActionReceiver" android:exported="true">
<intent-filter>
<action android:name="keepass2android.ACTION_OPEN_ENTRY" />
<action android:name="keepass2android.ACTION_CLOSE_ENTRY_VIEW" />
<action android:name="keepass2android.ACTION_ENTRY_ACTION_SELECTED" />
<action android:name="keepass2android.ACTION_LOCK_DATABASE" />
<action android:name="keepass2android.ACTION_UNLOCK_DATABASE" />
<action android:name="keepass2android.ACTION_CLOSE_DATABASE" />
<action android:name="keepass2android.ACTION_OPEN_DATABASE" />
</intent-filter>
</receiver>
</application>
</manifest>

View File

@ -0,0 +1,6 @@
/** Automatically generated file. DO NOT MODIFY */
package keepass2android.plugina;
public final class BuildConfig {
public final static boolean DEBUG = true;
}

View File

@ -0,0 +1,91 @@
/* AUTO-GENERATED FILE. DO NOT MODIFY.
*
* This class was automatically generated by the
* aapt tool from the resource data it found. It
* should not be modified by hand.
*/
package keepass2android.plugina;
public final class R {
public static final class attr {
}
public static final class dimen {
/** Default screen margins, per the Android Design guidelines.
Example customization of dimensions originally defined in res/values/dimens.xml
(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.
Example customization of dimensions originally defined in res/values/dimens.xml
(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).
*/
public static final int activity_horizontal_margin=0x7f040000;
public static final int activity_vertical_margin=0x7f040001;
}
public static final class drawable {
public static final int ic_launcher=0x7f020000;
}
public static final class id {
public static final int action_settings=0x7f080001;
public static final int container=0x7f080000;
}
public static final class layout {
public static final int activity_plug_in=0x7f030000;
public static final int fragment_plug_in=0x7f030001;
}
public static final class menu {
public static final int plug_in=0x7f070000;
}
public static final class string {
public static final int action_settings=0x7f050002;
public static final int app_name=0x7f050000;
public static final int hello_world=0x7f050001;
public static final int kp2aplugin_author=0x7f050005;
public static final int kp2aplugin_shortdesc=0x7f050004;
public static final int kp2aplugin_title=0x7f050003;
}
public static final class style {
/**
Base application theme, dependent on API level. This theme is replaced
by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
Theme customizations available in newer API levels can go in
res/values-vXX/styles.xml, while customizations related to
backward-compatibility can go here.
Base application theme for API 11+. This theme completely replaces
AppBaseTheme from res/values/styles.xml on API 11+ devices.
API 11 theme customizations can go here.
Base application theme for API 14+. This theme completely replaces
AppBaseTheme from BOTH res/values/styles.xml and
res/values-v11/styles.xml on API 14+ devices.
API 14 theme customizations can go here.
Base application theme, dependent on API level. This theme is replaced
by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
Theme customizations available in newer API levels can go in
res/values-vXX/styles.xml, while customizations related to
backward-compatibility can go here.
*/
public static final int AppBaseTheme=0x7f060000;
/** Application theme.
All customizations that are NOT specific to a particular API-level can go here.
Application theme.
All customizations that are NOT specific to a particular API-level can go here.
*/
public static final int AppTheme=0x7f060001;
}
}

View File

@ -0,0 +1,24 @@
/* AUTO-GENERATED FILE. DO NOT MODIFY.
*
* This class was automatically generated by the
* aapt tool from the resource data it found. It
* should not be modified by hand.
*/
package keepass2android.pluginsdk;
public final class R {
public static final class dimen {
public static final int activity_horizontal_margin = 0x7f040000;
public static final int activity_vertical_margin = 0x7f040001;
}
public static final class drawable {
public static final int ic_launcher = 0x7f020000;
}
public static final class string {
public static final int app_name = 0x7f050000;
}
public static final class style {
public static final int AppBaseTheme = 0x7f060000;
public static final int AppTheme = 0x7f060001;
}
}

Binary file not shown.

View File

@ -0,0 +1,20 @@
# To enable ProGuard in your project, edit project.properties
# to define the proguard.config property as described in that file.
#
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in ${sdk.dir}/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the ProGuard
# include property in project.properties.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

View File

@ -0,0 +1,15 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system edit
# "ant.properties", and override values to adapt the script to your
# project structure.
#
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
# Project target.
target=android-19
android.library.reference.1=../Keepass2AndroidPluginSDK

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -0,0 +1,8 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="keepass2android.plugina.PlugInA"
tools:ignore="MergeRootFrame" />

View File

@ -0,0 +1,16 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="keepass2android.plugina.PlugInA$PlaceholderFragment" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
</RelativeLayout>

View File

@ -0,0 +1,12 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="keepass2android.plugina.PlugInA" >
<item
android:id="@+id/action_settings"
android:orderInCategory="100"
android:title="@string/action_settings"
android:showAsAction="never"/>
</menu>

View File

@ -0,0 +1,10 @@
<resources>
<!--
Example customization of dimensions originally defined in res/values/dimens.xml
(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).
-->
<dimen name="activity_horizontal_margin">64dp</dimen>
</resources>

View File

@ -0,0 +1,7 @@
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
</resources>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">PluginA</string>
<string name="hello_world">Hello world!</string>
<string name="action_settings">Settings</string>
<string name="kp2aplugin_title">The Great PluginA</string>
<string name="kp2aplugin_shortdesc">Test plugin to demonstrate how plugins work</string>
<string name="kp2aplugin_author">Philipp Crocoll</string>
</resources>

View File

@ -0,0 +1,20 @@
<resources>
<!--
Base application theme, dependent on API level. This theme is replaced
by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
-->
<style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
<!--
Theme customizations available in newer API levels can go in
res/values-vXX/styles.xml, while customizations related to
backward-compatibility can go here.
-->
</style>
<!-- Application theme. -->
<style name="AppTheme" parent="AppBaseTheme">
<!-- All customizations that are NOT specific to a particular API-level can go here. -->
</style>
</resources>

View File

@ -0,0 +1,20 @@
package keepass2android.plugina;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
public class EntryOpenedReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Bundle extras = intent.getExtras();
if (extras != null) {
Log.w("PluginA", "received broadcast!");
}
}
}

View File

@ -0,0 +1,62 @@
package keepass2android.plugina;
import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.os.Build;
public class PlugInA extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_plug_in);
if (savedInstanceState == null) {
getFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment()).commit();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.plug_in, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {
public PlaceholderFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_plug_in,
container, false);
return rootView;
}
}
}

View File

@ -0,0 +1,20 @@
package keepass2android.plugina;
import java.util.ArrayList;
import keepass2android.pluginsdk.Strings;
public class PluginAAccessReceiver
extends keepass2android.pluginsdk.PluginAccessBroadcastReceiver
{
@Override
public ArrayList<String> getScopes() {
ArrayList<String> scopes = new ArrayList<String>();
scopes.add(Strings.SCOPE_DATABASE_ACTIONS);
scopes.add(Strings.SCOPE_CURRENT_ENTRY);
return scopes;
}
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>PluginInputStick</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,4 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.source=1.6

View File

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="keepass2android.plugin.inputstick"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="19" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="keepass2android.plugin.inputstick.MainActivity"
android:label="@string/app_name" >
</activity>
<receiver
android:name="keepass2android.plugin.inputstick.AccessReceiver"
android:exported="true" >
<intent-filter>
<action android:name="keepass2android.ACTION_TRIGGER_REQUEST_ACCESS" />
<action android:name="keepass2android.ACTION_RECEIVE_ACCESS" />
<action android:name="keepass2android.ACTION_REVOKE_ACCESS" />
</intent-filter>
</receiver>
<receiver
android:name="keepass2android.plugin.inputstick.ActionReceiver"
android:exported="true" >
<intent-filter>
<action android:name="keepass2android.ACTION_OPEN_ENTRY" />
<action android:name="keepass2android.ACTION_ENTRY_OUTPUT_MODIFIED" />
<action android:name="keepass2android.ACTION_ENTRY_ACTION_SELECTED" />
<action android:name="keepass2android.ACTION_CLOSE_ENTRY_VIEW" />
</intent-filter>
</receiver>
<service
android:name="keepass2android.plugin.inputstick.InputStickService"
android:enabled="true" >
</service>
<activity
android:name="keepass2android.plugin.inputstick.SettingsActivity"
android:label="@string/title_activity_settings" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@ -0,0 +1,20 @@
/* AUTO-GENERATED FILE. DO NOT MODIFY.
*
* This class was automatically generated by the
* aapt tool from the resource data it found. It
* should not be modified by hand.
*/
package com.inputstick.api;
public final class R {
public static final class drawable {
public static final int ic_launcher = 0x7f020000;
}
public static final class string {
public static final int app_name = 0x7f060000;
}
public static final class style {
public static final int AppBaseTheme = 0x7f070000;
public static final int AppTheme = 0x7f070001;
}
}

View File

@ -0,0 +1,6 @@
/** Automatically generated file. DO NOT MODIFY */
package keepass2android.plugin.inputstick;
public final class BuildConfig {
public final static boolean DEBUG = true;
}

View File

@ -0,0 +1,141 @@
/* AUTO-GENERATED FILE. DO NOT MODIFY.
*
* This class was automatically generated by the
* aapt tool from the resource data it found. It
* should not be modified by hand.
*/
package keepass2android.plugin.inputstick;
public final class R {
public static final class array {
public static final int layout_names=0x7f080000;
public static final int layout_values=0x7f080001;
}
public static final class attr {
}
public static final class dimen {
/** Default screen margins, per the Android Design guidelines.
Example customization of dimensions originally defined in res/values/dimens.xml
(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.
Example customization of dimensions originally defined in res/values/dimens.xml
(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).
*/
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 int ic_notification=0x7f020001;
}
public static final class id {
public static final int action_settings=0x7f0a0003;
public static final int button1=0x7f0a0001;
public static final int button2=0x7f0a0002;
public static final int container=0x7f0a0000;
}
public static final class layout {
public static final int activity_main=0x7f030000;
public static final int fragment_main=0x7f030001;
}
public static final class menu {
public static final int main=0x7f090000;
}
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 app_name=0x7f060000;
/** Strings related to Settings
*/
public static final int configure_plugin=0x7f060009;
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=0x7f06000a;
public static final int title_activity_settings=0x7f060008;
}
public static final class style {
/**
Base application theme, dependent on API level. This theme is replaced
by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
Theme customizations available in newer API levels can go in
res/values-vXX/styles.xml, while customizations related to
backward-compatibility can go here.
Base application theme for API 11+. This theme completely replaces
AppBaseTheme from res/values/styles.xml on API 11+ devices.
API 11 theme customizations can go here.
Base application theme for API 14+. This theme completely replaces
AppBaseTheme from BOTH res/values/styles.xml and
res/values-v11/styles.xml on API 14+ devices.
API 14 theme customizations can go here.
Base application theme, dependent on API level. This theme is replaced
by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
Theme customizations available in newer API levels can go in
res/values-vXX/styles.xml, while customizations related to
backward-compatibility can go here.
Base application theme for API 11+. This theme completely replaces
AppBaseTheme from res/values/styles.xml on API 11+ devices.
API 11 theme customizations can go here.
Base application theme for API 14+. This theme completely replaces
AppBaseTheme from BOTH res/values/styles.xml and
res/values-v11/styles.xml on API 14+ devices.
API 14 theme customizations can go here.
Base application theme, dependent on API level. This theme is replaced
by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
Theme customizations available in newer API levels can go in
res/values-vXX/styles.xml, while customizations related to
backward-compatibility can go here.
Base application theme for API 11+. This theme completely replaces
AppBaseTheme from res/values/styles.xml on API 11+ devices.
API 11 theme customizations can go here.
Base application theme for API 14+. This theme completely replaces
AppBaseTheme from BOTH res/values/styles.xml and
res/values-v11/styles.xml on API 14+ devices.
API 14 theme customizations can go here.
*/
public static final int AppBaseTheme=0x7f070000;
/** Application theme.
All customizations that are NOT specific to a particular API-level can go here.
Application theme.
All customizations that are NOT specific to a particular API-level can go here.
Application theme.
All customizations that are NOT specific to a particular API-level can go here.
*/
public static final int AppTheme=0x7f070001;
}
public static final class xml {
public static final int pref_general=0x7f040000;
}
}

View File

@ -0,0 +1,24 @@
/* AUTO-GENERATED FILE. DO NOT MODIFY.
*
* This class was automatically generated by the
* aapt tool from the resource data it found. It
* should not be modified by hand.
*/
package keepass2android.pluginsdk;
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 string {
public static final int app_name = 0x7f060000;
}
public static final class style {
public static final int AppBaseTheme = 0x7f070000;
public static final int AppTheme = 0x7f070001;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -0,0 +1,20 @@
# To enable ProGuard in your project, edit project.properties
# to define the proguard.config property as described in that file.
#
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in ${sdk.dir}/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the ProGuard
# include property in project.properties.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

View File

@ -0,0 +1,16 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system edit
# "ant.properties", and override values to adapt the script to your
# project structure.
#
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
# Project target.
target=android-19
android.library.reference.1=../InputStickAPI
android.library.reference.2=../Keepass2AndroidPluginSDK

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 839 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 548 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1016 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,12 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="keepass2android.plugin.inputstick.MainActivity"
tools:ignore="MergeRootFrame" >
</FrameLayout>

View File

@ -0,0 +1,29 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="keepass2android.plugin.inputstick.MainActivity$PlaceholderFragment" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button 1" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button 2" />
</LinearLayout>
</RelativeLayout>

View File

@ -0,0 +1,11 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context="keepass2android.plugin.inputstick.MainActivity" >
<item
android:id="@+id/action_settings"
android:orderInCategory="100"
android:showAsAction="never"
android:title="@string/action_settings"/>
</menu>

View File

@ -0,0 +1,11 @@
<resources>
<!--
Base application theme for API 11+. This theme completely replaces
AppBaseTheme from res/values/styles.xml on API 11+ devices.
-->
<style name="AppBaseTheme" parent="android:Theme.Holo.Light">
<!-- API 11 theme customizations can go here. -->
</style>
</resources>

View File

@ -0,0 +1,12 @@
<resources>
<!--
Base application theme for API 14+. This theme completely replaces
AppBaseTheme from BOTH res/values/styles.xml and
res/values-v11/styles.xml on API 14+ devices.
-->
<style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
<!-- API 14 theme customizations can go here. -->
</style>
</resources>

View File

@ -0,0 +1,10 @@
<resources>
<!--
Example customization of dimensions originally defined in res/values/dimens.xml
(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).
-->
<dimen name="activity_horizontal_margin">64dp</dimen>
</resources>

View File

@ -0,0 +1,7 @@
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
</resources>

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">InputStick Plugin for KP2A</string>
<string name="action_settings">Settings</string>
<string name="kp2aplugin_title">InputStick Plugin</string>
<string name="kp2aplugin_shortdesc">Allows to send text from KP2A via InputStick to your PC.</string>
<string name="kp2aplugin_author">Philipp Crocoll</string>
<string name="action_input_stick">Type with InputStick</string>
<string name="action_type_tab">Type Tab with InputStick</string>
<string name="action_type_enter">Type Enter with InputStick</string>
</resources>

View File

@ -0,0 +1,24 @@
<resources>
<string name="title_activity_settings">KP2A InputStick Settings</string>
<!-- Strings related to Settings -->
<string name="configure_plugin">Configure as plugin</string>
<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>
</string-array>
<string-array name="layout_values">
<item>en-US</item>
<item>de-DE</item>
<item>pl-PL</item>
<item>ru-RU</item>
</string-array>
</resources>

View File

@ -0,0 +1,20 @@
<resources>
<!--
Base application theme, dependent on API level. This theme is replaced
by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
-->
<style name="AppBaseTheme" parent="android:Theme.Light">
<!--
Theme customizations available in newer API levels can go in
res/values-vXX/styles.xml, while customizations related to
backward-compatibility can go here.
-->
</style>
<!-- Application theme. -->
<style name="AppTheme" parent="AppBaseTheme">
<!-- All customizations that are NOT specific to a particular API-level can go here. -->
</style>
</resources>

View File

@ -0,0 +1,24 @@
<PreferenceScreen
android:key="general_pref"
xmlns:android="http://schemas.android.com/apk/res/android" >
<Preference
android:key="enable_plugin_pref"
android:title="@string/configure_plugin" />
<!--
NOTE: Hide buttons to simplify the UI. Users can touch outside the dialog to
dismiss it.
-->
<!-- NOTE: ListPreference's summary should be set to its value by the activity code. -->
<ListPreference
android:defaultValue="en-US"
android:entries="@array/layout_names"
android:entryValues="@array/layout_values"
android:key="kbd_layout"
android:negativeButtonText="@null"
android:positiveButtonText="@null"
android:title="@string/layout_title" />
</PreferenceScreen>

Some files were not shown because too many files have changed in this diff Show More