简体   繁体   中英

How to talk to a Bluetooth keyboard?

I've written an Android app that connects to a Bluetooth keyboard. It connects through a BT socket to the keyboard and acquires the socket's input stream.

InputStream inStrm = socket.getInputStream();

Next I tried to read the input stream, but it says there are no bytes available.

int nBytesAvail = inStrm.available(); // always gives me 0

Or

int  dataByte = inStrm.read(); // always generates IOException

The exception says: Software caused connection to abort

If I try to write to the stream, I get another exception: Transport endpoint is not connected.

One of two things can be happening.

  1. My first fear is that there is the HID protocol to be spoken to the keyboard, and it will not divulge its secrets until I utter the proper incantation. Is that correct? Or should that be taken care of by the BT socket stack automatically? The socket stream seems to be a standard serial stream, and I'm not sure that's correct.

  2. My second fear is that since this is a Galaxy Tab, my problem might simply be that that particular part of the OS has been removed by Samsung (but would I still get a valid input stream from the socket connection?). It is widely reported that the US versions of the Tab simply will not connect to any BT HID using the standard Android BT utilities, although BT file transfers do work fine.

I suppose a third possibility is that I'm simply missing the keystrokes as they happen. I don't know how much buffering Java does of BT data coming in from a HID, but if the socket connection is made, the data should appear in the input stream, no?

I'm reluctant to put in much more time into this in case I'm going about it completely the wrong way (see #1), or it is doomed to fail (see #2).

All normal Bluetooth keyboards implement the HID profile, which requires an L2CAP connection. Android so far only provides the ability to use RFCOMM connections. You would need to use the Native Development Kit and write your keyboard code in C to using bluez to achieve your goal. Have a look at apps that use the Nintendo WiiMote. The WiiMote also implements the HID profile.

mringwal's answer is correct, besides the NDK approach, it is possible to use reflection on some devices, to achieve L2CAP connectivity:

public static BluetoothSocket createL2CAPBluetoothSocket(String address, int psm){
        return createBluetoothSocket(TYPE_L2CAP, -1, false,false, address, psm);
    }
    // method for creating a bluetooth client socket
    private static BluetoothSocket createBluetoothSocket(
            int type, int fd, boolean auth, boolean encrypt, String address, int port){
        try {
            Constructor<BluetoothSocket> constructor = BluetoothSocket.class.getDeclaredConstructor(
                    int.class, int.class,boolean.class,boolean.class,String.class, int.class);
            constructor.setAccessible(true);
            BluetoothSocket clientSocket = (BluetoothSocket) 
                constructor.newInstance(type,fd,auth,encrypt,address,port);
            return clientSocket;
        }catch (Exception e) { return null; }
    }

where TYPE_L2CAP is an integer having the constant value 3.

Note that this approach will only work on SOME android devices.

Writing a HID application is not a simple task. You need to implement a Report descriptor parser, a component used to "discover" the capabilities (special keys, functions) of a remote HID device. You will also need to learn the HID protocol and work flow , a copy is available here: http://www.dawidurbanski.pl/public/download/projekty/bluepad/HID_SPEC_V10.pdf

There are already professional programs doing exactly that, supporting HID on Android, see for example this software: http://teksoftco.com/index.php?section=product&pid=24

Because of Stack limitations, the L2CAP protocol is not available on all devices, so a solution that works on ALL devices is currently impossible.

Some Galaxy Tabs support the HID protocol, some don't. It depends on the carrier, not on Samsung. My Verizon Galaxy Tab came without HID support even though the T-Mobile ones had it. But in April of this year Verizon (not Samsung) pushed out a firmware upgrade that included HID support so my BT keyboard & mouse started working. I'm running Android 2.2, and my firmware build number is SCH-I800.EC02.

It's my guess that you're trying to do this because your Tab won't connect to the BT keyboard at all. This is exactly what I was trying to do before April. From what I remember reading, the magic incantation part is supposed to be handled by Android automatically: when you make the HID connection, Android pops up a message window to enter a code on the keyboard, then the socket connection is returned to your program (or something to that effect).

So if you can't get the Tab to connect to the keyboard normally, then your HID profile has been disabled and (afaik) no amount of programming will make it work, except maybe a rewrite of the HID profile in Java.

I'm sure you tried this already, but to test it go to Settings > Wireless and Networks > Blutetooth settings, you should see the keyboard in the list whether or not you have HID support. Tap the keyboard entry, it should connect right away. If it just delays indefinitely or if you get an error message, then you have no HID support.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM