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);
}
Good day, sir.
Let me kindly point to you to a humble holiday timewaster of mine that actually is able to be used with a piece of junk called iPad, whose software stack should be reasonable close to iPhone of yours: https://github.com/lkundrak/virtkbd
Aside from the actual implementation, I'll try to answer your questions.
Question 1:
Given the quality and length of Bluetooth HID profile specification, USB HID one and tooling available and actual device specifics, I guess trial and error will take you further. Have an actual Bluetooth keyboard, and write a simple protocol repeater and dumper to let you observe what do they do -- refer to documentation to decrypt what's going on.
Question 2:
Right. For my iPad, I first need to pair the devices with my computer not being of a Keyboard class (my guess is that iPad otherwise attempts to make me enter a PIN, which can not be done with Bluez). Then I need to change the class to Keyboard (by running my bithdd program) and force iPad to reconnect, so that it grabs the protocol descriptor from SDP and attempts to connect to L2CAP ports 17 and 19.
Question 3:
Yes, it's pretty much like that -- I don't think you miss anything important.
Have a nice day!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With