Mouse buttons are bindable; mouse LOOK scoped (not built)
BUTTONS (shipped). Win32 hands mouse buttons out as virtual keys, and the
binding path already stores VKs and polls GetAsyncKeyState -- so this needed no
verb, no parser change and no new machinery, just names:
key MOUSE4 button 0x40 # side buttons
key MOUSE5 button 0x46
key MOUSEMIDDLE button 0x41
MOUSELEFT/MOUSERIGHT are named too, with a warning in the file header and the
docs: they are how the player presses cockpit buttons (left = press, right =
latch), and the poll is focus-guarded but not click-aware, so binding either
ALSO fires on every panel click. The side and middle buttons are the free
ones. Axes work as well (`key MOUSE4 axis Throttle slew + 0.7`).
One guard: the RGB lamp mirror skips mouse VKs when building its map -- a
keyboard lamp array has no mouse buttons to paint (BTPadBindingIsMouseKey).
Verified live: a bindings.txt carrying two mouse rows loads 76 keys (74 + 2),
and a real injected XBUTTON1 press produced `[emitter] FIRED #1`. Clean A/B --
the earlier run whose SendInput failed the struct-size check logged no fire at
all. Shipped commented-out examples in the default profile so the capability
is discoverable.
LOOK (scoped only). docs/MOUSELOOK_PLAN.md. Mouse MOVEMENT is a real feature,
not a table entry, and the hard part is not reading the device:
- The cursor is already spoken for. The glass cockpit's premise is that all
72 buttons are mouse targets; mouse-look wants a captured, hidden, recentred
cursor. Both cannot be true, so this is a MODE question first -- four
models compared, recommending hold-to-look (costs nothing when unbound,
cannot strand a player, behaves the same in surround and exploded layouts).
- The channels are POSITIONAL (JoystickX/Y are -1..1 deflections the mapper
reads per control mode); a mouse gives deltas. Accumulate-into-a-virtual-
stick reuses every existing rule; a rate model would need new mapper
semantics.
- Control mode changes what it MEANS: BASIC steers with the stick, MID/ADV
twist the torso -- so mouse-look steers in one and aims in the other.
Proposed grammar (new row type, so old builds skip it with a warning),
where the code goes, ~250 lines, and a verification plan whose load-bearing
item is "panel clicks still work when a mouselook binding exists but is not
engaged". Also flagged: the pod had NO mouse, so nothing here is
reconstruction -- every choice is design, judged on feel, and it must stay out
of the pod build's path.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -61,8 +61,42 @@ static const NamedValue keyNames[] =
|
||||
{ "BACKTICK", VK_OEM_3 }, { "LBRACKET", VK_OEM_4 },
|
||||
{ "BACKSLASH", VK_OEM_5 }, { "RBRACKET", VK_OEM_6 },
|
||||
{ "QUOTE", VK_OEM_7 },
|
||||
//
|
||||
// MOUSE BUTTONS (2026-07-26). Win32 hands these out as virtual keys, and
|
||||
// the whole binding path already stores VKs and reads them with
|
||||
// GetAsyncKeyState -- so they need no verb, no parser change and no new
|
||||
// machinery, just a name. `key MOUSE4 button 0x40` works exactly like any
|
||||
// other key row, axes included.
|
||||
//
|
||||
// ⚠ MOUSELEFT/MOUSERIGHT are how the player presses cockpit buttons (left
|
||||
// = press, right = latch). The poll is focus-guarded but not click-aware,
|
||||
// so binding either ALSO fires on every panel click. They are named here
|
||||
// for completeness; the middle and side buttons are the free ones.
|
||||
//
|
||||
{ "MOUSELEFT", VK_LBUTTON }, { "MOUSERIGHT", VK_RBUTTON },
|
||||
{ "MOUSEMIDDLE", VK_MBUTTON },
|
||||
{ "MOUSE4", VK_XBUTTON1 }, { "MOUSE5", VK_XBUTTON2 },
|
||||
{ "MOUSEX1", VK_XBUTTON1 }, { "MOUSEX2", VK_XBUTTON2 },
|
||||
};
|
||||
|
||||
//
|
||||
// A mouse button rather than a keyboard key? (Used where a binding only
|
||||
// makes sense for a real key -- the RGB lamp mirror, which paints keycaps.)
|
||||
//
|
||||
static int
|
||||
IsMouseVirtualKey(int virtualKey)
|
||||
{
|
||||
return (virtualKey == VK_LBUTTON || virtualKey == VK_RBUTTON ||
|
||||
virtualKey == VK_MBUTTON || virtualKey == VK_XBUTTON1 ||
|
||||
virtualKey == VK_XBUTTON2) ? 1 : 0;
|
||||
}
|
||||
|
||||
int
|
||||
BTPadBindingIsMouseKey(int virtualKey)
|
||||
{
|
||||
return IsMouseVirtualKey(virtualKey);
|
||||
}
|
||||
|
||||
static const NamedValue padButtonNames[] =
|
||||
{
|
||||
{ "A", XINPUT_GAMEPAD_A },
|
||||
@@ -202,6 +236,10 @@ static const char *defaultProfileText =
|
||||
"# key <KEYNAME> axis <channel> set <value> jump/detent\n"
|
||||
"# pad <PADBTN> button <addr>\n"
|
||||
"# padaxis <PADAXIS> axis <channel> [invert] [slew <rate>]\n"
|
||||
"# <KEYNAME> may be a MOUSE BUTTON: MOUSEMIDDLE, MOUSE4, MOUSE5 (the two\n"
|
||||
"# side buttons; MOUSEX1/MOUSEX2 are aliases). MOUSELEFT and MOUSERIGHT\n"
|
||||
"# also work but are how you press cockpit buttons -- bind them and they\n"
|
||||
"# fire on every panel click too. Mouse MOVEMENT is not bindable.\n"
|
||||
"# Channels: Throttle JoystickX JoystickY LeftPedal RightPedal Turn\n"
|
||||
"# (Turn = signed composite: + drives the right pedal, - the left --\n"
|
||||
"# made for mapping a gamepad stick to turning)\n"
|
||||
@@ -240,6 +278,10 @@ static const char *defaultProfileText =
|
||||
"key RALT button 0x3F\n"
|
||||
"\n"
|
||||
"# --- the four mappable fire buttons ------------------------------------\n"
|
||||
"# The mouse's side buttons are free if you want them on the trigger:\n"
|
||||
"# key MOUSE4 button 0x40\n"
|
||||
"# key MOUSE5 button 0x46\n"
|
||||
"# key MOUSEMIDDLE button 0x41\n"
|
||||
"key SPACE button 0x40 # main trigger\n"
|
||||
"key NUMPAD0 button 0x40 # main trigger\n"
|
||||
"key NUMPAD1 button 0x45 # pinky\n"
|
||||
|
||||
@@ -230,6 +230,14 @@ PadRIO::PadRIO():
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// A keyboard lamp array has no mouse buttons to paint.
|
||||
{
|
||||
extern int BTPadBindingIsMouseKey(int virtualKey);
|
||||
if (BTPadBindingIsMouseKey(binding.virtualKey))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Logical duplicate = False;
|
||||
for (int j = 0; j < count; ++j)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user