#pragma once //########################################################################### // // L4PADBINDINGS -- the PadRIO input-binding profile (BT_GLASS only). // // Maps PC keyboard keys and XInput pad controls onto the pod's abstract // control surface: RIO button addresses (buttonGroup elements), MFD keypad // units, and the five analog channels (Throttle, JoystickX/Y, Left/Right // Pedal). The profile is read from "bindings.txt" in the working directory // (content\); a self-documenting default file is written on first run. // Grammar (one binding per line, '#' comments): // // key button // key keypad // key axis deflect <+|-> // key axis slew <+|-> // key axis set // pad button // padaxis axis [invert] [slew ] // joydev [product-name substring...] // joyaxis axis [invert] [slew ] [deadzone ] // joybutton button // joybutton keypad // joyhat button // // deflect = held drives the channel toward +/-1 at /s, auto-centers // on release (the spring-centered stick model). // slew = held moves the channel at /s and it STAYS (the throttle // lever model). // set = press jumps the channel to (all-stop detent). // // joy* rows (generic DirectInput joysticks -- flight sticks, HOTAS, // pedals; L4JOY.h) attach to the most recent joydev slot (slot 0 if none // given). A slot with a name substring binds THAT device; without one it // binds the Nth attached non-XInput device. JOYAXIS names follow the // DirectInput layout: X Y Z RX RY RZ SL0 SL1 (twist is usually RZ, a // HOTAS throttle usually Z or SL0). A direct (non-slew) joyaxis on the // Throttle channel maps the full axis travel onto the 0..1 lever (a // physical lever OWNS the channel); other channels follow the pad model // (outside the deadzone owns the channel). BT_JOYCONFIG=1 generates // these rows interactively. // //########################################################################### class PadBindingProfile { public: enum Channel { ChannelThrottle = 0, ChannelJoystickX, ChannelJoystickY, ChannelLeftPedal, ChannelRightPedal, // issue #25: composite -- a SIGNED axis that decomposes into the // pedal pair (positive = right pedal, negative = left pedal) so a // gamepad stick can drive the turn ("twin-stick" profile). ChannelTurn, ChannelCount }; enum ActionKind { ActionButton, // RIO button address (buttonGroup element) ActionKeypad, // MFD keypad unit + key ActionAxisDeflect, ActionAxisSlew, ActionAxisSet }; struct Action { ActionKind kind; int address; // ActionButton: RIO address; ActionKeypad: unit int key; // ActionKeypad: key number (0-9=digits, 10+=A..) int channel; // ActionAxis*: Channel float rate; // deflect/slew: units per second (signed); // set: the target value }; struct KeyBinding { int virtualKey; // Win32 VK code Action action; }; struct PadButtonBinding { unsigned buttonMask; // XINPUT_GAMEPAD_* bit Action action; // ActionButton / ActionKeypad only }; enum PadAxis { PadAxisLX = 0, PadAxisLY, PadAxisRX, PadAxisRY, PadAxisLT, PadAxisRT, PadAxisCount }; struct PadAxisBinding { int axis; // PadAxis int channel; // Channel int invert; // flip the sign int slew; // 0 = direct absolute, 1 = value drives d/dt float slewRate; // full-deflection slew speed (units/s) }; // // Generic-joystick bindings (DirectInput devices -- L4JOY.h). device // is a joydev SLOT (0-3), resolved at poll time by the slot's name // substring (or ordinal when the slot has none). // enum { JoyDeviceSlots = 4 }; enum JoyAxis { JoyAxisX = 0, JoyAxisY, JoyAxisZ, JoyAxisRX, JoyAxisRY, JoyAxisRZ, JoyAxisSL0, JoyAxisSL1, JoyAxisCount }; struct JoyAxisBinding { int device; // joydev slot int axis; // JoyAxis int channel; // Channel int invert; int slew; float slewRate; float deadzone; // 0..1 fraction (rescaled past it) }; struct JoyButtonBinding { int device; // joydev slot int button; // 0-31 Action action; // ActionButton / ActionKeypad only }; struct JoyHatBinding { int device; // joydev slot int hat; // 0-3 int direction; // 0 up / 1 right / 2 down / 3 left Action action; // ActionButton only }; PadBindingProfile(); ~PadBindingProfile(); // // Load "bindings.txt" from the working directory; if it does not exist, // write the default profile there first (self-documenting). Always // leaves a usable profile (falls back to built-in defaults on a // malformed file, logging each rejected line). // void Load(); int keyBindingCount; KeyBinding keyBindings[192]; int padButtonBindingCount; PadButtonBinding padButtonBindings[32]; int padAxisBindingCount; PadAxisBinding padAxisBindings[12]; int joyAxisBindingCount; JoyAxisBinding joyAxisBindings[24]; int joyButtonBindingCount; JoyButtonBinding joyButtonBindings[48]; int joyHatBindingCount; JoyHatBinding joyHatBindings[16]; char joyDeviceMatch[JoyDeviceSlots][64]; // "" = ordinal slot protected: int parseJoyDevice; // joydev slot for subsequent joy rows void LoadDefaults(); void WriteDefaultFile(const char *path); int ParseLine(char *line, int line_number); };