Allow configuring "keybinds" for haptic feedback (see desc.)
Open `Config` > `Controllers...` with any rom loaded and go to the last tab. A "Debug" virtual channel is hardcoded, and will be present on every core. As with the previous commit, holding Fast Forward causes this channel to fire and it will be passed through to a bound host gamepad. The prescale slider works. Virtual channels with a player number prefix also work, but the single "Debug" channel without a prefix is hardcoded. Caveats: Reopening the config dialog doesn't load the host channel back into the combobox. It will save to config correctly.
This commit is contained in:
parent
6102db0e68
commit
bb3fddcb5f
|
@ -30,6 +30,7 @@ namespace BizHawk.Client.Common
|
|||
private readonly WorkingDictionary<string, int> _axes = new WorkingDictionary<string, int>();
|
||||
private readonly Dictionary<string, AxisSpec> _axisRanges = new WorkingDictionary<string, AxisSpec>();
|
||||
private readonly Dictionary<string, AnalogBind> _axisBindings = new Dictionary<string, AnalogBind>();
|
||||
private readonly Dictionary<string, FeedbackBind> _feedbackBindings = new Dictionary<string, FeedbackBind>();
|
||||
|
||||
/// <summary>don't do this</summary>
|
||||
public void ForceType(ControllerDefinition newType) => Definition = newType;
|
||||
|
@ -94,6 +95,14 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
}
|
||||
|
||||
public void PrepareHapticsForHost(SimpleController finalHostController, int debug)
|
||||
{
|
||||
foreach (var kvp in _feedbackBindings)
|
||||
{
|
||||
finalHostController.SetHapticChannelStrength(kvp.Value.GamepadPrefix + kvp.Value.Channel, (int) ((double) debug * kvp.Value.Prescale));
|
||||
}
|
||||
}
|
||||
|
||||
public void ApplyAxisConstraints(string constraintClass)
|
||||
=> Definition.ApplyAxisConstraints(constraintClass, _axes);
|
||||
|
||||
|
@ -153,6 +162,8 @@ namespace BizHawk.Client.Common
|
|||
_axisBindings[button] = bind;
|
||||
}
|
||||
|
||||
public void BindFeedbackChannel(string channel, FeedbackBind binding) => _feedbackBindings[channel] = binding;
|
||||
|
||||
public List<string> PressedButtons => _buttons
|
||||
.Where(kvp => kvp.Value)
|
||||
.Select(kvp => kvp.Key)
|
||||
|
|
|
@ -22,12 +22,16 @@ namespace BizHawk.Client.Common
|
|||
|
||||
public Config()
|
||||
{
|
||||
if (AllTrollers.Count == 0 && AllTrollersAutoFire.Count == 0 && AllTrollersAnalog.Count == 0)
|
||||
if (AllTrollers.Count == 0
|
||||
&& AllTrollersAutoFire.Count == 0
|
||||
&& AllTrollersAnalog.Count == 0
|
||||
&& AllTrollersFeedbacks.Count == 0)
|
||||
{
|
||||
var cd = ConfigService.Load<DefaultControls>(ControlDefaultPath);
|
||||
AllTrollers = cd.AllTrollers;
|
||||
AllTrollersAutoFire = cd.AllTrollersAutoFire;
|
||||
AllTrollersAnalog = cd.AllTrollersAnalog;
|
||||
AllTrollersFeedbacks = cd.AllTrollersFeedbacks;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -293,6 +297,7 @@ namespace BizHawk.Client.Common
|
|||
public Dictionary<string, Dictionary<string, string>> AllTrollers { get; set; } = new Dictionary<string, Dictionary<string, string>>();
|
||||
public Dictionary<string, Dictionary<string, string>> AllTrollersAutoFire { get; set; } = new Dictionary<string, Dictionary<string, string>>();
|
||||
public Dictionary<string, Dictionary<string, AnalogBind>> AllTrollersAnalog { get; set; } = new Dictionary<string, Dictionary<string, AnalogBind>>();
|
||||
public Dictionary<string, Dictionary<string, FeedbackBind>> AllTrollersFeedbacks { get; set; } = new Dictionary<string, Dictionary<string, FeedbackBind>>();
|
||||
|
||||
/// <remarks>as this setting spans multiple cores and doesn't actually affect the behavior of any core, it hasn't been absorbed into the new system</remarks>
|
||||
public bool GbAsSgb { get; set; }
|
||||
|
|
|
@ -13,5 +13,8 @@ namespace BizHawk.Client.Common
|
|||
|
||||
public Dictionary<string, Dictionary<string, AnalogBind>> AllTrollersAnalog { get; set; }
|
||||
= new Dictionary<string, Dictionary<string, AnalogBind>>();
|
||||
|
||||
public Dictionary<string, Dictionary<string, FeedbackBind>> AllTrollersFeedbacks { get; set; }
|
||||
= new Dictionary<string, Dictionary<string, FeedbackBind>>();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
#nullable enable
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BizHawk.Client.Common
|
||||
{
|
||||
public struct FeedbackBind
|
||||
{
|
||||
public string? Channel;
|
||||
|
||||
/// <remarks>"X# "/"J# " (with the trailing space)</remarks>
|
||||
public string? GamepadPrefix;
|
||||
|
||||
[JsonIgnore]
|
||||
public bool IsZeroed => GamepadPrefix == null;
|
||||
|
||||
public float Prescale;
|
||||
|
||||
public FeedbackBind(string prefix, string channel, float prescale)
|
||||
{
|
||||
GamepadPrefix = prefix;
|
||||
Channel = channel;
|
||||
Prescale = prescale;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -53,7 +53,7 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
var def = emulator.ControllerDefinition;
|
||||
|
||||
ActiveController = BindToDefinition(def, config.AllTrollers, config.AllTrollersAnalog);
|
||||
ActiveController = BindToDefinition(def, config.AllTrollers, config.AllTrollersAnalog, config.AllTrollersFeedbacks);
|
||||
AutoFireController = BindToDefinitionAF(emulator, config.AllTrollersAutoFire, config.AutofireOn, config.AutofireOff);
|
||||
|
||||
// allow propagating controls that are in the current controller definition but not in the prebaked one
|
||||
|
@ -86,7 +86,11 @@ namespace BizHawk.Client.Common
|
|||
AutofireStickyXorAdapter.MassToggleStickyState(ActiveController.PressedButtons);
|
||||
}
|
||||
|
||||
private static Controller BindToDefinition(ControllerDefinition def, IDictionary<string, Dictionary<string, string>> allBinds, IDictionary<string, Dictionary<string, AnalogBind>> analogBinds)
|
||||
private static Controller BindToDefinition(
|
||||
ControllerDefinition def,
|
||||
IDictionary<string, Dictionary<string, string>> allBinds,
|
||||
IDictionary<string, Dictionary<string, AnalogBind>> analogBinds,
|
||||
IDictionary<string, Dictionary<string, FeedbackBind>> feedbackBinds)
|
||||
{
|
||||
var ret = new Controller(def);
|
||||
if (allBinds.TryGetValue(def.Name, out var binds))
|
||||
|
@ -111,6 +115,15 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
}
|
||||
|
||||
if (feedbackBinds.TryGetValue(def.Name, out var fBinds))
|
||||
{
|
||||
const string channel = "Debug";
|
||||
// foreach (var channel in def.HapticsChannels)
|
||||
{
|
||||
if (fBinds.TryGetValue(channel, out var bind)) ret.BindFeedbackChannel(channel, bind);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -668,14 +668,6 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
public override bool BlocksInputWhenFocused { get; } = false;
|
||||
|
||||
private static readonly IReadOnlyCollection<string> DEBUG_HAPTIC_CHANNELS = new[]
|
||||
{
|
||||
"J0 Mono", "J0 Left", "J0 Right",
|
||||
"X0 Mono", "X0 Left", "X0 Right",
|
||||
"J1 Mono", "J1 Left", "J1 Right",
|
||||
"X1 Mono", "X1 Left", "X1 Right"
|
||||
};
|
||||
|
||||
public int ProgramRunLoop()
|
||||
{
|
||||
// needs to be done late, after the log console snaps on top
|
||||
|
@ -711,8 +703,9 @@ namespace BizHawk.Client.EmuHawk
|
|||
// ...but prepare haptics first, those get read in ProcessInput
|
||||
var finalHostController = (ControllerInputCoalescer) InputManager.ControllerInputCoalescer;
|
||||
// for now, vibrate the first gamepad when the Fast Forward hotkey is held, using the value from the previous (host) frame
|
||||
var debugVibrating = InputManager.ClientControls.IsPressed("Fast Forward") ? int.MaxValue : 0;
|
||||
foreach (var channel in DEBUG_HAPTIC_CHANNELS) finalHostController.SetHapticChannelStrength(channel, debugVibrating);
|
||||
InputManager.ActiveController.PrepareHapticsForHost(
|
||||
finalHostController,
|
||||
debug: InputManager.ClientControls.IsPressed("Fast Forward") ? int.MaxValue : 0);
|
||||
ProcessInput(
|
||||
_hotkeyCoalescer,
|
||||
finalHostController,
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
this.NormalControlsTab = new System.Windows.Forms.TabPage();
|
||||
this.AutofireControlsTab = new System.Windows.Forms.TabPage();
|
||||
this.AnalogControlsTab = new System.Windows.Forms.TabPage();
|
||||
this.FeedbacksTab = new System.Windows.Forms.TabPage();
|
||||
this.checkBoxAutoTab = new System.Windows.Forms.CheckBox();
|
||||
this.buttonOK = new System.Windows.Forms.Button();
|
||||
this.buttonCancel = new System.Windows.Forms.Button();
|
||||
|
@ -59,6 +60,7 @@
|
|||
this.tabControl1.Controls.Add(this.NormalControlsTab);
|
||||
this.tabControl1.Controls.Add(this.AutofireControlsTab);
|
||||
this.tabControl1.Controls.Add(this.AnalogControlsTab);
|
||||
this.tabControl1.Controls.Add(this.FeedbacksTab);
|
||||
this.tabControl1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tabControl1.Location = new System.Drawing.Point(3, 3);
|
||||
this.tabControl1.Name = "tabControl1";
|
||||
|
@ -95,6 +97,15 @@
|
|||
this.AnalogControlsTab.Text = "Analog Controls";
|
||||
this.AnalogControlsTab.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// FeedbacksTab
|
||||
//
|
||||
this.FeedbacksTab.Location = new System.Drawing.Point(4, 22);
|
||||
this.FeedbacksTab.Name = "FeedbacksTab";
|
||||
this.FeedbacksTab.Size = new System.Drawing.Size(554, 495);
|
||||
this.FeedbacksTab.TabIndex = 3;
|
||||
this.FeedbacksTab.Text = "Feedbacks";
|
||||
this.FeedbacksTab.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// checkBoxAutoTab
|
||||
//
|
||||
this.checkBoxAutoTab.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
|
@ -267,6 +278,7 @@
|
|||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
|
||||
private System.Windows.Forms.PictureBox pictureBox1;
|
||||
private System.Windows.Forms.TabPage AnalogControlsTab;
|
||||
private System.Windows.Forms.TabPage FeedbacksTab;
|
||||
private System.Windows.Forms.ContextMenuStrip contextMenuStrip1;
|
||||
private System.Windows.Forms.ToolTip toolTip1;
|
||||
private MenuButton btnMisc;
|
||||
|
|
|
@ -90,6 +90,11 @@ namespace BizHawk.Client.EmuHawk
|
|||
return new AnalogBindPanel(settings, buttons) { Dock = DockStyle.Fill, AutoScroll = true };
|
||||
}
|
||||
|
||||
private static Control CreateFeedbacksPanel(Dictionary<string, FeedbackBind> settings, List<string> buttons, Size size)
|
||||
{
|
||||
return new FeedbacksBindPanel(settings, buttons) { Dock = DockStyle.Fill, AutoScroll = true };
|
||||
}
|
||||
|
||||
private static readonly Regex ButtonMatchesPlayer = new Regex("^P(\\d+)\\s");
|
||||
|
||||
private void LoadToPanel<TBindValue>(
|
||||
|
@ -201,7 +206,8 @@ namespace BizHawk.Client.EmuHawk
|
|||
private void LoadPanels(
|
||||
IDictionary<string, Dictionary<string, string>> normal,
|
||||
IDictionary<string, Dictionary<string, string>> autofire,
|
||||
IDictionary<string, Dictionary<string, AnalogBind>> analog)
|
||||
IDictionary<string, Dictionary<string, AnalogBind>> analog,
|
||||
IDictionary<string, Dictionary<string, FeedbackBind>> haptics)
|
||||
{
|
||||
LoadToPanel(
|
||||
NormalControlsTab,
|
||||
|
@ -230,21 +236,30 @@ namespace BizHawk.Client.EmuHawk
|
|||
new AnalogBind("", 1.0f, 0.1f),
|
||||
CreateAnalogPanel
|
||||
);
|
||||
LoadToPanel(
|
||||
FeedbacksTab,
|
||||
_emulator.ControllerDefinition.Name,
|
||||
/*_emulator.ControllerDefinition.HapticsChannels*/new[] { "Debug" },
|
||||
_emulator.ControllerDefinition.CategoryLabels,
|
||||
haptics,
|
||||
new(string.Empty, string.Empty, 1.0f),
|
||||
CreateFeedbacksPanel);
|
||||
|
||||
if (AnalogControlsTab.Controls.Count == 0)
|
||||
{
|
||||
tabControl1.TabPages.Remove(AnalogControlsTab);
|
||||
}
|
||||
if (FeedbacksTab.Controls.Count == 0) tabControl1.TabPages.Remove(FeedbacksTab);
|
||||
}
|
||||
|
||||
private void LoadPanels(DefaultControls cd)
|
||||
{
|
||||
LoadPanels(cd.AllTrollers, cd.AllTrollersAutoFire, cd.AllTrollersAnalog);
|
||||
LoadPanels(cd.AllTrollers, cd.AllTrollersAutoFire, cd.AllTrollersAnalog, cd.AllTrollersFeedbacks);
|
||||
}
|
||||
|
||||
private void LoadPanels(Config c)
|
||||
{
|
||||
LoadPanels(c.AllTrollers, c.AllTrollersAutoFire, c.AllTrollersAnalog);
|
||||
LoadPanels(c.AllTrollers, c.AllTrollersAutoFire, c.AllTrollersAnalog, c.AllTrollersFeedbacks);
|
||||
}
|
||||
|
||||
private void SetControllerPicture(string controlName)
|
||||
|
@ -328,6 +343,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
ActOnControlCollection<ControllerConfigPanel>(NormalControlsTab, c => c.Save(_config.AllTrollers[_emulator.ControllerDefinition.Name]));
|
||||
ActOnControlCollection<ControllerConfigPanel>(AutofireControlsTab, c => c.Save(_config.AllTrollersAutoFire[_emulator.ControllerDefinition.Name]));
|
||||
ActOnControlCollection<AnalogBindPanel>(AnalogControlsTab, c => c.Save(_config.AllTrollersAnalog[_emulator.ControllerDefinition.Name]));
|
||||
ActOnControlCollection<FeedbacksBindPanel>(FeedbacksTab, c => c.Save(_config.AllTrollersFeedbacks[_emulator.ControllerDefinition.Name]));
|
||||
}
|
||||
|
||||
private void SaveToDefaults(DefaultControls cd)
|
||||
|
@ -335,6 +351,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
ActOnControlCollection<ControllerConfigPanel>(NormalControlsTab, c => c.Save(cd.AllTrollers[_emulator.ControllerDefinition.Name]));
|
||||
ActOnControlCollection<ControllerConfigPanel>(AutofireControlsTab, c => c.Save(cd.AllTrollersAutoFire[_emulator.ControllerDefinition.Name]));
|
||||
ActOnControlCollection<AnalogBindPanel>(AnalogControlsTab, c => c.Save(cd.AllTrollersAnalog[_emulator.ControllerDefinition.Name]));
|
||||
ActOnControlCollection<FeedbacksBindPanel>(FeedbacksTab, c => c.Save(cd.AllTrollersFeedbacks[_emulator.ControllerDefinition.Name]));
|
||||
}
|
||||
|
||||
private static void ActOnControlCollection<T>(Control c, Action<T> proc)
|
||||
|
@ -389,17 +406,21 @@ namespace BizHawk.Client.EmuHawk
|
|||
var tb1 = GetTabControl(NormalControlsTab.Controls);
|
||||
var tb2 = GetTabControl(AutofireControlsTab.Controls);
|
||||
var tb3 = GetTabControl(AnalogControlsTab.Controls);
|
||||
var tb4 = GetTabControl(FeedbacksTab.Controls);
|
||||
int? wasTabbedPage1 = null;
|
||||
int? wasTabbedPage2 = null;
|
||||
int? wasTabbedPage3 = null;
|
||||
int? wasTabbedPage4 = null;
|
||||
|
||||
if (tb1?.SelectedTab != null) { wasTabbedPage1 = tb1.SelectedIndex; }
|
||||
if (tb2?.SelectedTab != null) { wasTabbedPage2 = tb2.SelectedIndex; }
|
||||
if (tb3?.SelectedTab != null) { wasTabbedPage3 = tb3.SelectedIndex; }
|
||||
if (tb4?.SelectedTab != null) { wasTabbedPage4 = tb4.SelectedIndex; }
|
||||
|
||||
NormalControlsTab.Controls.Clear();
|
||||
AutofireControlsTab.Controls.Clear();
|
||||
AnalogControlsTab.Controls.Clear();
|
||||
FeedbacksTab.Controls.Clear();
|
||||
|
||||
// load panels directly from the default config.
|
||||
// this means that the changes are NOT committed. so "Cancel" works right and you
|
||||
|
@ -427,6 +448,12 @@ namespace BizHawk.Client.EmuHawk
|
|||
newTb3?.SelectTab(wasTabbedPage3.Value);
|
||||
}
|
||||
|
||||
if (wasTabbedPage4.HasValue)
|
||||
{
|
||||
var newTb4 = GetTabControl(FeedbacksTab.Controls);
|
||||
newTb4?.SelectTab(wasTabbedPage4.Value);
|
||||
}
|
||||
|
||||
tabControl1.ResumeLayout();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
#nullable enable
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using BizHawk.Client.Common;
|
||||
using BizHawk.Common.StringExtensions;
|
||||
using BizHawk.WinForms.Controls;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
public class FeedbackBindControl : UserControl
|
||||
{
|
||||
private readonly Container _components = new();
|
||||
|
||||
/// <summary>'+'-delimited e.g. <c>"Mono"</c>, <c>"Left"</c>, <c>"Left+Right"</c></summary>
|
||||
public string BoundChannels { get; private set; }
|
||||
|
||||
public string BoundGamepadPrefix { get; private set; }
|
||||
|
||||
public float Prescale { get; private set; }
|
||||
|
||||
public readonly string VChannelName;
|
||||
|
||||
public FeedbackBindControl(string vChannel, FeedbackBind existingBind, IHostInputAdapter hostInputAdapter)
|
||||
{
|
||||
BoundChannels = existingBind.Channel ?? string.Empty;
|
||||
BoundGamepadPrefix = existingBind.GamepadPrefix ?? string.Empty;
|
||||
Prescale = existingBind.IsZeroed ? 1.0f : existingBind.Prescale;
|
||||
VChannelName = vChannel;
|
||||
|
||||
SzTextBoxEx txtBoundPrefix = new() { ReadOnly = true, Size = new(19, 19) };
|
||||
ComboBox cbBoundChannel = new() { Enabled = false, Size = new(112, 24) };
|
||||
void UpdateDropdownAndLabel(string newPrefix)
|
||||
{
|
||||
txtBoundPrefix.Text = newPrefix;
|
||||
var wasSelected = (string) cbBoundChannel.SelectedItem;
|
||||
cbBoundChannel.Enabled = false;
|
||||
cbBoundChannel.SelectedIndex = -1;
|
||||
cbBoundChannel.Items.Clear();
|
||||
if (hostInputAdapter.GetHapticsChannels().TryGetValue(newPrefix, out var channels) && channels.Count != 0)
|
||||
{
|
||||
var hasLeft = false;
|
||||
var hasRight = false;
|
||||
foreach (var hostChannel in channels)
|
||||
{
|
||||
cbBoundChannel.Items.Add(hostChannel);
|
||||
if (hostChannel == "Left") hasLeft = true;
|
||||
else if (hostChannel == "Right") hasRight = true;
|
||||
}
|
||||
if (hasLeft && hasRight) cbBoundChannel.Items.Add("Left+Right");
|
||||
cbBoundChannel.SelectedItem = wasSelected;
|
||||
cbBoundChannel.Enabled = true;
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(newPrefix))
|
||||
{
|
||||
cbBoundChannel.Items.Add("(none available)");
|
||||
cbBoundChannel.SelectedIndex = 0;
|
||||
}
|
||||
}
|
||||
UpdateDropdownAndLabel(BoundGamepadPrefix);
|
||||
cbBoundChannel.SelectedIndexChanged += (changedSender, _)
|
||||
=> BoundChannels = (string?) ((ComboBox) changedSender).SelectedItem ?? string.Empty;
|
||||
SingleRowFLP flpBindReadout = new() { Controls = { txtBoundPrefix, cbBoundChannel, new LabelEx { Text = vChannel } } };
|
||||
|
||||
Timer timer = new(_components);
|
||||
SzButtonEx btnBind = new() { Size = new(75, 23), Text = "Bind!" };
|
||||
void UpdateListeningState(bool newState)
|
||||
{
|
||||
if (newState)
|
||||
{
|
||||
Input.Instance.StartListeningForAxisEvents();
|
||||
timer.Start();
|
||||
btnBind.Text = "Cancel!";
|
||||
}
|
||||
else
|
||||
{
|
||||
timer.Stop();
|
||||
Input.Instance.StopListeningForAxisEvents();
|
||||
btnBind.Text = "Bind!";
|
||||
}
|
||||
}
|
||||
var isListening = false;
|
||||
timer.Tick += (_, _) =>
|
||||
{
|
||||
var bindValue = Input.Instance.GetNextAxisEvent();
|
||||
if (bindValue == null) return;
|
||||
UpdateListeningState(isListening = false);
|
||||
UpdateDropdownAndLabel(BoundGamepadPrefix = bindValue.SubstringBefore(' ') + ' ');
|
||||
};
|
||||
btnBind.Click += (_, _) => UpdateListeningState(isListening = !isListening);
|
||||
SzButtonEx btnUnbind = new() { Size = new(75, 23), Text = "Unbind!" };
|
||||
btnUnbind.Click += (_, _) => UpdateDropdownAndLabel(BoundGamepadPrefix = string.Empty);
|
||||
LocSingleColumnFLP flpButtons = new() { Controls = { btnBind, btnUnbind } };
|
||||
|
||||
LabelEx lblPrescale = new() { Margin = new(0, 0, 0, 24) };
|
||||
TransparentTrackBar tbPrescale = new() { Maximum = 20, Size = new(96, 45), TickFrequency = 5 };
|
||||
tbPrescale.ValueChanged += (changedSender, _) =>
|
||||
{
|
||||
Prescale = ((TrackBar) changedSender).Value / 10.0f;
|
||||
lblPrescale.Text = $"Pre-scaled by: {Prescale:F1}x";
|
||||
};
|
||||
tbPrescale.Value = (int) (Prescale * 10.0f);
|
||||
LocSzSingleRowFLP flpPrescale = new() { Controls = { lblPrescale, tbPrescale }, Size = new(200, 32) };
|
||||
|
||||
SuspendLayout();
|
||||
AutoScaleDimensions = new(6.0f, 13.0f);
|
||||
AutoScaleMode = AutoScaleMode.Font;
|
||||
Size = new(378, 99);
|
||||
Controls.Add(new SingleColumnFLP
|
||||
{
|
||||
Controls =
|
||||
{
|
||||
flpBindReadout,
|
||||
new SingleRowFLP { Controls = { flpButtons, flpPrescale } }
|
||||
}
|
||||
});
|
||||
ResumeLayout();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing) _components.Dispose();
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
#nullable enable
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using BizHawk.Client.Common;
|
||||
using BizHawk.WinForms.Controls;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
public class FeedbacksBindPanel : UserControl
|
||||
{
|
||||
private readonly FlowLayoutPanel _flpMain = new SingleColumnFLP();
|
||||
|
||||
private readonly IDictionary<string, FeedbackBind> _realConfigObject;
|
||||
|
||||
public FeedbacksBindPanel(IDictionary<string, FeedbackBind> realConfigObject, ICollection<string>? realConfigButtons = null)
|
||||
{
|
||||
_realConfigObject = realConfigObject;
|
||||
_flpMain.Controls.Add(new LabelEx { Text = "To bind, click \"Bind!\", move an axis (e.g. analog stick) on the desired gamepad, and choose from the dropdown.\nNote: haptic feedback won't work if your gamepad is shown as \"J#\" or if your input method is OpenTK." });
|
||||
var adapter = Input.Instance.Adapter;
|
||||
foreach (var buttonName in realConfigButtons ?? realConfigObject.Keys)
|
||||
{
|
||||
_flpMain.Controls.Add(new FeedbackBindControl(buttonName, _realConfigObject[buttonName], adapter));
|
||||
}
|
||||
SuspendLayout();
|
||||
Controls.Add(_flpMain);
|
||||
ResumeLayout();
|
||||
}
|
||||
|
||||
/// <param name="saveConfigObject">if non-null, save to possibly different config object than originally initialized from</param>
|
||||
public void Save(IDictionary<string, FeedbackBind>? saveConfigObject = null)
|
||||
{
|
||||
var saveTo = saveConfigObject ?? _realConfigObject;
|
||||
foreach (var c in _flpMain.Controls.OfType<FeedbackBindControl>())
|
||||
{
|
||||
if (string.IsNullOrEmpty(c.BoundGamepadPrefix)) continue;
|
||||
foreach (var channel in c.BoundChannels.Split('+'))
|
||||
{
|
||||
saveTo[c.VChannelName] = new(c.BoundGamepadPrefix, channel, c.Prescale);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
namespace BizHawk.Emulation.Common
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BizHawk.Emulation.Common
|
||||
{
|
||||
/// <summary>
|
||||
/// A empty implementation of IController that represents the lack of
|
||||
|
|
Loading…
Reference in New Issue