#pragma once //########################################################################### // // L4PADRIO -- the hardware-less cockpit device (BT_GLASS only). // // PadRIO synthesizes the pod's abstract control surface (RIOBase: the five // analog Scalars + button/keypad events + lamps) from an XInput controller // and the PC keyboard, so the whole stock RIO path above the seam -- the // LBE4ControlsManager push, MechRIOMapper, streamed .CTL mappings, lamp // writes -- runs with no serial hardware. Selected at runtime with // L4CONTROLS=PAD (the factory arm in L4CTRL.cpp). // // Input model (bindings: L4PADBINDINGS.h, content\bindings.txt): // - keyboard keys emit button/keypad edge events and drive the analog // channels (spring-stick deflect / throttle-lever slew / detent set) // - XInput pad buttons emit button events; pad axes drive the channels // directly (or as slew rates); hot-plug re-probe every ~3 s // - on-screen cockpit buttons (the L4PADPANEL window, or any WndProc) // inject through the static SetScreenButton() entry // - lamps are recorded in lampState[] for the on-screen panel to render // // The keyboard is only read while a window of THIS process has focus. // L4PADFLIP=1 inverts both stick axes. // //########################################################################### #include "l4rio.h" #include "l4padbindings.h" class PadRIO : public RIOBase { public: PadRIO(); ~PadRIO(); Logical GetNextEvent(RIOEvent *destinationPointer); void SetLamp(int lampNumber, int state); Logical IsOperational() const { return True; } // // The on-screen panel / WndProc entries. Safe no-ops when no PadRIO // is active (pod build never links this TU; a glass build without // L4CONTROLS=PAD never constructs one). Same-thread use only: the // panel WndProc runs on the app thread's message pump. // static Logical IsActive(); static void SetScreenButton(int unit, int pressed); static int GetLampState(int unit); enum { LampCount = 128 }; protected: void Poll(); void PushEvent(const RIOEvent &event); void EmitButton(int address, int pressed); void EmitKeypad(int unit, int key); PadBindingProfile bindings; // // Event queue (ring; drop-newest on overflow, logged). // enum { EventQueueSize = 128 }; RIOEvent eventQueue[EventQueueSize]; int eventHead, eventTail; // // Poll state. // unsigned long lastPollMilliseconds; unsigned long lastPadProbeMilliseconds; int padIndex; // connected XInput slot, -1 = none unsigned previousPadButtons; unsigned char previousKeyHeld[192]; // per key BINDING (parallel to the profile) float channelValue[PadBindingProfile::ChannelCount]; float channelReturnRate[PadBindingProfile::ChannelCount]; int flipStickAxes; // L4PADFLIP int lampState[LampCount]; static PadRIO *activeInstance; };