Mobile and Handhelds · Volume 1

How Android Sees the Gun — The Rule That Drops an Absolute Mouse, and What Survives

What an Android phone, tablet, TV box or handheld does with an OpenFIRE gun plugged into its USB port: the one test in Android's input reader that decides whether a pointing device is a mouse, why the gun's absolute mouse fails it, what the keyboard and gamepad halves still deliver, what Sinden found when it tried, the port's power, and how to check a device on the bench

Figure 1 — A Sinden light gun beside an Ayaneo 2S, a Windows handheld, with Steam open on The House of the Dead: Remake. A handheld PC is the easiest small machine to run a light gun from, because it is a PC;…
Figure 1 — A Sinden light gun beside an Ayaneo 2S, a Windows handheld, with Steam open on The House of the Dead: Remake. A handheld PC is the easiest small machine to run a light gun from, because it is a PC; a phone or an Android handheld is the hardest, for the reason this volume sets out. The Sinden finds the screen by a white border drawn around the picture; the OpenFIRE gun this dive is about finds it by infrared emitters instead. Photo: Phil Hayton / GamesRadar+ (Future).

1.1 What this dive covers

The Platform Support dives each take the project’s gun (a Raspberry Pi Pico running a private fork of OpenFIRE, a PixArt infrared camera aimed at emitters around the screen, a regulated 24 V solenoid on its own brick) to one kind of host. PC-Windows is the reference; Linux and Retro Distros covers the Raspberry Pi, Batocera and the Steam Deck; MiSTer FPGA, Arcade Hardware and Original Consoles cover the rest.

This dive covers what is left: phones, tablets and television boxes running Android; iPhones, iPads and the Apple TV; Windows and Linux handheld PCs and the small Linux handhelds; and the Nintendo Switch. The answer differs sharply between them, and the reason is almost always the same question: does the operating system accept an absolute pointing device as a pointer? Windows and desktop Linux do. Android, as shipped, does not, and the next three sections show the line of source code that decides it.

The plan:

Table 1 — The plan

VolCovers
1Android’s input stack and the gun (this volume)
2Getting the gun into Android games anyway: gamepad mode, a touchscreen mode for the fork, the emulators, TV boxes and Android handhelds
3Apple (iPad, iPhone, Apple TV) and Nintendo Switch: why there is no route, and what exists instead
4Handheld PCs and Linux handhelds: Windows handhelds, Knulli and ROCKNIX, the port’s power budget, docks
5Screen size, docking and casting, calibration per display, and the “where it runs” table

Nothing in this dive has been run with the project’s gun, which is not built yet. Where a bench result belongs, a marker says what to capture.

1.2 The gun, as a USB device

The gun enumerates as one USB device (vendor ID 0xF143, manufacturer “OpenFIRE”) with a HID interface carrying three report types and a CDC serial interface. Open-Source Firmware, Volume 6 has the full account; what matters here is the shape of the mouse. The report descriptor in OpenFIRE’s TinyUSB_Devices.h (TUD_HID_REPORT_DESC_ABSMOUSE5) declares a Generic Desktop Mouse application containing five buttons and an X and a Y, each 16 bits, logical range 0 to 32767, both flagged Absolute. There is no wheel and no relative axis of any kind.

On a Linux kernel, and every Android device runs one, hid-input turns that collection into an input device whose capabilities are: key codes BTN_LEFT through BTN_EXTRA (0x110–0x114), and absolute axes ABS_X and ABS_Y. The keyboard collection becomes a second input device with ordinary key codes, and the gamepad collection a third, with gamepad buttons, two sticks and a hat. Linux and Retro Distros, Volume 1 shows the same three nodes on a desktop. Android sees exactly the same three /dev/input/event nodes; what differs is the layer above the kernel that decides what to do with them.

1.3 Android’s input reader and the cursor test

Android does not use libinput, X or Wayland. Its input stack is inputflinger, and the component that opens each event node and decides what kind of device it is lives in EventHub.cpp. The classification, read in AOSP’s main branch on 24 October 2026, is a series of tests on the device’s capability bits. The one that matters:

// See if this is a cursor device such as a trackball or mouse.
if (device->keyBitmask.test(BTN_MOUSE) && device->relBitmask.test(REL_X) &&
    device->relBitmask.test(REL_Y)) {
    device->classes |= InputDeviceClass::CURSOR;
}

A device is a mouse, to Android, only if it has the left button and relative X and Y. The following tests look for touch devices: a multi-touch screen reports ABS_MT_POSITION_X/Y; an old-style single-touch screen reports BTN_TOUCH with ABS_X and ABS_Y. Keyboards are recognised by key codes below BTN_MISC or above BTN_WHEEL, and gamepads by buttons in the BTN_MISC and BTN_JOYSTICK ranges. Then:

// If the device isn't recognized as something we handle, don't monitor it.
if (device->classes == ftl::Flags<InputDeviceClass>(0)) {
    ALOGV("Dropping device: id=%d, path='%s', name='%s'", ...);
    return;
}

The cursor mapper that turns a mouse’s events into pointer motion (CursorInputMapper.cpp) has no code for absolute axes at all; the word does not occur in it.

Figure 2 — How Android's input reader classifies each of the three devices an OpenFIRE gun presents. The keyboard and gamepad pass ordinary tests and are kept. The absolute mouse has the left button but no re…
Figure 2 — How Android's input reader classifies each of the three devices an OpenFIRE gun presents. The keyboard and gamepad pass ordinary tests and are kept. The absolute mouse has the left button but no relative axes, so it is not a cursor; it has X and Y but no touch key, so it is not a touchscreen; its buttons fall outside both the keyboard and gamepad ranges. Nothing claims it, and the reader drops it. Own-work diagram from AOSP EventHub.cpp, main branch, read 24 October 2026.

1.4 Applying the test to the gun’s three devices

Table 2 — 1.4 Applying the test to the gun's three devices

Gun deviceCapabilitiesCursor?Touch?Keyboard or gamepad?Result
Keyboardordinary key codes (Start “1”, Select “5”, arrows)nonokeyboardkept: keys reach apps
Absolute mouseBTN_LEFT…BTN_EXTRA, ABS_X, ABS_Yno (no REL_X/Y)no (no BTN_TOUCH)no (0x110–0x114 is in neither range)dropped
Gamepadgamepad buttons, two sticks, hatnonogamepad and joystickkept: buttons and sticks reach apps

So on an Android device as shipped, an OpenFIRE gun in its default mode delivers its Start and Select keys and nothing else of use. The aim and the trigger both live on the mouse device (the trigger is the left mouse button in the firmware’s default table, Open-Source Firmware, Volume 6), and the mouse device never leaves the input reader. No app sees a cursor; there is nothing to configure in RetroArch, because RetroArch never receives an event.

This is an inference from source, not a test: no account of an OpenFIRE gun plugged into an Android device was found. It is a strong inference, because the code path is short and unconditional, and because two independent sources (next section) report exactly the behaviour it predicts. The bench check in section 1.10 settles it in two commands.

Two things survive that matter for Volume 2. The gamepad device is fully usable: OpenFIRE can put the aim point on an analog stick in its gamepad mode, and Android passes sticks to apps per device. And the keyboard is usable, so Start and Select work in any mode.

1.5 What other people found

An Arduino absolute mouse, 2020. In the issue tracker of NicoHood’s HID library for Arduino, a user reported on 10 October 2020 that the library’s absolute-mouse example “did work w/ Ubuntu 20 but not with Android 8.0/9.0 nor ios14”. A month later two users reported that a multi-touch digitizer descriptor (a sketch named Touchy.ino) worked on Android 10 and Android 7.0. That is the classification rule seen from outside: the absolute mouse fails the cursor test; a digitizer passes the touch test.

Sinden’s Android driver, 2022. Sinden’s own Android readme (in AndroidBeta.zip, dated 6 September 2022) says: “My early investigations made me think that absolute mouse support in Android emulators is poor so I have also added joystick support to Sinden Lightgun.” Its firmware v1.09 added a joystick mode for that reason, and the Android package ships four builds: absolute mouse or joystick, each with manual or automatic start. Sinden put the blame on the emulators; the source above suggests that for a mouse with no relative axes the operating system drops it before any emulator could try.

Android-x86, 2018. The Android-x86 project, a port of Android to PCs, carried its own patch to inputflinger titled “treat tablet-style inputs as absolute coordinate mouse pointer” (commit 6084c3ff, 26 December 2018), which classifies a device with BTN_MOUSE, ABS_X, ABS_Y and a wheel as a cursor, so that virtual machines’ absolute pointers would work. It exists because stock AOSP does not do this, and it was never part of AOSP; the main branch read for this volume has no such test. It also would not help the gun, which has no wheel.

1.6 What a configuration file can and cannot change

Android reads per-device input configuration files (.idc) matched by vendor and product ID, and they are the usual way to tune a touchscreen. They cannot rescue the gun’s mouse. The only device.type values EventHub acts on before classification are rotaryEncoder and externalStylus; the touch settings (touch.deviceType = pointer and the like) apply only to a device already classified as touch. The system’s .idc directories are read-only without root in any case.

What would work, in order of how much of the device it takes over:

Table 3 — What would work, in order of how much of the device it takes over

RouteWhat it doesCost
Gun in gamepad modeAim on a stick; Android passes it to appsOnly apps that can treat a stick as an absolute pointer (Volume 2)
A touchscreen report in the gun’s firmwareAndroid classifies it as an external touchscreenA firmware change in the private fork; touch, not mouse, semantics (Volume 2)
An app that reads the device directlyUsbManager lets an app claim a USB interface, but the HID interface is held by the kernel’s driverOnly the CDC serial interface is realistically claimable without root
A patched inputflinger or kernelAs Android-x86 didA custom ROM; outside this project
Root and a userspace bridgeRead the event node, inject touchRoot; per-device; fragile

1.7 Bluetooth does not change the answer

The same classification applies to a Bluetooth HID device: the Bluetooth stack hands Android a uhid input device built from the same report descriptor, and EventHub tests its bits in the same way. OpenFIRE’s source does contain a Bluetooth Classic HID path for the Pico W (TinyUSBDevices_::beginBT() in TinyUSB_Devices.cpp, advertising itself with class-of-device 0x2580, a mouse), and its Bluetooth report map carries the same absolute mouse. It would be dropped for the same reason. Open-Source Firmware, Volume 6 records that OpenFIRE ships only -noBT Pico W builds because Bluetooth is a known issue in its README, so this is academic for now; the radio options the project is actually trialling are in Fully Wireless, and they arrive at the host as a USB dongle, which brings the question straight back to section 1.4.

1.8 The other guns on Android: Sinden, GUN4IR, AimTrak

Table 4 — 1.8 The other guns on Android: Sinden, GUN4IR, AimTrak

GunWhat reaches AndroidStatus found
Sinden (border camera)A UVC camera plus a serial port, processed by Sinden’s own app into a mouse or joystick”A very raw beta” (Sinden’s driver page); needs Android 9+, a kernel with V4L2 USB video support (“I do not know any way to add these without a Kernel rebuild”), and probably setenforce 0 and chmod 777 on the device nodes after every re-plug. “The device being rooted would strongly help.” Two guns may need a kernel patch for USB bandwidth. Runs the camera at 320 × 240. Sinden’s FAQ lists Android as not supported.
GUN4IRAn absolute mouse by default, with gamepad and keyboard modesSame classification as OpenFIRE: mouse dropped, gamepad kept. No Android account found.
AimTrak (Ultimarc), Bluetooth versionA Bluetooth “composite-HID-over-GATT” device that “should show as an additional HID mouse”Ultimarc’s Bluetooth guide lists Android and iOS “All recent versions” as tested hosts. That is a connectivity statement: whether its pointer is absolute and what an emulator does with it are not stated. The Bluetooth upgrade kit “does not support recoil”.

The Sinden is the instructive one. Because it does its image processing on the host, it needs a camera driver and raw device access on Android, which is a far higher bar than an infrared gun that computes its own aim point. An OpenFIRE gun needs nothing from Android but acceptance of one HID device, and that one acceptance is exactly what fails. Border tracking’s host dependence is covered in Border Tracking, Volume 1.

1.9 Power from a phone’s port

The gun’s electronics draw about 0.75 W, 150 mA at 5 V, by the estimate in Power Supplies, Volume 1, and the solenoid runs from its own 24 V brick by decision D17 (no USB-only gun). So the only question for a phone is whether its port supplies 150 mA, and any USB host port must: 100 mA before configuration and 500 mA after on USB 2.0 (Power Supplies, Volume 3 has the table). The questions that do bite on a phone are different:

  • One port. A phone or Android handheld usually has one USB-C port, used both to charge and to host the gun. A USB-C hub with a power-delivery input lets the device charge while it hosts, but only if the device accepts being a power sink and a data host at once; most current phones do, not all, and the only test is the device in hand.
  • The 24 V brick still needs a wall. A phone on a table with a mains-powered gun beside it is not portable. A battery inside the gun, with only a thin USB lead to the host, is the Wireless Power Only architecture; the cell and charger are LiPo Batteries.
  • Sinden’s recoil gun is different. Sinden’s own documentation says “each recoil lightgun requires a continual draw of 500mA” from USB (quoted in Border Tracking), which a phone may refuse or brown out on. The project’s gun avoids this by design.

1.10 Checking a device on the bench

Two commands over adb settle section 1.4 for any given Android device, phone, TV box or handheld. With the gun plugged in:

adb shell getevent -p          # lists every event node with its capability bits
adb shell dumpsys input        # lists the devices inputflinger kept, with their classes

The expected result: getevent -p shows three nodes named “OpenFIRE FIRECon P1 Keyboard”, “OpenFIRE FIRECon P1 Mouse” and “OpenFIRE FIRECon P1” (for the App’s first preset), the mouse with KEY (0001): 0110 0111 0112 0113 0114 and ABS (0003): 0000 0001; dumpsys input lists the keyboard and the gamepad under its event hub devices and does not list the mouse. If the mouse is listed, the device’s vendor has patched inputflinger, and the rest of this dive should be re-read with that in mind.

1.11 Why this, and why not the others

This volume chooses no part. It sets a constraint for the firmware and for every later volume: on Android, the gun must arrive as a gamepad or a touchscreen, not as a mouse. The alternatives considered:

Table 5 — This volume chooses no part. It sets a constraint for the firmware and for every later volume: on Android, the gun must arrive as a gamepad or a touchscreen, not as a mouse. The alternatives considered

ApproachVerdictWhy
Rely on the absolute mouseRejectedAOSP drops it (section 1.3); no configuration file can change that (1.6)
Add a relative mouse to the firmwareRejectedAndroid would accept it, but would apply pointer acceleration and let the cursor drift from the aim point; a light gun’s whole point is an absolute position
Gamepad modeVolume 2 route 1Kept by Android; needs an app that maps a stick to a pointer
A touchscreen reportVolume 2 route 2Kept by Android as an external touchscreen; needs a firmware change
Custom ROM or rootOut of scopePer-device, and nothing a kit buyer could be asked to do

1.12 What could not be verified

  • Any Android device’s actual behaviour with an OpenFIRE gun (section 1.10 is the test).
  • Whether any phone or TV-box vendor has modified EventHub classification; Android-x86’s patch shows it can be done.
  • The “absolute mouse fails on Android 8/9” report is one user’s, from 2020; the source read is from 2026.
  • Whether Ultimarc’s Bluetooth AimTrak reports absolute or relative coordinates.
  • Which current phones accept charging through a hub while hosting a device.

Sources

  1. AOSP, frameworks/native, services/inputflinger/reader/EventHub.cpp and mapper/CursorInputMapper.cpp, branch main, https://android.googlesource.com/platform/frameworks/native/+/refs/heads/main/services/inputflinger/reader/ — read 2026-10-24.
  2. TeamOpenFIRE, OpenFIRE-Firmware, libraries/TinyUSB_Devices/TinyUSB_Devices.h (TUD_HID_REPORT_DESC_ABSMOUSE5) and TinyUSB_Devices.cpp (beginBT), https://github.com/TeamOpenFIRE/OpenFIRE-Firmware — read 2026-10-24.
  3. NicoHood, HID, issue #123 “Capacitive Touch Screen Emulation”, comments of 10 October, 6 November and 9 November 2020, https://github.com/NicoHood/HID/issues/123 — read 2026-10-24.
  4. Sinden Technology, “Driver Software”, https://sindenlightgun.com/drivers/, and AndroidBeta.zip, readme.txt dated 6 September 2022 — read 2026-10-24.
  5. Android-x86, frameworks/native commit 6084c3ff, “inputflinger: treat tablet-style inputs as absolute coordinate mouse pointer”, 26 December 2018 (listing on osdn.net; the commit page itself was not opened).
  6. Ultimarc, Bluetooth Light Gun (AimTrak Bluetooth guide), https://www.ultimarc.com/AimtrakBluetooth.pdf, undated — read 2026-10-24.
  7. Phil Hayton, “I made an arcade light gun setup using a handheld, and you can too over Christmas”, GamesRadar+, 24 December 2023, republished by Yahoo Tech (photograph).

Comments (0)

  1. Loading…

Comments are held for moderation — nothing appears until approved.