PC (Windows) · Volume 1

The Gun as Windows Sees It — One Device, Three Readers, a COM Port and the Primary Monitor

What a Windows PC makes of an OpenFIRE light gun, the three different ways programs read it, why two guns need two identities, why the gun's screen must be the primary monitor, and a first map of what runs where

Figure 1 — A light gun aimed at Duck Hunt, the dog holding up the bird, on a modern flat screen. The gun here is a Sinden, which plays from a computer, a camera gun that finds the screen by a white border; th…
Figure 1 — A light gun aimed at Duck Hunt, the dog holding up the bird, on a modern flat screen. The gun here is a Sinden, which plays from a computer, a camera gun that finds the screen by a white border; the OpenFIRE gun this dive is about finds it by infrared emitters instead, but on Windows both arrive as the same kind of device, an absolute mouse, and every program in this dive reads them the same way. Photo: Damien McFerran / Time Extension.

This dive is about one gun on one kind of computer: the light gun being built for this category (a Raspberry Pi Pico running a private fork of OpenFIRE, a camera that sees infrared emitters at the screen, and a regulated 24 V solenoid) plugged into a Windows PC. It covers what Windows makes of the gun, the emulators and loaders that play light-gun games, how game-driven recoil reaches the solenoid, what latency Windows adds, and, at the end, a game-by-game table of what works.

It is the first of the Platform Support dives. The firmware’s side of the same conversation, what the gun sends and what it accepts, belongs to Open-Source Firmware, Volume 6 and is linked rather than repeated. Linux and the retro distributions, MiSTer, original consoles and arcade hardware each have their own dive.

1.1 Why Windows is the reference platform

Nearly every program that plays light-gun games well was written for Windows first, and several were written only for Windows. MAME’s per-device light-gun input on Windows comes from the Windows Raw Input API; Supermodel’s README says plainly that multiple mice or PC light guns need Raw Input, “supported only on Windows”; TeknoParrot, DemulShooter, the Model 2 emulator, Demul and MAMEHooker are Windows programs; and the OpenFIRE App ships a Windows build (OpenFIREapp-win64.zip) beside its Linux AppImages in release v3.0.3. Flycast, DuckStation and RetroArch run elsewhere too, but their multi-gun paths on Windows are the Raw Input ones described in this dive.

So Windows is where the most games work with the least effort, where every feature of the gun (two players, game-driven recoil, lights) has a working route, and where the first bench tests of the finished gun will most likely be run. It is also where the gun’s behaviour is easiest to measure, because the hook programs and emulators publish their outputs in readable text (Volume 5).

1.2 What Windows enumerates

Figure 2 — What Windows makes of one OpenFIRE gun. A single USB device with vendor ID 0xF143 enumerates as a composite: a HID interface carrying a keyboard, an absolute mouse and a sixteen-button gamepad, and…
Figure 2 — What Windows makes of one OpenFIRE gun. A single USB device with vendor ID 0xF143 enumerates as a composite: a HID interface carrying a keyboard, an absolute mouse and a sixteen-button gamepad, and a CDC serial interface. Windows' own class drivers bind to all of them with no installation: the HID parts become a keyboard, a mouse and a game controller, and the serial part becomes a numbered COM port through the in-box Usbser.sys. Own-work diagram.

The gun is one USB device with OpenFIRE’s fixed vendor ID 0xF143, the manufacturer string “OpenFIRE”, and a product ID and name that the App sets. The HID report layout (keyboard, absolute mouse with a 0–32767 range, sixteen-button gamepad) and the 1 ms polling interval are documented in Open-Source Firmware, Volume 6, section 6.2. What matters here is what Windows does with them:

Table 1 — The gun is one USB device with OpenFIRE's fixed vendor ID 0xF143, the manufacturer string "OpenFIRE", and a product ID and name that the App sets. The HID report layout (keyboard, absolute mouse with a 0–32767 range, sixteen-button gamepad) and the 1 ms polling interval are documented in [Open-Source Firmware, Volume 6, section 6.2](/light-guns/building-the-electronics/open-source-firmware/vol-6/). What matters here is what Windows does with them

InterfaceWindows driverAppears asWho reads it
HID keyboardkbdhid (in-box)A keyboard in Device ManagerEvery program; Start, Select and the D-pad as keys
HID absolute mousemouhid (in-box)A “HID-compliant mouse”The desktop cursor, and any program reading Raw Input per device
HID gamepadHID game controller (in-box)A game controller, read through DirectInput, Raw Input or SDLEmulators that accept generic controllers
CDC serialUsbser.sys (in-box)“USB Serial Device (COMn)“The OpenFIRE App, MAMEHooker, QMamehook, a batch file

No driver needs installing. Microsoft’s documentation for Usbser.sys says the in-box driver loads automatically for any function with class code 02 and subclass 02, “You don’t need to write your own INF file”, and the HID classes are among Windows’ standard class drivers. That is also why the gun works on any Windows PC a kit buyer owns, which matters under decision D11 (kits may be sold).

One consequence of the gamepad being a generic HID gamepad, not an Xbox-class one: programs or game profiles that only read XInput will not see it. XInput is Microsoft’s API for Xbox controllers; a generic HID gamepad is reached through DirectInput, Raw Input or SDL. Where a loader offers a choice of input API (TeknoParrot does, per game: DirectInput, XInput or RawInput), the gun’s route is RawInput for the mouse or DirectInput for the gamepad, never XInput. This follows from the device classes and was not tested.

The absolute mouse’s 0–32767 logical range is rescaled by Windows. Raw Input reports an absolute mouse as normalised coordinates “between 0 and 65,535”, with (0,0) at the top-left of the display and (65535,65535) at the bottom-right (Microsoft, RAWMOUSE). Every program in this dive works in those units or in pixels derived from them.

1.3 Three readers: the cursor, Raw Input and the gamepad

Figure 3 — The three ways a Windows program can read the gun's aim. The system cursor is one shared position for every mouse on the machine, so it can only ever be one player. Raw Input delivers each mouse's …
Figure 3 — The three ways a Windows program can read the gun's aim. The system cursor is one shared position for every mouse on the machine, so it can only ever be one player. Raw Input delivers each mouse's own reports, tagged with its device, so two guns are two players; this is what MAME's rawinput provider, RetroArch's raw driver, Supermodel, Flycast, DuckStation, TeknoParrot and DemulShooter use. The gamepad route puts the aim on an analog stick, one per controller, for programs that only take gamepads. Own-work diagram.

Everything that goes wrong with light guns on Windows traces back to which of three readers a program uses.

The system cursor. Windows merges every mouse on the machine into one cursor. An absolute mouse moves it to where the gun points, which is why the gun works in a browser, on the desktop and in any game that uses the mouse pointer, with no set-up at all. But there is only one cursor. A program reading it (MAME’s win32 light-gun provider, which calls GetCursorPos(); RetroArch’s dinput driver; PCSX2) can only ever have one gun, and a second gun plugged in fights the first for the same pointer. DemulShooter’s configuration page puts it exactly: devices that report relative positions “will share the same axis values (i.e : Windows Cursor position). So this method is not meant to be used in order to obtain multiplayer-separated values”.

Raw Input. Windows’ Raw Input API delivers each mouse’s reports separately, tagged with the device they came from, before they are merged into the cursor. A program that registers for Raw Input can tell Player 1’s gun from Player 2’s. Every serious multi-gun path on Windows uses it, and each was read in source for this dive:

Table 2 — Raw Input. Windows' Raw Input API delivers each mouse's reports separately, tagged with the device they came from, before they are merged into the cursor. A program that registers for Raw Input can tell Player 1's gun from Player 2's. Every serious multi-gun path on Windows uses it, and each was read in source for this dive

ProgramWhere the Raw Input handling isWhat it does with an absolute report
MAME 0.289src/osd/modules/input/input_rawinput.cpp, lightgun_input_rawinputEvery mouse becomes its own light gun; position taken only when MOUSE_MOVE_ABSOLUTE is set
RetroArch v1.22.2 and masterinput/drivers/winraw_input.cEach mouse published by index; a port reads “the mouse at its Mouse Index”
TeknoParrot (master, 2026-10-19)InputListenerRawInput.csAn absolute report goes to the P1–P4 light-gun binding for that device path
DuckStationsrc/util/win32_raw_input_source.cppEach mouse becomes “Raw Input Pointer n”, honouring the virtual-desktop flag
Supermodel, Flycast, DemulShooterper their documentation (Volume 4, Volume 5)Per-device mapping; DemulShooter lists “only devices supporting RawInput data”

The gamepad. OpenFIRE’s gamepad mode (serial command M0x1, or the App) puts the camera’s aim on an analog stick. A program that takes only gamepads can then still be aimed, and two guns become two controllers with no cursor contention. It is the fallback for programs with no Raw Input (PCSX2’s second gun is the clearest case, Volume 4), and the price is that the aim arrives as a stick deflection the program must treat as an absolute position. Open-Source Firmware, Volume 6, section 6.4 has the modes.

The rule that follows: for one player, anything works; for two, use a program’s Raw Input path, or put the second gun in gamepad mode.

1.4 The primary-monitor rule

Microsoft’s documentation for the Raw Input mouse structure is unambiguous: absolute coordinates map onto “the display surface”, and “In a multimonitor system, the coordinates map to the primary monitor”, unless the device also sets the virtual-desktop flag, in which case they span every monitor. A HID absolute mouse like the gun’s does not set that flag in anything read for this dive, so on a desk with two monitors the gun’s full range covers the primary monitor only.

The consequence is simple and is the first thing to check when the aim is wildly wrong on a multi-monitor PC: make the gun’s screen the primary display (Settings, System, Display, “Make this my main display”), or run the games on whichever display is primary. Programs that map coordinates themselves (TeknoParrot and DuckStation both read the virtual-desktop flag in their source) behave the same way for this gun, because the flag is not set. A television connected as a second display for a living-room set-up is the common trap.

1.5 Identity: one gun is easy, two guns are not

A single gun can keep the firmware’s default identity (product ID 1, name “FIRECon P1”). Two guns with the same identity look like one device to anything that tells devices apart by their IDs, and the OpenFIRE instruction book warns that programs such as RetroArch and TeknoParrot “will get VERY confused” (Open-Source Firmware, Volume 6, section 6.6).

The App’s “Simple USB Identifier Presets” fix this in one click. Its source (appmainwindow.cpp, v3.0.3) shows what each preset writes:

Table 3 — The App's "Simple USB Identifier Presets" fix this in one click. Its source (appmainwindow.cpp, v3.0.3) shows what each preset writes

PresetProduct IDProduct nameStart / Select keys
P10x0001FIRECon P11 / 5
P20x0002FIRECon P22 / 6
P30x0003FIRECon P33 / 7
P40x0004FIRECon P44 / 8

So on Windows the two guns appear with hardware IDs USB\VID_F143&PID_0001 and USB\VID_F143&PID_0002, and Raw Input device paths that contain those strings. That substring is what MAME’s stable-ID mapping matches on (Volume 2): MAME’s documentation gives the identical pattern for two Ultimarc AimTrak guns (VID_D209&PID_1601, VID_D209&PID_1602).

Why not leave the IDs the same and rely on the USB port? Because enumeration order is not stable. MAME’s documentation says device numbers change with “disconnecting and reconnecting USB or Bluetooth devices, changing ports/hubs, and even just restarting the computer”. A product ID baked into each gun survives all of that.

The vendor ID stays 0xF143. It is how the App, MiSTer and the hook programs find OpenFIRE guns; decision D24 (18 October 2026) keeps it for every personal and bench gun and requires an assigned vendor ID before any kit is sold. On Windows the change would be invisible to Raw Input programs, which match on any device, but not to MAME mapdevice lines written with VID_F143, to QMamehook (which detects OpenFIRE, GUN4IR and Blamcon vendor IDs only), or to the App, so it is a fleet-wide change when it comes. Our Firmware, Volume 6 and Licensing, IP and Kits own it.

1.6 The COM port

The serial interface is how the App configures the gun and how hook programs drive its recoil. Windows numbers it in arrival order, so a gun may be COM3 today and COM7 after moving it to another port. Two things depend on the number:

  • MAMEHooker wants Player 1’s gun on COM1, Player 2’s on COM2, and sees only up to COM4, per the OpenFIRE wiki. The number is changed in Device Manager, under the port’s Properties, Port Settings, Advanced. Open-Source Firmware, Volume 6, section 6.9 has the rule and the ini anatomy.
  • QMamehook ignores COM numbers and numbers players by the order it detects guns, so the product-ID presets above are what keep P1 as P1.

Windows keeps the assigned number for that device on that USB port, so set it once with each gun in the port it will live in. Re-check it after any change of hub or port.

A quick serial test from a Command Prompt, before any game is involved, uses the commands in Open-Source Firmware, Volume 6, section 6.11: echo S > COM3 puts the gun in serial mode and its LED goes white; echo E > COM3 returns it. (v6.1’s release notes record a fix for commands sent this way from Windows batch files.)

1.7 The screen: no border, the right picture, the right shape

No border is needed. The gun finds the screen by infrared emitters fixed around it, not by anything drawn on it. The white-border overlays, shaders and layout files that camera guns such as the Sinden need, which Border Tracking, Volume 6 covers for every emulator, do nothing for this gun and can be left off. That removes a whole layer of per-emulator configuration and is one of the practical arguments for infrared that Border Tracking records in its comparison.

Fill the screen, or tell the gun what shape the picture is. The gun’s calibration maps its aim onto the whole display. A program that draws a 4:3 game with black bars on a 16:9 screen still receives coordinates across the full width, so either the program scales them into the picture, or the aim drifts outward toward the sides. There are three fixes, in order of preference:

  1. Let the program handle it. TeknoParrot’s source says its emulators “publish their exact screen-space content viewport. This keeps absolute and relative gun input aligned with letterboxed output.”
  2. Use the gun’s 4:3 correction. OpenFIRE narrows its output to the centred 4:3 window when sent M3x1 (or set in the profile); Open-Source Firmware, Volume 6, section 6.4 gives the exact windows. A hook program’s start command can send it per game.
  3. Stretch the picture. Every emulator here can stretch to the full screen, at the price of a distorted picture.

Which programs need which is part of the per-game table in Volume 6. That MAME’s full-screen pillarbox needs fix 2 or 3 is expected from how it scales Raw Input coordinates (Volume 2), and should be confirmed on the built gun.

Exclusive full screen is not needed for low latency on current Windows, which Volume 6 explains, so borderless windowed modes are fine; but the game window must cover the screen the gun was calibrated to.

1.8 Calibrating on Windows

Calibration happens in the gun, not in Windows. The App’s calibration screen draws targets at the centre and the four edges and stores the result in the gun’s flash, per profile; the procedure and what each shot records are in Open-Source Firmware, Volume 5, section 5.3, and the mathematics in Aiming Maths and Calibration. The App for Windows is the OpenFIREapp-win64.zip release asset; installing and docking are in Open-Source Firmware, Volume 4.

Three Windows-specific habits:

  • Calibrate on the screen the games will use, at its native resolution, and with that screen primary. The App’s full-screen targets are drawn on the display the App window is on; if that is not the primary monitor, the targets and the gun’s coordinate range disagree (1.4).
  • Turn off display scaling surprises. Calibration is against the physical picture, so Windows’ DPI scaling does not affect it, but a television’s overscan does: set the TV to its “just scan”, “screen fit” or PC mode so the desktop’s edges are on the glass.
  • Some games also calibrate themselves. Arcade software run under Demul, the Model 2 emulator and Supermodel often has its own gun calibration in the game’s test menu, which DemulShooter’s documentation tells the player to run “the first time you run a game”. That is a second calibration on top of the gun’s, done once per game (Volume 4).

Windows’ mouse settings (pointer speed, “Enhance pointer precision”) do not touch the gun’s aim: Raw Input events “are not subject to the effects of the mouse speed set in the Control Panel”, per Microsoft, and an absolute position has no acceleration to apply.

1.9 The software, on one page

Figure 4 — Which program reads what. Each row is a program in this dive, coloured by how it reads the gun: per-device Raw Input (two or more guns), the shared system cursor (one gun), or a gamepad stick. The …
Figure 4 — Which program reads what. Each row is a program in this dive, coloured by how it reads the gun: per-device Raw Input (two or more guns), the shared system cursor (one gun), or a gamepad stick. The right-hand columns show whether it can drive the gun's recoil from the game, and how. Own-work chart, from each program's own documentation and source as read 2026-10-20.

Table 4 — 1.9 The software, on one page

ProgramPlaysVersion readGun input on WindowsTwo gunsGame-driven recoilVolume
MAMEArcade, including most 1980s–2000s gun games0.289 (30 July 2026)-lightgunprovider rawinputYesNative outputs (-output windows or network) to a hook2
RetroArchConsoles and arcade through coresv1.22.2 (20 November 2025)raw input driver, Mouse Index per portYesNot from RetroArch itself (MAME-core network outputs only, per QMamehook)3
Model 2 emulatorSega Model 2 (House of the Dead, Virtua Cop 1 and 2)1.1aIts own Raw Input option, or DemulShooterYesThrough DemulShooter4
SupermodelSega Model 3 (The Lost World)0.3a git build (20 October 2026)-input-system=rawinputYesNot from the emulator: its outputs are lamps and the drive board only4
DemulNaomi, Atomiswave0.7a 180428Through DemulShooterYesThrough DemulShooter4
FlycastNaomi, Atomiswave, Dreamcastv2.7 (19 August 2026)“Use Raw Input”YesRaw JVS output bits (lamp0, lamp1 …) on TCP 8000; DemulShooter names them4
PCSX2PlayStation 2 (GunCon 2)v2.8.2 (4 September 2026)System cursor; second gun by relative (stick) bindsPartlyNo4
DuckStationPlayStation (GunCon, Justifier)rolling build (13 October 2026)“Use Raw Input”YesNo4
TeknoParrotPC-based arcade (Lindbergh, RingEdge, Namco ES3/ES4, Raw Thrills…)master (19 October 2026)Per-game Input API = RawInputYesThrough DemulShooter, game by game5
DemulShooterHooks games in the above and PC gamesv17.10 (14 October 2026)Raw Input, P1–P4Up to fourGenuine and custom outputs5
PC-native gamesThe House of the Dead Remake, Operation Wolf Returns, othersper gameMostly the cursor; DemulShooter adds per-gun inputThrough DemulShooterThrough DemulShooter5

Volume 5 also covers the hook side (MAMEHooker, QMamehook, Hook Of The Reaper, OutputHooker) as it runs on Windows; Volume 6 has latency, multi-gun assignment end to end, troubleshooting, and the game-by-game table.

1.10 Why this, and why not the others

The project’s first platform is Windows. The criteria were: the most games with a working light-gun path, two-player support, a working route for game-driven recoil, the OpenFIRE App available, and measurability on the bench.

Table 5 — 1.10 Why this, and why not the others

PlatformVerdictWhy
Windows PCFirstEvery program above has a Windows build; Raw Input gives per-gun input in all the major emulators; MAMEHooker, QMamehook and DemulShooter’s outputs all work; the App’s Windows build is a release asset
Linux and retro distributionsSecondMAME, RetroArch, Flycast, Supermodel and QMamehook run natively, but TeknoParrot, DemulShooter, Demul and MAMEHooker need Wine, and MAMEHooker in Wine “will only work with games running in the same prefix” (OpenFIRE wiki); the Linux and Retro Distros dive owns it
MiSTerLaterOpenFIRE support is built into MiSTer’s main program, but calibration “has to be done against the desired display from a different device”, per the v6.0 release notes, which is to say a PC; MiSTer FPGA
Original consolesNot directlyAn absolute-mouse gun cannot be a GunCon or a Zapper without protocol emulation hardware; Original Consoles

1.11 What could not be verified

  • Whether the OpenFIRE gun’s HID absolute mouse ever sets the virtual-desktop flag on Windows (assumed not, from the firmware’s report descriptor having no such concept; to confirm by reading usFlags in a Raw Input logger on the built gun).
  • That a generic HID gamepad is invisible to XInput-only programs is stated from the API definitions and was not tested with this gun.
  • MAME’s behaviour with a pillarboxed 4:3 game and an absolute gun, stated as expected and to be confirmed.

Sources

  1. Microsoft, “RAWMOUSE structure (winuser.h)”, Microsoft Learn, updated 26 June 2024, https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-rawmouse — read 2026-10-20.
  2. Microsoft, “USB Serial Driver (Usbser.sys)”, Microsoft Learn, updated 18 July 2025, https://learn.microsoft.com/en-us/windows-hardware/drivers/usbcon/usb-driver-installation-based-on-compatible-ids — read 2026-10-20.
  3. TeamOpenFIRE, OpenFIRE-App v3.0.3, src/appmainwindow.cpp (USB identifier presets) and release assets, https://github.com/TeamOpenFIRE/OpenFIRE-App — read 2026-10-20.
  4. TeamOpenFIRE, MAMEHOOKER Documentation, OpenFIRE-Firmware wiki, https://github.com/TeamOpenFIRE/OpenFIRE-Firmware/wiki/MAMEHOOKER-Documentation — read 2026-10-20.
  5. MAMEdev, src/osd/modules/input/input_rawinput.cpp, input_win32.cpp, and docs/source/advanced/devicemap.rst (“Stable Controller IDs”), MAME master after 0.289, https://github.com/mamedev/mame — read 2026-10-20.
  6. libretro, input/drivers/winraw_input.c at tag v1.22.2 and master, https://github.com/libretro/RetroArch — read 2026-10-20.
  7. teknogods, TeknoParrotUI master (pushed 19 October 2026): TeknoParrotUi.Common/InputListening/InputListenerRawInput.cs, https://github.com/teknogods/TeknoParrotUI — read 2026-10-20.
  8. Connor McLaughlin (stenzek), DuckStation, src/util/win32_raw_input_source.cpp, https://github.com/stenzek/duckstation — read 2026-10-20.
  9. argonlefou, DemulShooter wiki, “Configuration” (v17.10), https://github.com/argonlefou/DemulShooter/wiki/Configuration — read 2026-10-20.
  10. The Supermodel project (Bart Trzynadlowski and contributors), Docs/README.txt, https://github.com/trzy/supermodel — read 2026-10-20.
  11. Release dates from each project’s GitHub releases, read 2026-10-20.
  12. Damien McFerran, “Sinden Light Gun review”, Time Extension, 24 December 2023, https://www.timeextension.com/reviews/sinden-light-gun-old-school-arcade-blasting-on-your-modern-day-tv (photograph).

Comments (0)

  1. Loading…

Comments are held for moderation — nothing appears until approved.