I am trying to send keystrokes via bluetooth to my iPhone4 from ubuntu. I.e., developing a very primitive virtual keyboard.
Problem Have my application talk to iPhone (i.e. using report protocol, that's all iPhone supports). As it is, my write(interruptChannelFD)
calls return no errors, but
no text appears on iPhone side. The l2cap channels have been opened using blueZ library.
Question 1: Given that no virtual keyboard exists that does that, just how hard is it?
I am at the stage where iPhone and my linux box connect and stay connected, no problem.
Also, all the perror()
calls are telling me that control and interrupt channel sockets connect just fine. (What I do is hciconfig my dongle to Keyboard device class and use the
well-known code by Collin Mulliner with slight modification -- I had to enter a passcode once, as all smartphones require).
Question 2: I should be able to just write()
into interrupt socket without worrying about encryption, right? I've entered the passcode and the phone trusts the keyboard. (Collin was pondering a possible hid attack, but I connect honestly)
Also, it is my understanding that in boot protocol of a HID device, the exact report descriptor specfied in SPD is hardly relevant -- the report format is fixed anyway. So...
Question 3: Do I miss something major about the report protocol. What I do is modify the Apple keyboard report descriptor and write into the socket (see below).
const uint8_t hid_spec[] = {
0x05, 0x01, // usage page
0x09, 0x06, // keyboard
0xa1, 0x01, // collection (Application)
0x85, 0x01, // report id (0x01)
0x05, 0x07, // usage page(keyboard)
0x19, 0xe0, // usage min
0x29, 0xe7, // usage max
0x15, 0x00, // logical min
0x25, 0x01, // logical max
0x75, 0x01, // report size
0x95, 0x08, // report count
0x81, 0x02, // input (dat var abs)
0x75, 0x08, // report size
0x95, 0x01, // report count
0x81, 0x01, // input (const)
// The following two outputs I don't seem to receive
0x75, 0x01, // report size
0x95, 0x05, // report count
0x05, 0x08, // usage page (LEDs)
0x19, 0x01, // usage min
0x29, 0x05, // usage max
0x91, 0x02, // OUTPUT1 (dat var abs)
0x75, 0x03,
0x95, 0x01,
0x91, 0x01, // OUTPUT2 (arr,const)
0x75, 0x08, // report size
0x95, 0x06, // report count
0x15, 0x00, // logical min
0x26, 0xff, 0x00 // logical max
0x05, 0x07
0x19, 0x00
0x2a, 0xff, 0x00,
0x81, 0x00,
// A total of 9 bits sent by now
// I tried remove the following fields
/********** BEGIN SNIP
0x75, 0x01,
0x95, 0x01,
0x15, 0x00,
0x25, 0x01,
0x05, 0x0c,
0x09, 0xb8,
0x81, 0x06,
0x09, 0xe2,
0x81, 0x06,
0x09, 0xe9,
0x81, 0x02,
0x09, 0xea,
0x81, 0x02,
0x75, 0x01,
0x95, 0x04,
0x81, 0x01,
**** END SNIP/
0xc0 // end coll
};
After this, I write the following 10 bytes into the interrupt channel:
pkg[0] = 0xa1; // BT HDR (DATA)
pkg[1] = 0x01; // REPORT ID 0x1 == kbd
pkg[2] = modifiers; // Ctrl, Shift, etc
pkg[3] = 0x00; // constant 0 (see descr)
// pkg[4] = 0x00; // the key code - entered before this point, according to HID usage tables.
pkg[5] = 0x00;
pkg[6] = 0x00;
pkg[7] = 0x00;
pkg[8] = 0x00;
pkg[9] = 0x00;
if (write(is, pkg, 10) <= 0) {
perror("write");
exit(-1);
}
org.bluez.Agent
RequestPinCode
(ie. You need to register as an agent viaorg.bluez.Adapter
RegisterAgent
). You also shouldn't have to enter a PIN if you're using a 2.1 Bluetooth device (since those allow Secure Simple Pairing) – Trillbee