Skip to content

Put alt handling code in FormBase. Fixes #3584. #4380

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions src/BizHawk.Client.EmuHawk/FormBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,5 +94,40 @@ public void UpdateWindowTitle()
=> base.Text = Config?.UseStaticWindowTitles == true
? (_windowTitleStatic ??= WindowTitleStatic)
: WindowTitle;

// Alt key hacks. We need this in order for hotkey bindings with alt to work.
/// <summary>sends a simulation of a plain alt key keystroke</summary>
internal void SendPlainAltKey(int lparam)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These should be public.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why should they be more visible than they need to be?

Copy link
Member

@YoshiRulz YoshiRulz Jul 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FormBase and the caller, Input, aren't semantically related. I misread the diff viewer. My point still stands: They may end up in separate projects in the future.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The caller is MainForm.

{
var m = new Message { WParam = new IntPtr(0xF100), LParam = new IntPtr(lparam), Msg = 0x0112, HWnd = Handle };
base.WndProc(ref m);
}

/// <summary>HACK to send an alt+mnemonic combination</summary>
internal void SendAltKeyChar(char c) => ProcessMnemonic(c);

protected override void WndProc(ref Message m)
{
if (!BlocksInputWhenFocused)
{
// this is necessary to trap plain alt keypresses so that only our hotkey system gets them
if (m.Msg == 0x0112) // WM_SYSCOMMAND
{
if (m.WParam.ToInt32() == 0xF100) // SC_KEYMENU
{
return;
}
}
}

base.WndProc(ref m);
}

protected override bool ProcessDialogChar(char charCode)
{
// this is necessary to trap alt+char combinations so that only our hotkey system gets them
return (ModifierKeys & Keys.Alt) != 0 || base.ProcessDialogChar(charCode);
}

}
}
12 changes: 5 additions & 7 deletions src/BizHawk.Client.EmuHawk/Input/Input.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public void ControlInputFocus(Control c, HostInputType types, bool wants)

private readonly Func<Config> _getConfigCallback;

internal Input(IntPtr mainFormHandle, Func<Config> getConfigCallback, Func<bool, AllowInput> mainFormInputAllowedCallback)
internal Input(IntPtr mainFormHandle, Func<Config> getConfigCallback, Func<AllowInput> mainFormInputAllowedCallback)
{
_getConfigCallback = getConfigCallback;
_currentConfig = _getConfigCallback();
Expand Down Expand Up @@ -133,7 +133,7 @@ private void HandleButton(string button, bool newState, HostInputType source)

private void HandleAxis(string axis, int newValue)
{
if (ShouldSwallow(MainFormInputAllowedCallback(false), HostInputType.Pad))
if (ShouldSwallow(MainFormInputAllowedCallback(), HostInputType.Pad))
return;

if (_trackDeltas)
Expand Down Expand Up @@ -189,7 +189,7 @@ public KeyValuePair<string, int>[] GetAxisValues()
/// <summary>
/// Controls whether MainForm generates input events. should be turned off for most modal dialogs
/// </summary>
public readonly Func<bool, AllowInput> MainFormInputAllowedCallback;
public readonly Func<AllowInput> MainFormInputAllowedCallback;

private void UpdateThreadProc()
{
Expand Down Expand Up @@ -262,13 +262,11 @@ private void UpdateThreadProc()
if (_newEvents.Count != 0)
{
//WHAT!? WE SHOULD NOT BE SO NAIVELY TOUCHING MAINFORM FROM THE INPUTTHREAD. ITS BUSY RUNNING.
AllowInput allowInput = MainFormInputAllowedCallback(false);
AllowInput allowInput = MainFormInputAllowedCallback();

foreach (var ie in _newEvents)
{
//events are swallowed in some cases:
if ((ie.LogicalButton.Modifiers & LogicalButton.MASK_ALT) is not 0U && ShouldSwallow(MainFormInputAllowedCallback(true), ie.Source))
continue;
if (ie.EventType == InputEventType.Press && ShouldSwallow(allowInput, ie.Source))
continue;

Expand Down Expand Up @@ -332,7 +330,7 @@ public string GetNextBindEvent(ref InputEvent lastPress)
lock (this)
{
if (_inputEvents.Count == 0) return null;
AllowInput allowInput = MainFormInputAllowedCallback(false);
AllowInput allowInput = MainFormInputAllowedCallback();

//wait for the first release after a press to complete input binding, because we need to distinguish pure modifierkeys from modified keys
//if you just pressed ctrl, wanting to bind ctrl, we'd see: pressed:ctrl, unpressed:ctrl
Expand Down
48 changes: 4 additions & 44 deletions src/BizHawk.Client.EmuHawk/MainForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
Expand Down Expand Up @@ -620,14 +619,13 @@ _argParser.SocketAddress is var (socketIP, socketPort)
Input.Instance = new Input(
Handle,
() => Config,
yieldAlt => ActiveForm switch
() => ActiveForm switch
{
null => Config.AcceptBackgroundInput // none of our forms are focused, check the background input config
? Config.AcceptBackgroundInputControllerOnly
? AllowInput.OnlyController
: AllowInput.All
: AllowInput.None,
TAStudio when yieldAlt => AllowInput.None,
FormBase { BlocksInputWhenFocused: false } => AllowInput.All,
ControllerConfig => AllowInput.All,
HotkeyConfig => AllowInput.All,
Expand Down Expand Up @@ -1267,7 +1265,7 @@ private void ProcessInput(

// look for hotkey bindings for this key
var triggers = searchHotkeyBindings(ie.LogicalButton.ToString());
if (triggers.Count == 0)
if (triggers.Count == 0 && ActiveForm is FormBase afb)
{
// Maybe it is a system alt-key which hasn't been overridden
if (ie.EventType is InputEventType.Press && (ie.LogicalButton.Modifiers & LogicalButton.MASK_ALT) is not 0U)
Expand All @@ -1277,12 +1275,12 @@ private void ProcessInput(
var c = ie.LogicalButton.Button.ToLowerInvariant()[0];
if ((c >= 'a' && c <= 'z') || c == ' ')
{
SendAltKeyChar(c);
afb.SendAltKeyChar(c);
}
}
else if (ie.LogicalButton.Button == "Space")
{
SendPlainAltKey(32);
afb.SendPlainAltKey(32);
}
}

Expand Down Expand Up @@ -2474,23 +2472,6 @@ private void SaveSlotSelectedMessage()
DisplayManager.UpdateSource(video);
}

// sends a simulation of a plain alt key keystroke
private void SendPlainAltKey(int lparam)
{
var m = new Message { WParam = new IntPtr(0xF100), LParam = new IntPtr(lparam), Msg = 0x0112, HWnd = Handle };
base.WndProc(ref m);
}

/// <summary>HACK to send an alt+mnemonic combination</summary>
private void SendAltKeyChar(char c)
=> _ = typeof(ToolStrip).InvokeMember(
OSTailoredCode.IsUnixHost ? "ProcessMnemonic" : "ProcessMnemonicInternal",
BindingFlags.NonPublic | BindingFlags.InvokeMethod | BindingFlags.Instance,
null,
MainformMenu,
new object/*?*/[] { c },
CultureInfo.InvariantCulture);

public static readonly FilesystemFilterSet ConfigFileFSFilterSet = new(new FilesystemFilter("Config File", new[] { "ini" }))
{
AppendAllFilesEntry = false,
Expand Down Expand Up @@ -2925,27 +2906,6 @@ private void FdsInsertDiskMenuAdd(string name, string button, string msg)

private const int WmDeviceChange = 0x0219;

// Alt key hacks
protected override void WndProc(ref Message m)
{
// this is necessary to trap plain alt keypresses so that only our hotkey system gets them
if (m.Msg == 0x0112) // WM_SYSCOMMAND
{
if (m.WParam.ToInt32() == 0xF100) // SC_KEYMENU
{
return;
}
}

base.WndProc(ref m);
}

protected override bool ProcessDialogChar(char charCode)
{
// this is necessary to trap alt+char combinations so that only our hotkey system gets them
return (ModifierKeys & Keys.Alt) != 0 || base.ProcessDialogChar(charCode);
}

private void UpdateCoreStatusBarButton()
{
var attributes = Emulator.Attributes();
Expand Down