Main.BluetoothKeyboard History
Hide minor edits - Show changes to markup
Deprecated: Function create_function() is deprecated in /home/bluekitc/public_html/ringwald.ch/electronics/pmwiki.php on line 456
Deleted line 190:
Deleted lines 192-193:
Further Exploration
Added lines 195-196:
Further Exploration \\
Changed lines 1-2 from:
User-space Java Bluetooth (JSR-82) Keyboard Driver
to:
User-Space Java Bluetooth (JSR-82) Keyboard Driver
Changed lines 13-17 from:
Further Exploration
Build your own HalfKeyboard (tm).
to:
Changed lines 192-198 from:
@]
to:
@]
Further Exploration
Build your own HalfKeyboard (tm).
Changed lines 1-2 from:
User-space Java Bluetooth (JSR-82) Keyboard Driver
to:
User-space Java Bluetooth (JSR-82) Keyboard Driver
Changed lines 5-8 from:
Motivation
Requirements
to:
Motivation
Requirements
Changed lines 11-13 from:
Explanation
Further Exploration
to:
Explanation
Further Exploration \\
Added line 17:
Added lines 1-15:
User-space Java Bluetooth (JSR-82) Keyboard Driver
... stay tuned!
Motivation
Requirements
- JSR-82 implementation, e.g., BlueCove
Explanation
Further Exploration Build your own HalfKeyboard (tm).
Changed line 164 from:
KeyEvent.VK_TAB, ' ', /* 42 - 44 */
to:
KeyEvent.VK_TAB, ' ', /* 42 - 44 */
Changed line 164 from:
KeyEvent.VK_TAB, ' ', /* 42 - 44 */
to:
KeyEvent.VK_TAB, ' ', /* 42 - 44 */
Changed line 163 from:
KeyEvent.VK_ENTER, 27, KeyEvent.VK_BACK_SPACE, /* 40 - 42 */
to:
KeyEvent.VK_ENTER, 27, KeyEvent.VK_BACK_SPACE, /* 40 - 42 */
Changed line 164 from:
KeyEvent.VK_TAB, ' ', /* 42 - 44 */
to:
KeyEvent.VK_TAB, ' ', /* 42 - 44 */
Changed line 166 from:
'.', '/', KeyEvent.VK_ENTER /* 55 - 57 */
to:
'.', '/', KeyEvent.VK_ENTER /* 55 - 57 */
Changed lines 165-166 from:
'-', '=', '[', ']', '\\', 0, ';', '\'', '`', ',' /* 45 - 54 */ '.', '/', KeyEvent.VK_ENTER /* 55 - 57 */
to:
'-', '=', '[', ']', '\\', 0, ';', '\'', '`', ',', /* 45 - 54 */ '.', '/', KeyEvent.VK_ENTER /* 55 - 57 */
Changed line 165 from:
'-', '=', '[', ']', '\\', 0, ';', '\'', '`', ',', /* 45 - 54 */
to:
'-', '=', '[', ']', '\\', 0, ';', '\'', '`', ',' /* 45 - 54 */
Changed lines 163-164 from:
KeyEvent.VK_ENTER, 27, KeyEvent.VK_BACK_SPACE, KeyEvent.VK_TAB, ' ', /* 40 - 44 */
to:
KeyEvent.VK_ENTER, 27, KeyEvent.VK_BACK_SPACE, /* 40 - 42 */ KeyEvent.VK_TAB, ' ', /* 42 - 44 */
Changed lines 94-95 from:
boolean ctrl_pressed, boolean alt_pressed, boolean command_pressed) throws AWTException {
to:
boolean ctrl_pressed, boolean alt_pressed, boolean command_pressed) throws AWTException {
Changed lines 163-164 from:
KeyEvent.VK_ENTER, 27, KeyEvent.VK_BACK_SPACE, KeyEvent.VK_TAB, ' ', /* 40 - 44 */
to:
KeyEvent.VK_ENTER, 27, KeyEvent.VK_BACK_SPACE, KeyEvent.VK_TAB, ' ', /* 40 - 44 */
Changed lines 83-85 from:
injectKey(new_key, shift_pressed, ctrl_pressed, alt_pressed, command_pressed);
to:
injectKey(new_key, shift_pressed, ctrl_pressed, alt_pressed, command_pressed);
Changed lines 93-94 from:
void injectKey(int new_key, boolean shift_pressed, boolean ctrl_pressed, boolean alt_pressed, boolean command_pressed) throws AWTException {
to:
void injectKey(int new_key, boolean shift_pressed, boolean ctrl_pressed, boolean alt_pressed, boolean command_pressed) throws AWTException {
Changed lines 93-94 from:
void injectKey(int new_key, boolean shift_pressed, boolean ctrl_pressed, boolean alt_pressed, boolean command_pressed) throws AWTException {
to:
void injectKey(int new_key, boolean shift_pressed, boolean ctrl_pressed, boolean alt_pressed, boolean command_pressed) throws AWTException {
Changed lines 149-150 from:
public static final int cursor_keys[] = { KeyEvent.VK_RIGHT, KeyEvent.VK_LEFT, KeyEvent.VK_DOWN, KeyEvent.VK_UP};
to:
public static final int cursor_keys[] = { KeyEvent.VK_RIGHT, KeyEvent.VK_LEFT, KeyEvent.VK_DOWN, KeyEvent.VK_UP };
Changed lines 83-84 from:
injectKey(new_key, shift_pressed, ctrl_pressed, alt_pressed, command_pressed);
to:
injectKey(new_key, shift_pressed, ctrl_pressed, alt_pressed, command_pressed);
Changed line 26 from:
+ kbAddr + ":13;authenticate=true;");
to:
+ kbAddr + ":13;authenticate=true;");
Changed lines 43-44 from:
void handlePacket(byte[] hidReport, int packetLen) throws IOException, AWTException {
to:
void handlePacket(byte[] hidReport, int packetLen) throws IOException, AWTException {
Changed line 15 from:
IOException{
to:
IOException {
Changed lines 25-26 from:
L2CAPConnection con = (L2CAPConnection) Connector.open("btl2cap://" + kbAddr + ":13;authenticate=true;");
to:
L2CAPConnection con = (L2CAPConnection) Connector.open("btl2cap://" + kbAddr + ":13;authenticate=true;");
Changed lines 12-15 from:
public static void main(String[] args) throws AWTException, InterruptedException, IOException{
to:
public static void main(String[] args) throws AWTException, InterruptedException, IOException{
Changed lines 12-165 from:
public static void main(String[] args) throws AWTException, InterruptedException, IOException { new BluetoothKeyboard().go(); } void go() throws IOException, AWTException { // allow connections to PSM below 0x1001 System.setProperty("bluecove.jsr82.psm_minimum_off", "true"); // connect L2CAPConnection con = (L2CAPConnection) Connector.open("btl2cap://" + kbAddr + ":13;authenticate=true;"); System.out.println("Connected"); // process reports byte hidReport[] = new byte[255]; while (true){ // get packet from L2CAP connection int packetLen = con.receive(hidReport); // dump report dumpBuffer(hidReport, packetLen); // process event handlePacket(hidReport, packetLen); } } void handlePacket(byte[] hidReport, int packetLen) throws IOException, AWTException { // decode keys, only process up to NUM_KEYS int modifier = hidReport[2]; int nrKeys = packetLen - 4; if (nrKeys > NUM_KEYS){ nrKeys = NUM_KEYS; } // modifier keys boolean ctrl_pressed = (modifier & 0x11) != 0; boolean shift_pressed = (modifier & 0x22) != 0; boolean alt_pressed = (modifier & 0x44) != 0; boolean command_pressed = (modifier & 0x88) != 0; // process events for (int i=0; i< nrKeys; i++){ // find key in last state int new_event = hidReport[4+i]; if (new_event == 0 || new_event == 44) continue; for (int j=0; j<NUM_KEYS; j++){ if (new_event == last_keyboard_state[j]){ new_event = 0; break; } } if (new_event == 0) continue; // get from table int new_key = 0; if (new_event <= 57){ new_key = keytable_us_none[new_event]; } else if (new_event >= 0x4f && new_event <= 0x52) { new_key = cursor_keys[ new_event - 0x4f]; } else { continue; } injectKey(new_key, shift_pressed, ctrl_pressed, alt_pressed, command_pressed); } // store keyboard state System.arraycopy(hidReport, 4, last_keyboard_state, 0, NUM_KEYS); last_modifier = modifier; } void injectKey(int new_key, boolean shift_pressed, boolean ctrl_pressed, boolean alt_pressed, boolean command_pressed) throws AWTException { // create Robot instance if necessary if (robot == null){ robot = new Robot(); } // use upper case chars char key = Character.toUpperCase((char) new_key); // set up modifier keys if (shift_pressed) { robot.keyPress(KeyEvent.VK_SHIFT); } if (ctrl_pressed) { robot.keyPress(KeyEvent.VK_CONTROL); } if (alt_pressed) { robot.keyPress(KeyEvent.VK_ALT); } if (command_pressed){ robot.keyPress(KeyEvent.VK_META); } // inject single press robot.keyPress(key); robot.keyRelease(key); // unset modifier keys if (command_pressed){ robot.keyRelease(KeyEvent.VK_META); } if (alt_pressed) { robot.keyRelease(KeyEvent.VK_ALT); } if (ctrl_pressed) { robot.keyRelease(KeyEvent.VK_CONTROL); } if (shift_pressed) { robot.keyRelease(KeyEvent.VK_SHIFT); } } public void dumpBuffer(byte[] data, int len){ System.out.print("DATA: "); for (int i=0;i<len;i++){ int value = data[i]; if (value<0){ value += 256; } System.out.print( Integer.toHexString(value) + " "); } System.out.println(); } public static final int cursor_keys[] = { KeyEvent.VK_RIGHT, KeyEvent.VK_LEFT, KeyEvent.VK_DOWN, KeyEvent.VK_UP}; public static int keytable_us_none [] = { 0, 0, 0, 0, /* 0-3 */ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', /* 4 - 13 */ 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', /* 14 - 23 */ 'u', 'v', 'w', 'x', 'y', 'z', /* 24 - 29 */ '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', /* 30 - 39 */ KeyEvent.VK_ENTER, 27, KeyEvent.VK_BACK_SPACE, KeyEvent.VK_TAB, ' ', /* 40 - 44 */ '-', '=', '[', ']', '\\', 0, ';', '\'', '`', ',', /* 45 - 54 */ '.', '/', KeyEvent.VK_ENTER /* 55 - 57 */ }; public static final int NUM_KEYS = 5; Robot robot; byte last_keyboard_state[] = new byte[NUM_KEYS]; int last_modifier = 0; // address of your keyboard public static final String kbAddr = "001b63fa61c3";
to:
public static void main(String[] args) throws AWTException, InterruptedException, IOException{ new BluetoothKeyboard().go(); } void go() throws IOException, AWTException { // allow connections to PSM below 0x1001 System.setProperty("bluecove.jsr82.psm_minimum_off", "true"); // connect L2CAPConnection con = (L2CAPConnection) Connector.open("btl2cap://" + kbAddr + ":13;authenticate=true;"); System.out.println("Connected"); // process reports byte hidReport[] = new byte[255]; while (true){ // get packet from L2CAP connection int packetLen = con.receive(hidReport); // dump report dumpBuffer(hidReport, packetLen); // process event handlePacket(hidReport, packetLen); } } void handlePacket(byte[] hidReport, int packetLen) throws IOException, AWTException { // decode keys, only process up to NUM_KEYS int modifier = hidReport[2]; int nrKeys = packetLen - 4; if (nrKeys > NUM_KEYS){ nrKeys = NUM_KEYS; } // modifier keys boolean ctrl_pressed = (modifier & 0x11) != 0; boolean shift_pressed = (modifier & 0x22) != 0; boolean alt_pressed = (modifier & 0x44) != 0; boolean command_pressed = (modifier & 0x88) != 0; // process events for (int i=0; i< nrKeys; i++){ // find key in last state int new_event = hidReport[4+i]; if (new_event == 0 || new_event == 44) continue; for (int j=0; j<NUM_KEYS; j++){ if (new_event == last_keyboard_state[j]){ new_event = 0; break; } } if (new_event == 0) continue; // get from table int new_key = 0; if (new_event <= 57){ new_key = keytable_us_none[new_event]; } else if (new_event >= 0x4f && new_event <= 0x52) { new_key = cursor_keys[ new_event - 0x4f]; } else { continue; } injectKey(new_key, shift_pressed, ctrl_pressed, alt_pressed, command_pressed); } // store keyboard state System.arraycopy(hidReport, 4, last_keyboard_state, 0, NUM_KEYS); last_modifier = modifier; } void injectKey(int new_key, boolean shift_pressed, boolean ctrl_pressed, boolean alt_pressed, boolean command_pressed) throws AWTException { // create Robot instance if necessary if (robot == null){ robot = new Robot(); } // use upper case chars char key = Character.toUpperCase((char) new_key); // set up modifier keys if (shift_pressed) { robot.keyPress(KeyEvent.VK_SHIFT); } if (ctrl_pressed) { robot.keyPress(KeyEvent.VK_CONTROL); } if (alt_pressed) { robot.keyPress(KeyEvent.VK_ALT); } if (command_pressed){ robot.keyPress(KeyEvent.VK_META); } // inject single press robot.keyPress(key); robot.keyRelease(key); // unset modifier keys if (command_pressed){ robot.keyRelease(KeyEvent.VK_META); } if (alt_pressed) { robot.keyRelease(KeyEvent.VK_ALT); } if (ctrl_pressed) { robot.keyRelease(KeyEvent.VK_CONTROL); } if (shift_pressed) { robot.keyRelease(KeyEvent.VK_SHIFT); } } public void dumpBuffer(byte[] data, int len){ System.out.print("DATA: "); for (int i=0;i<len;i++){ int value = data[i]; if (value<0){ value += 256; } System.out.print( Integer.toHexString(value) + " "); } System.out.println(); } public static final int cursor_keys[] = { KeyEvent.VK_RIGHT, KeyEvent.VK_LEFT, KeyEvent.VK_DOWN, KeyEvent.VK_UP}; public static int keytable_us_none [] = { 0, 0, 0, 0, /* 0-3 */ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', /* 4 - 13 */ 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', /* 14 - 23 */ 'u', 'v', 'w', 'x', 'y', 'z', /* 24 - 29 */ '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', /* 30 - 39 */ KeyEvent.VK_ENTER, 27, KeyEvent.VK_BACK_SPACE, KeyEvent.VK_TAB, ' ', /* 40 - 44 */ '-', '=', '[', ']', '\\', 0, ';', '\'', '`', ',', /* 45 - 54 */ '.', '/', KeyEvent.VK_ENTER /* 55 - 57 */ }; public static final int NUM_KEYS = 5; Robot robot; byte last_keyboard_state[] = new byte[NUM_KEYS]; int last_modifier = 0; // address of your keyboard public static final String kbAddr = "001b63fa61c3";
Changed lines 12-15 from:
public static void main(String[] args) throws AWTException, InterruptedException, IOException{
to:
public static void main(String[] args) throws AWTException, InterruptedException, IOException {
Added lines 1-165:
import java.awt.AWTException; import java.awt.Robot; import java.awt.event.KeyEvent; import java.io.IOException; import javax.bluetooth.L2CAPConnection; import javax.microedition.io.Connector; public class BluetoothKeyboard { public static void main(String[] args) throws AWTException, InterruptedException, IOException{ new BluetoothKeyboard().go(); } void go() throws IOException, AWTException { // allow connections to PSM below 0x1001 System.setProperty("bluecove.jsr82.psm_minimum_off", "true"); // connect L2CAPConnection con = (L2CAPConnection) Connector.open("btl2cap://" + kbAddr + ":13;authenticate=true;"); System.out.println("Connected"); // process reports byte hidReport[] = new byte[255]; while (true){ // get packet from L2CAP connection int packetLen = con.receive(hidReport); // dump report dumpBuffer(hidReport, packetLen); // process event handlePacket(hidReport, packetLen); } } void handlePacket(byte[] hidReport, int packetLen) throws IOException, AWTException { // decode keys, only process up to NUM_KEYS int modifier = hidReport[2]; int nrKeys = packetLen - 4; if (nrKeys > NUM_KEYS){ nrKeys = NUM_KEYS; } // modifier keys boolean ctrl_pressed = (modifier & 0x11) != 0; boolean shift_pressed = (modifier & 0x22) != 0; boolean alt_pressed = (modifier & 0x44) != 0; boolean command_pressed = (modifier & 0x88) != 0; // process events for (int i=0; i< nrKeys; i++){ // find key in last state int new_event = hidReport[4+i]; if (new_event == 0 || new_event == 44) continue; for (int j=0; j<NUM_KEYS; j++){ if (new_event == last_keyboard_state[j]){ new_event = 0; break; } } if (new_event == 0) continue; // get from table int new_key = 0; if (new_event <= 57){ new_key = keytable_us_none[new_event]; } else if (new_event >= 0x4f && new_event <= 0x52) { new_key = cursor_keys[ new_event - 0x4f]; } else { continue; } injectKey(new_key, shift_pressed, ctrl_pressed, alt_pressed, command_pressed); } // store keyboard state System.arraycopy(hidReport, 4, last_keyboard_state, 0, NUM_KEYS); last_modifier = modifier; } void injectKey(int new_key, boolean shift_pressed, boolean ctrl_pressed, boolean alt_pressed, boolean command_pressed) throws AWTException { // create Robot instance if necessary if (robot == null){ robot = new Robot(); } // use upper case chars char key = Character.toUpperCase((char) new_key); // set up modifier keys if (shift_pressed) { robot.keyPress(KeyEvent.VK_SHIFT); } if (ctrl_pressed) { robot.keyPress(KeyEvent.VK_CONTROL); } if (alt_pressed) { robot.keyPress(KeyEvent.VK_ALT); } if (command_pressed){ robot.keyPress(KeyEvent.VK_META); } // inject single press robot.keyPress(key); robot.keyRelease(key); // unset modifier keys if (command_pressed){ robot.keyRelease(KeyEvent.VK_META); } if (alt_pressed) { robot.keyRelease(KeyEvent.VK_ALT); } if (ctrl_pressed) { robot.keyRelease(KeyEvent.VK_CONTROL); } if (shift_pressed) { robot.keyRelease(KeyEvent.VK_SHIFT); } } public void dumpBuffer(byte[] data, int len){ System.out.print("DATA: "); for (int i=0;i<len;i++){ int value = data[i]; if (value<0){ value += 256; } System.out.print( Integer.toHexString(value) + " "); } System.out.println(); } public static final int cursor_keys[] = { KeyEvent.VK_RIGHT, KeyEvent.VK_LEFT, KeyEvent.VK_DOWN, KeyEvent.VK_UP}; public static int keytable_us_none [] = { 0, 0, 0, 0, /* 0-3 */ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', /* 4 - 13 */ 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', /* 14 - 23 */ 'u', 'v', 'w', 'x', 'y', 'z', /* 24 - 29 */ '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', /* 30 - 39 */ KeyEvent.VK_ENTER, 27, KeyEvent.VK_BACK_SPACE, KeyEvent.VK_TAB, ' ', /* 40 - 44 */ '-', '=', '[', ']', '\\', 0, ';', '\'', '`', ',', /* 45 - 54 */ '.', '/', KeyEvent.VK_ENTER /* 55 - 57 */ }; public static final int NUM_KEYS = 5; Robot robot; byte last_keyboard_state[] = new byte[NUM_KEYS]; int last_modifier = 0; // address of your keyboard public static final String kbAddr = "001b63fa61c3"; }