androidusbmousemouseeventusb-otg

Reading raw mouse data on android


In my Android app, I read the values from a 3DConnexion SpaceNavigator via USB-OTG to control an AR.Drone.

Now I want to do the same with a mouse. However, Android is grabbing the mouse and presenting a mouse-cursor. When I write a device-filter with the vendor and product ID of the mouse, I do not get it like with the SpaceNavigator (strangely, both are HID -- I get no cursor with the SpaceNavigator).

Is there a way to get the raw mouse data without the cursor?

Would be perfect with stock Android. but I would also consider altering the ROM for that.


Solution

  • As soon as your Application claims the Mouse (as a USB HID device while being Host), Android should hide the cursor and you can read the raw data. This should work on stock android, but your device has to support USB Host mode and a USB OTG cable will be needed to connect the mouse.

    Basic procedure:

    Example Code that works for me (Android 5.0):

    UsbManager usbManager;
    UsbDevice usbDevice;
    
    private void connect() {
        this.usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
        HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();
    
        // just get the first enumerated USB device
        Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
        if (deviceIterator.hasNext()) {
            this.usbDevice = deviceIterator.next();
        }
    
        if (usbDevice == null) {
            Log.w(TAG, "no USB device found");
            return;
        }
    
        // ask for permission
    
        final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";
        final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
    
            public void onReceive(Context context, Intent intent) {
                String action = intent.getAction();
                if (ACTION_USB_PERMISSION.equals(action)) {
                    synchronized (this) {
                        UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
    
                        if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                            if(device != null){
                                // call method to set up device communication
                                Log.i(TAG, "permission granted. access mouse.");
    
                                // repeat in a different thread
                                transfer(device);
                            }
                        }
                        else {
                            Log.d(TAG, "permission denied for device " + device);
                        }
                    }
                } else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
                    UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                    if (device != null) {
                        // TODO:
                        // call your method that cleans up and closes communication with the device
                        // usbInterface.releaseInterface();
                        // usbDeviceConnection.close();
                    }
                }
            }
        };
    
        PendingIntent mPermissionIntent = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0);
        IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
        context.registerReceiver(mUsbReceiver, filter);
    
        usbManager.requestPermission(usbDevice, mPermissionIntent);
    }
    
    private void transfer(UsbDevice device) {
    
        int TIMEOUT = 0;
        boolean forceClaim = true;
    
        // just grab the first endpoint
        UsbInterface intf = device.getInterface(0);
        UsbEndpoint endpoint = intf.getEndpoint(0);
        UsbDeviceConnection connection = this.usbManager.openDevice(device);
        connection.claimInterface(intf, forceClaim);
    
        byte[] bytes = new byte[endpoint.getMaxPacketSize()];
    
        connection.bulkTransfer(endpoint, bytes, bytes.length, TIMEOUT);
    
        // depending on mouse firmware and vendor the information you're looking for may
        // be in a different order or position. For some logitech devices the following 
        // is true:
    
        int x = (int) bytes[1];
        int y = (int) bytes[2];
        int scrollwheel = (int) bytes[3]
    
        // call a listener, process your data ...
    }