redo some of client input and hotkey handling
This commit is contained in:
parent
003b7ebebf
commit
9355bc0f2e
|
@ -14,6 +14,20 @@ namespace BizHawk.MultiClient
|
|||
private List<string> removeFromForcePressedButtons = new List<string>();
|
||||
private List<string> programmaticallyPressedButtons = new List<string>();
|
||||
|
||||
public List<string> SearchBindings(string button)
|
||||
{
|
||||
var ret = new List<string>();
|
||||
foreach (var kvp in bindings)
|
||||
{
|
||||
foreach (var bound_button in kvp.Value)
|
||||
{
|
||||
if (bound_button == button)
|
||||
ret.Add(kvp.Key);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public Controller(ControllerDefinition definition)
|
||||
{
|
||||
type = definition;
|
||||
|
@ -67,6 +81,7 @@ namespace BizHawk.MultiClient
|
|||
return false;
|
||||
}
|
||||
|
||||
//zeromus - TODO - this is gross!!!
|
||||
if (Global.Config.AllowUD_LR == false)
|
||||
{
|
||||
string prefix;
|
||||
|
@ -93,7 +108,7 @@ namespace BizHawk.MultiClient
|
|||
bool sticky = stickyButtons[button];
|
||||
|
||||
foreach (var control in bindings[button])
|
||||
if (Input.IsPressed(control))
|
||||
if (Input.Instance.IsPressed(control))
|
||||
return sticky ? false : true;
|
||||
|
||||
return sticky ? true : false;
|
||||
|
|
|
@ -1,143 +1,187 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using SlimDX.DirectInput;
|
||||
|
||||
//maybe todo - split into an event processor class (which can grab events from the main input class and be used to step through them independently)
|
||||
|
||||
namespace BizHawk.MultiClient
|
||||
{
|
||||
public static class Input
|
||||
public class Input
|
||||
{
|
||||
public static Input Instance { get; private set; }
|
||||
Thread UpdateThread;
|
||||
|
||||
private Input()
|
||||
{
|
||||
UpdateThread = new Thread(UpdateThreadProc);
|
||||
UpdateThread.IsBackground = true;
|
||||
UpdateThread.Start();
|
||||
}
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
KeyInput.Initialize();
|
||||
GamePad.Initialize();
|
||||
Instance = new Input();
|
||||
}
|
||||
|
||||
public static void Update()
|
||||
public enum InputEventType
|
||||
{
|
||||
KeyInput.Update();
|
||||
GamePad.UpdateAll();
|
||||
Press, Release
|
||||
}
|
||||
|
||||
public static bool IsPressed(string control)
|
||||
public struct LogicalButton
|
||||
{
|
||||
if (Global.Config.AcceptBackgroundInput == false && Form.ActiveForm == null)
|
||||
return false; // application isn't active and background input is disabled
|
||||
|
||||
// Check joystick first, its easier
|
||||
if (control.StartsWith("J1 ")) return GetGamePad(0, control.Substring(3));
|
||||
if (control.StartsWith("J2 ")) return GetGamePad(1, control.Substring(3));
|
||||
if (control.StartsWith("J3 ")) return GetGamePad(2, control.Substring(3));
|
||||
if (control.StartsWith("J4 ")) return GetGamePad(3, control.Substring(3));
|
||||
|
||||
// Keyboard time.
|
||||
// Keyboard bindings are significantly less free-form than they were previously.
|
||||
// They are no longer just a list of keys which must be pressed simultaneously.
|
||||
// Bindings are assumed to be in the form of 0, 1, 2, or 3 modifiers (Ctrl, Alt, Shift),
|
||||
// plus one non-modifier key, which is at the end.
|
||||
// It is not possible to bind to two non-modifier keys together as a chorded hotkey.
|
||||
|
||||
|
||||
int lastCombinerPosition = control.LastIndexOf('+');
|
||||
if (lastCombinerPosition < 0)
|
||||
{
|
||||
// No modifiers in this key binding.
|
||||
|
||||
// Verify that no modifiers are currently pressed.
|
||||
if (KeyInput.CtrlModifier || KeyInput.ShiftModifier || KeyInput.AltModifier)
|
||||
return false;
|
||||
|
||||
Key k = (Key) Enum.Parse(typeof (Key), control, true);
|
||||
return KeyInput.IsPressed(k);
|
||||
}
|
||||
|
||||
// 1 or more modifiers present in binding. First, lets identify the non-modifier key and check if it's pressed.
|
||||
string nonModifierString = control.Substring(lastCombinerPosition+1);
|
||||
Key nonModifierKey = (Key)Enum.Parse(typeof(Key), nonModifierString, true);
|
||||
if (KeyInput.IsPressed(nonModifierKey) == false)
|
||||
return false; // non-modifier key isn't pressed anyway, exit out
|
||||
|
||||
// non-modifier key IS pressed, now we need to ensure the modifiers match exactly
|
||||
if (control.Contains("Ctrl+") ^ KeyInput.CtrlModifier) return false;
|
||||
if (control.Contains("Shift+") ^ KeyInput.ShiftModifier) return false;
|
||||
if (control.Contains("Alt+") ^ KeyInput.AltModifier) return false;
|
||||
|
||||
// You have passed all my tests, you may consider yourself pressed.
|
||||
// Man, I'm winded.
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool IsPressedSingle(string control)
|
||||
{
|
||||
if (string.IsNullOrEmpty(control))
|
||||
return false;
|
||||
|
||||
if (control.StartsWith("J1 ")) return GetGamePad(0, control.Substring(3));
|
||||
if (control.StartsWith("J2 ")) return GetGamePad(1, control.Substring(3));
|
||||
if (control.StartsWith("J3 ")) return GetGamePad(2, control.Substring(3));
|
||||
if (control.StartsWith("J4 ")) return GetGamePad(3, control.Substring(3));
|
||||
|
||||
if (control.Contains("RightShift"))
|
||||
control = control.Replace("RightShift", "LeftShift");
|
||||
if (control.Contains("RightControl"))
|
||||
control = control.Replace("RightControl", "LeftControl");
|
||||
if (control.Contains("RightAlt"))
|
||||
control = control.Replace("RightAlt", "LeftAlt");
|
||||
if (control.Contains("Ctrl"))
|
||||
control = control.Replace("Ctrl", "LeftControl");
|
||||
|
||||
if (control.Contains("Shift") && control != "LeftShift")
|
||||
control = control.Replace("Shift", "LeftShift");
|
||||
if (control.Contains("Control") && control.Trim() != "LeftControl")
|
||||
control = control.Replace("Control", "LeftControl");
|
||||
if (control.Contains("Ctrl") && control.Trim() != "LeftControl")
|
||||
control = control.Replace("Control", "LeftControl");
|
||||
if (control.Contains("Alt") && control != "LeftAlt")
|
||||
control = control.Replace("Alt", "LeftAlt");
|
||||
|
||||
Key k = (Key)Enum.Parse(typeof(Key), control, true);
|
||||
return KeyInput.IsPressed(k);
|
||||
}
|
||||
|
||||
private static bool GetGamePad(int index, string control)
|
||||
{
|
||||
if (index >= GamePad.Devices.Count)
|
||||
return false;
|
||||
|
||||
if (control == "Up") return GamePad.Devices[index].Up;
|
||||
if (control == "Down") return GamePad.Devices[index].Down;
|
||||
if (control == "Left") return GamePad.Devices[index].Left;
|
||||
if (control == "Right") return GamePad.Devices[index].Right;
|
||||
|
||||
if (control.StartsWith("B"))
|
||||
public LogicalButton(string button, Keys modifiers)
|
||||
{
|
||||
int buttonIndex = int.Parse(control.Substring(1)) - 1;
|
||||
if (buttonIndex >= GamePad.Devices[index].Buttons.Length)
|
||||
return false;
|
||||
return GamePad.Devices[index].Buttons[buttonIndex];
|
||||
Button = button;
|
||||
Modifiers = modifiers;
|
||||
}
|
||||
public string Button;
|
||||
public Keys Modifiers;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string ret = "";
|
||||
if ((Modifiers & Keys.Control) != 0) ret += "Ctrl+";
|
||||
if ((Modifiers & Keys.Alt) != 0) ret += "Alt+";
|
||||
if ((Modifiers & Keys.Shift) != 0) ret += "Shift+";
|
||||
ret += Button;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
public class InputEvent
|
||||
{
|
||||
public LogicalButton LogicalButton;
|
||||
public InputEventType EventType;
|
||||
}
|
||||
|
||||
|
||||
//coalesces events back into instantaneous states
|
||||
class InputCoalescer
|
||||
{
|
||||
public void Receive(InputEvent ie)
|
||||
{
|
||||
bool state = ie.EventType == InputEventType.Press;
|
||||
State[ie.LogicalButton.ToString()] = state;
|
||||
LogicalButton unmodified = ie.LogicalButton;
|
||||
unmodified.Modifiers = Keys.None;
|
||||
UnmodifiedState[unmodified.ToString()] = state;
|
||||
}
|
||||
|
||||
return false;
|
||||
public WorkingDictionary<string, bool> State = new WorkingDictionary<string, bool>();
|
||||
|
||||
public WorkingDictionary<string, bool> UnmodifiedState = new WorkingDictionary<string, bool>();
|
||||
}
|
||||
|
||||
public static string GetPressedKey()
|
||||
InputCoalescer Coalescer = new InputCoalescer();
|
||||
|
||||
|
||||
WorkingDictionary<string, bool> LastState = new WorkingDictionary<string, bool>();
|
||||
|
||||
|
||||
HashSet<string> Ignore = new HashSet<string>(new[] { "LeftShift", "RightShift" });
|
||||
void HandleButton(string button, bool newState)
|
||||
{
|
||||
// Poll Joystick input
|
||||
for (int j = 0; j < GamePad.Devices.Count; j++)
|
||||
if (Ignore.Contains(button)) return;
|
||||
if (LastState[button] && newState) return;
|
||||
if (!LastState[button] && !newState) return;
|
||||
|
||||
var ie = new InputEvent();
|
||||
ie.EventType = newState ? InputEventType.Press : InputEventType.Release;
|
||||
ie.LogicalButton = new LogicalButton(button, _Modifiers);
|
||||
_NewEvents.Add(ie);
|
||||
LastState[button] = newState;
|
||||
}
|
||||
|
||||
Keys _Modifiers;
|
||||
List<InputEvent> _NewEvents = new List<InputEvent>();
|
||||
|
||||
//TODO - maybe need clearevents for various purposes? maybe not.
|
||||
Queue<InputEvent> InputEvents = new Queue<InputEvent>();
|
||||
public InputEvent DequeueEvent()
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
if (GamePad.Devices[j].Up) return "J" + (j+1) + " Up";
|
||||
if (GamePad.Devices[j].Down) return "J" + (j+1) + " Down";
|
||||
if (GamePad.Devices[j].Left) return "J" + (j+1) + " Left";
|
||||
if (GamePad.Devices[j].Right) return "J" + (j+1) + " Right";
|
||||
|
||||
var buttons = GamePad.Devices[j].Buttons;
|
||||
for (int b=0; b<buttons.Length; b++)
|
||||
{
|
||||
if (buttons[b])
|
||||
return "J" + (j+1) + " B" + (b+1);
|
||||
}
|
||||
if (InputEvents.Count == 0) return null;
|
||||
else return InputEvents.Dequeue();
|
||||
}
|
||||
}
|
||||
void EnqueueEvent(InputEvent ie)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
InputEvents.Enqueue(ie);
|
||||
Coalescer.Receive(ie);
|
||||
}
|
||||
}
|
||||
|
||||
return KeyInput.GetPressedKey();
|
||||
public bool CheckState(string button) { lock (this) return Coalescer.State[button]; }
|
||||
public bool CheckStateUnmodified(string button) { lock (this) return Coalescer.UnmodifiedState[button]; }
|
||||
|
||||
void UpdateThreadProc()
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
KeyInput.Update();
|
||||
GamePad.UpdateAll();
|
||||
|
||||
_Modifiers = KeyInput.GetModifierKeysAsKeys();
|
||||
_NewEvents.Clear();
|
||||
|
||||
//analyze keys
|
||||
foreach (var key in KeyInput.State.PressedKeys) HandleButton(key.ToString(), true);
|
||||
foreach (var key in KeyInput.State.ReleasedKeys) HandleButton(key.ToString(), false);
|
||||
|
||||
//analyze joysticks
|
||||
for (int i = 0; i < GamePad.Devices.Count; i++)
|
||||
{
|
||||
var pad = GamePad.Devices[i];
|
||||
string jname = "J" + (i + 1) + " ";
|
||||
HandleButton(jname + "Up", pad.Up);
|
||||
HandleButton(jname + "Down", pad.Down);
|
||||
HandleButton(jname + "Left", pad.Left);
|
||||
HandleButton(jname + "Right", pad.Right);
|
||||
|
||||
for (int b = 0; b < pad.Buttons.Length; b++)
|
||||
HandleButton(jname + "B" + (b + 1), pad.Buttons[b]);
|
||||
}
|
||||
|
||||
bool swallow = (Global.Config.AcceptBackgroundInput == false && Form.ActiveForm == null);
|
||||
|
||||
foreach (var ie in _NewEvents)
|
||||
{
|
||||
//events are swallowed in some cases:
|
||||
if (ie.EventType == InputEventType.Press && swallow)
|
||||
{ }
|
||||
else
|
||||
EnqueueEvent(ie);
|
||||
}
|
||||
|
||||
//arbitrary selection of polling frequency:
|
||||
Thread.Sleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void Update()
|
||||
{
|
||||
//TODO - for some reason, we may want to control when the next event processing step happens
|
||||
//so i will leave this method here for now..
|
||||
}
|
||||
|
||||
public bool IsPressed(string control)
|
||||
{
|
||||
return Instance.CheckState(control);
|
||||
}
|
||||
|
||||
public string GetNextPressedButtonOrNull()
|
||||
{
|
||||
InputEvent ie = Instance.DequeueEvent();
|
||||
if (ie == null) return null;
|
||||
if (ie.EventType == InputEventType.Release) return null;
|
||||
return ie.LogicalButton.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -113,6 +113,15 @@ namespace BizHawk.MultiClient
|
|||
}
|
||||
}
|
||||
|
||||
public static System.Windows.Forms.Keys GetModifierKeysAsKeys()
|
||||
{
|
||||
System.Windows.Forms.Keys ret = System.Windows.Forms.Keys.None;
|
||||
if (ShiftModifier) ret |= System.Windows.Forms.Keys.Shift;
|
||||
if (CtrlModifier) ret |= System.Windows.Forms.Keys.Control;
|
||||
if (AltModifier) ret |= System.Windows.Forms.Keys.Alt;
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static string GetModifierKeys()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder(16);
|
||||
|
|
|
@ -314,7 +314,7 @@ namespace BizHawk.MultiClient
|
|||
{
|
||||
for (; ; )
|
||||
{
|
||||
Input.Update();
|
||||
Input.Instance.Update();
|
||||
CheckHotkeys();
|
||||
|
||||
StepRunLoop_Core();
|
||||
|
@ -956,27 +956,198 @@ namespace BizHawk.MultiClient
|
|||
[System.Security.SuppressUnmanagedCodeSecurity, DllImport("User32.dll", CharSet = CharSet.Auto)]
|
||||
public static extern bool PeekMessage(out Message msg, IntPtr hWnd, UInt32 msgFilterMin, UInt32 msgFilterMax, UInt32 flags);
|
||||
|
||||
void OnSelectSlot(int num)
|
||||
{
|
||||
SaveSlot = num;
|
||||
SaveSlotSelectedMessage();
|
||||
UpdateStatusSlots();
|
||||
}
|
||||
|
||||
public void CheckHotkeys()
|
||||
{
|
||||
if (Global.ClientControls["ToolBox"])
|
||||
for(;;)
|
||||
{
|
||||
LoadToolBox();
|
||||
Global.ClientControls.UnpressButton("ToolBox");
|
||||
}
|
||||
var ie = Input.Instance.DequeueEvent();
|
||||
if(ie == null) break;
|
||||
|
||||
if (Global.ClientControls["Quick Save State"])
|
||||
{
|
||||
if (!IsNullEmulator())
|
||||
SaveState("QuickSave" + SaveSlot.ToString());
|
||||
Global.ClientControls.UnpressButton("Quick Save State");
|
||||
}
|
||||
//TODO - wonder what happens if we pop up something interactive as a response to one of these hotkeys? may need to purge further processing
|
||||
|
||||
if (Global.ClientControls["Quick Load State"])
|
||||
{
|
||||
if (!IsNullEmulator())
|
||||
LoadState("QuickSave" + SaveSlot.ToString());
|
||||
Global.ClientControls.UnpressButton("Quick Load State");
|
||||
}
|
||||
//TODO - deal with these later somehow
|
||||
if(ie.EventType == Input.InputEventType.Release) return;
|
||||
|
||||
var triggers = Global.ClientControls.SearchBindings(ie.LogicalButton.ToString());
|
||||
foreach(var trigger in triggers)
|
||||
{
|
||||
//todo - could have these in a table somehow ?
|
||||
switch (trigger)
|
||||
{
|
||||
case "ToolBox":
|
||||
LoadToolBox();
|
||||
break;
|
||||
|
||||
case "Quick Save State":
|
||||
if (!IsNullEmulator())
|
||||
SaveState("QuickSave" + SaveSlot.ToString());
|
||||
break;
|
||||
|
||||
case "Quick Load State":
|
||||
if (!IsNullEmulator())
|
||||
LoadState("QuickSave" + SaveSlot.ToString());
|
||||
break;
|
||||
|
||||
case "Unthrottle":
|
||||
unthrottled ^= true;
|
||||
Global.RenderPanel.AddMessage("Unthrottled: " + unthrottled);
|
||||
break;
|
||||
|
||||
case "Hard Reset":
|
||||
LoadRom(CurrentlyOpenRom);
|
||||
break;
|
||||
|
||||
case "Screenshot":
|
||||
TakeScreenshot();
|
||||
break;
|
||||
|
||||
case "SaveSlot0": if (!IsNullEmulator()) SaveState("QuickSave0"); break;
|
||||
case "SaveSlot1": if (!IsNullEmulator()) SaveState("QuickSave1"); break;
|
||||
case "SaveSlot2": if (!IsNullEmulator()) SaveState("QuickSave2"); break;
|
||||
case "SaveSlot3": if (!IsNullEmulator()) SaveState("QuickSave3"); break;
|
||||
case "SaveSlot4": if (!IsNullEmulator()) SaveState("QuickSave4"); break;
|
||||
case "SaveSlot5": if (!IsNullEmulator()) SaveState("QuickSave5"); break;
|
||||
case "SaveSlot6": if (!IsNullEmulator()) SaveState("QuickSave6"); break;
|
||||
case "SaveSlot7": if (!IsNullEmulator()) SaveState("QuickSave7"); break;
|
||||
case "SaveSlot8": if (!IsNullEmulator()) SaveState("QuickSave8"); break;
|
||||
case "SaveSlot9": if (!IsNullEmulator()) SaveState("QuickSave9"); break;
|
||||
case "LoadSlot0": if (!IsNullEmulator()) LoadState("QuickSave0"); break;
|
||||
case "LoadSlot1": if (!IsNullEmulator()) LoadState("QuickSave1"); break;
|
||||
case "LoadSlot2": if (!IsNullEmulator()) LoadState("QuickSave2"); break;
|
||||
case "LoadSlot3": if (!IsNullEmulator()) LoadState("QuickSave3"); break;
|
||||
case "LoadSlot4": if (!IsNullEmulator()) LoadState("QuickSave4"); break;
|
||||
case "LoadSlot5": if (!IsNullEmulator()) LoadState("QuickSave5"); break;
|
||||
case "LoadSlot6": if (!IsNullEmulator()) LoadState("QuickSave6"); break;
|
||||
case "LoadSlot7": if (!IsNullEmulator()) LoadState("QuickSave7"); break;
|
||||
case "LoadSlot8": if (!IsNullEmulator()) LoadState("QuickSave8"); break;
|
||||
case "LoadSlot9": if (!IsNullEmulator()) LoadState("QuickSave9"); break;
|
||||
case "SelectSlot0": OnSelectSlot(0); break;
|
||||
case "SelectSlot1": OnSelectSlot(1); break;
|
||||
case "SelectSlot2": OnSelectSlot(2); break;
|
||||
case "SelectSlot3": OnSelectSlot(3); break;
|
||||
case "SelectSlot4": OnSelectSlot(4); break;
|
||||
case "SelectSlot5": OnSelectSlot(5); break;
|
||||
case "SelectSlot6": OnSelectSlot(6); break;
|
||||
case "SelectSlot7": OnSelectSlot(7); break;
|
||||
case "SelectSlot8": OnSelectSlot(8); break;
|
||||
case "SelectSlot9": OnSelectSlot(9); break;
|
||||
|
||||
case "Toggle Fullscreen": ToggleFullscreen(); break;
|
||||
case "Save Named State": SaveStateAs(); break;
|
||||
case "Load Named State": LoadStateAs(); break;
|
||||
case "Previous Slot": PreviousSlot(); break;
|
||||
case "Next Slot": NextSlot(); break;
|
||||
case "Ram Watch": LoadRamWatch(); break;
|
||||
case "Ram Search": LoadRamSearch(); break;
|
||||
case "Ram Poke":
|
||||
{
|
||||
RamPoke r = new RamPoke();
|
||||
r.Show();
|
||||
break;
|
||||
}
|
||||
case "Hex Editor": LoadHexEditor(); break;
|
||||
case "Lua Console":
|
||||
{
|
||||
var window = new BizHawk.MultiClient.tools.LuaWindow();
|
||||
window.Show();
|
||||
break;
|
||||
}
|
||||
case "Cheats": LoadCheatsWindow(); break;
|
||||
case "Open ROM":
|
||||
{
|
||||
OpenROM();
|
||||
break;
|
||||
}
|
||||
|
||||
case "Close ROM": CloseROM(); break;
|
||||
|
||||
case "Display FPS": ToggleFPS(); break;
|
||||
|
||||
case "Display FrameCounter": ToggleFrameCounter(); break;
|
||||
case "Display LagCounter": ToggleLagCounter(); break;
|
||||
case "Display Input": ToggleInputDisplay(); break;
|
||||
case "Toggle Read Only": ToggleReadOnly(); break;
|
||||
case "Play Movie":
|
||||
{
|
||||
PlayMovie();
|
||||
break;
|
||||
}
|
||||
case "Record Movie":
|
||||
{
|
||||
RecordMovie();
|
||||
break;
|
||||
}
|
||||
|
||||
case "Stop Movie": StopUserMovie(); break;
|
||||
case "Play Beginning": PlayMovieFromBeginning(); break;
|
||||
case "Volume Up": VolumeUp(); break;
|
||||
case "Volume Down": VolumeDown(); break;
|
||||
case "Soft Reset": SoftReset(); break;
|
||||
|
||||
case "Toggle MultiTrack":
|
||||
{
|
||||
Global.MainForm.UserMovie.MultiTrack.IsActive = !Global.MainForm.UserMovie.MultiTrack.IsActive;
|
||||
if (Global.MainForm.UserMovie.MultiTrack.IsActive)
|
||||
{
|
||||
Global.RenderPanel.AddMessage("MultiTrack Enabled");
|
||||
Global.RenderPanel.MT = "Recording None";
|
||||
}
|
||||
else
|
||||
Global.RenderPanel.AddMessage("MultiTrack Disabled");
|
||||
Global.MainForm.UserMovie.MultiTrack.RecordAll = false;
|
||||
Global.MainForm.UserMovie.MultiTrack.CurrentPlayer = 0;
|
||||
break;
|
||||
}
|
||||
case "Increment Player":
|
||||
{
|
||||
Global.MainForm.UserMovie.MultiTrack.CurrentPlayer++;
|
||||
Global.MainForm.UserMovie.MultiTrack.RecordAll = false;
|
||||
if (Global.MainForm.UserMovie.MultiTrack.CurrentPlayer > 5) //TODO: Replace with console's maximum or current maximum players??!
|
||||
{
|
||||
Global.MainForm.UserMovie.MultiTrack.CurrentPlayer = 1;
|
||||
}
|
||||
Global.RenderPanel.MT = "Recording Player " + Global.MainForm.UserMovie.MultiTrack.CurrentPlayer.ToString();
|
||||
break;
|
||||
}
|
||||
|
||||
case "Decrement Player":
|
||||
{
|
||||
Global.MainForm.UserMovie.MultiTrack.CurrentPlayer--;
|
||||
Global.MainForm.UserMovie.MultiTrack.RecordAll = false;
|
||||
if (Global.MainForm.UserMovie.MultiTrack.CurrentPlayer < 1)
|
||||
{
|
||||
Global.MainForm.UserMovie.MultiTrack.CurrentPlayer = 5;//TODO: Replace with console's maximum or current maximum players??!
|
||||
}
|
||||
Global.RenderPanel.MT = "Recording Player " + Global.MainForm.UserMovie.MultiTrack.CurrentPlayer.ToString();
|
||||
break;
|
||||
}
|
||||
case "Record All":
|
||||
{
|
||||
Global.MainForm.UserMovie.MultiTrack.CurrentPlayer = 0;
|
||||
Global.MainForm.UserMovie.MultiTrack.RecordAll = true;
|
||||
Global.RenderPanel.MT = "Recording All";
|
||||
break;
|
||||
}
|
||||
case "Record None":
|
||||
{
|
||||
Global.MainForm.UserMovie.MultiTrack.CurrentPlayer = 0;
|
||||
Global.MainForm.UserMovie.MultiTrack.RecordAll = false;
|
||||
Global.RenderPanel.MT = "Recording None";
|
||||
break;
|
||||
}
|
||||
|
||||
} //switch(trigger)
|
||||
|
||||
} //foreach triggered hotkey
|
||||
|
||||
} //foreach event
|
||||
|
||||
//the pause hotkey is ignored when we are frame advancing
|
||||
if (!Global.ClientControls.IsPressed("Frame Advance"))
|
||||
|
@ -991,258 +1162,6 @@ namespace BizHawk.MultiClient
|
|||
}
|
||||
}
|
||||
|
||||
if (Global.ClientControls.IsPressed("Unthrottle"))
|
||||
{
|
||||
Global.ClientControls.UnpressButton("Unthrottle");
|
||||
unthrottled ^= true;
|
||||
Global.RenderPanel.AddMessage("Unthrottled: " + unthrottled);
|
||||
}
|
||||
|
||||
if (Global.ClientControls["Hard Reset"])
|
||||
{
|
||||
Global.ClientControls.UnpressButton("Hard Reset");
|
||||
LoadRom(CurrentlyOpenRom);
|
||||
}
|
||||
|
||||
if (Global.ClientControls["Screenshot"])
|
||||
{
|
||||
Global.ClientControls.UnpressButton("Screenshot");
|
||||
TakeScreenshot();
|
||||
}
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
if (Global.ClientControls["SaveSlot" + i.ToString()])
|
||||
{
|
||||
if (!IsNullEmulator())
|
||||
SaveState("QuickSave" + i.ToString());
|
||||
Global.ClientControls.UnpressButton("LoadSlot" + i.ToString());
|
||||
Global.ClientControls.UnpressButton("SaveSlot" + i.ToString());
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
if (Global.ClientControls["LoadSlot" + i.ToString()])
|
||||
{
|
||||
if (!IsNullEmulator())
|
||||
LoadState("QuickSave" + i.ToString());
|
||||
Global.ClientControls.UnpressButton("LoadSlot" + i.ToString());
|
||||
Global.ClientControls.UnpressButton("SaveSlot" + i.ToString());
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
if (Global.ClientControls["SelectSlot" + i.ToString()])
|
||||
{
|
||||
SaveSlot = i;
|
||||
SaveSlotSelectedMessage();
|
||||
UpdateStatusSlots();
|
||||
Global.ClientControls.UnpressButton("SelectSlot" + i.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
if (Global.ClientControls["Toggle Fullscreen"])
|
||||
{
|
||||
Global.ClientControls.UnpressButton("Toggle Fullscreen");
|
||||
ToggleFullscreen();
|
||||
}
|
||||
|
||||
if (Global.ClientControls["Save Named State"])
|
||||
{
|
||||
SaveStateAs();
|
||||
Global.ClientControls.UnpressButton("Save Named State");
|
||||
}
|
||||
|
||||
if (Global.ClientControls["Load Named State"])
|
||||
{
|
||||
LoadStateAs();
|
||||
Global.ClientControls.UnpressButton("Load Named State");
|
||||
}
|
||||
|
||||
if (Global.ClientControls["Previous Slot"])
|
||||
{
|
||||
PreviousSlot();
|
||||
Global.ClientControls.UnpressButton("Previous Slot");
|
||||
}
|
||||
|
||||
if (Global.ClientControls["Next Slot"])
|
||||
{
|
||||
NextSlot();
|
||||
Global.ClientControls.UnpressButton("Next Slot");
|
||||
}
|
||||
|
||||
if (Global.ClientControls["Ram Watch"])
|
||||
{
|
||||
LoadRamWatch();
|
||||
Global.ClientControls.UnpressButton("Ram Watch");
|
||||
}
|
||||
|
||||
if (Global.ClientControls["Ram Search"])
|
||||
{
|
||||
LoadRamSearch();
|
||||
Global.ClientControls.UnpressButton("Ram Search");
|
||||
}
|
||||
|
||||
if (Global.ClientControls["Ram Poke"])
|
||||
{
|
||||
RamPoke r = new RamPoke();
|
||||
r.Show();
|
||||
Global.ClientControls.UnpressButton("Ram Poke");
|
||||
}
|
||||
|
||||
if (Global.ClientControls["Hex Editor"])
|
||||
{
|
||||
LoadHexEditor();
|
||||
Global.ClientControls.UnpressButton("Hex Editor");
|
||||
}
|
||||
|
||||
if (Global.ClientControls["Lua Console"])
|
||||
{
|
||||
var window = new BizHawk.MultiClient.tools.LuaWindow();
|
||||
window.Show();
|
||||
Global.ClientControls.UnpressButton("Lua Console");
|
||||
}
|
||||
|
||||
if (Global.ClientControls["Cheats"])
|
||||
{
|
||||
LoadCheatsWindow();
|
||||
Global.ClientControls.UnpressButton("Cheats");
|
||||
}
|
||||
|
||||
if (Global.ClientControls["Open ROM"])
|
||||
{
|
||||
OpenROM();
|
||||
Global.ClientControls.UnpressButton("Open ROM");
|
||||
}
|
||||
|
||||
if (Global.ClientControls["Close ROM"])
|
||||
{
|
||||
CloseROM();
|
||||
Global.ClientControls.UnpressButton("Close ROM");
|
||||
}
|
||||
//"Display LagCounter", "Display Input"}
|
||||
if (Global.ClientControls["Display FPS"])
|
||||
{
|
||||
ToggleFPS();
|
||||
Global.ClientControls.UnpressButton("Display FPS");
|
||||
}
|
||||
|
||||
if (Global.ClientControls["Display FrameCounter"])
|
||||
{
|
||||
ToggleFrameCounter();
|
||||
Global.ClientControls.UnpressButton("Display FrameCounter");
|
||||
}
|
||||
|
||||
if (Global.ClientControls["Display LagCounter"])
|
||||
{
|
||||
ToggleLagCounter();
|
||||
Global.ClientControls.UnpressButton("Display LagCounter");
|
||||
}
|
||||
|
||||
if (Global.ClientControls["Display Input"])
|
||||
{
|
||||
ToggleInputDisplay();
|
||||
Global.ClientControls.UnpressButton("Display Input");
|
||||
}
|
||||
|
||||
if (Global.ClientControls["Toggle Read Only"])
|
||||
{
|
||||
ToggleReadOnly();
|
||||
Global.ClientControls.UnpressButton("Toggle Read Only");
|
||||
}
|
||||
|
||||
if (Global.ClientControls["Play Movie"])
|
||||
{
|
||||
PlayMovie();
|
||||
Global.ClientControls.UnpressButton("Play Movie");
|
||||
}
|
||||
|
||||
if (Global.ClientControls["Record Movie"])
|
||||
{
|
||||
RecordMovie();
|
||||
Global.ClientControls.UnpressButton("Record Movie");
|
||||
}
|
||||
|
||||
if (Global.ClientControls["Stop Movie"])
|
||||
{
|
||||
StopUserMovie();
|
||||
Global.ClientControls.UnpressButton("Stop Movie");
|
||||
}
|
||||
|
||||
if (Global.ClientControls["Play Beginning"])
|
||||
{
|
||||
PlayMovieFromBeginning();
|
||||
Global.ClientControls.UnpressButton("Play Beginning");
|
||||
}
|
||||
|
||||
if (Global.ClientControls["Volume Up"])
|
||||
{
|
||||
VolumeUp();
|
||||
Global.ClientControls.UnpressButton("Volume Up");
|
||||
}
|
||||
|
||||
if (Global.ClientControls["Volume Down"])
|
||||
{
|
||||
VolumeDown();
|
||||
Global.ClientControls.UnpressButton("Volume Down");
|
||||
}
|
||||
|
||||
if (Global.ClientControls["Soft Reset"])
|
||||
{
|
||||
SoftReset();
|
||||
Global.ClientControls.UnpressButton("Soft Reset");
|
||||
}
|
||||
|
||||
if (Global.ClientControls["Toggle MultiTrack"])
|
||||
{
|
||||
Global.MainForm.UserMovie.MultiTrack.IsActive = !Global.MainForm.UserMovie.MultiTrack.IsActive;
|
||||
if (Global.MainForm.UserMovie.MultiTrack.IsActive)
|
||||
{
|
||||
Global.RenderPanel.AddMessage("MultiTrack Enabled");
|
||||
Global.RenderPanel.MT = "Recording None";
|
||||
}
|
||||
else
|
||||
Global.RenderPanel.AddMessage("MultiTrack Disabled");
|
||||
Global.MainForm.UserMovie.MultiTrack.RecordAll = false;
|
||||
Global.MainForm.UserMovie.MultiTrack.CurrentPlayer = 0;
|
||||
Global.ClientControls.UnpressButton("Toggle MultiTrack");
|
||||
}
|
||||
if (Global.ClientControls["Increment Player"])
|
||||
{
|
||||
Global.MainForm.UserMovie.MultiTrack.CurrentPlayer++;
|
||||
Global.MainForm.UserMovie.MultiTrack.RecordAll = false;
|
||||
if (Global.MainForm.UserMovie.MultiTrack.CurrentPlayer > 5) //TODO: Replace with console's maximum or current maximum players??!
|
||||
{
|
||||
Global.MainForm.UserMovie.MultiTrack.CurrentPlayer = 1;
|
||||
}
|
||||
Global.ClientControls.UnpressButton("Increment Player");
|
||||
Global.RenderPanel.MT = "Recording Player " + Global.MainForm.UserMovie.MultiTrack.CurrentPlayer.ToString();
|
||||
}
|
||||
if (Global.ClientControls["Decrement Player"])
|
||||
{
|
||||
Global.MainForm.UserMovie.MultiTrack.CurrentPlayer--;
|
||||
Global.MainForm.UserMovie.MultiTrack.RecordAll = false;
|
||||
if (Global.MainForm.UserMovie.MultiTrack.CurrentPlayer < 1)
|
||||
{
|
||||
Global.MainForm.UserMovie.MultiTrack.CurrentPlayer = 5;//TODO: Replace with console's maximum or current maximum players??!
|
||||
}
|
||||
Global.ClientControls.UnpressButton("Decrement Player");
|
||||
Global.RenderPanel.MT = "Recording Player " + Global.MainForm.UserMovie.MultiTrack.CurrentPlayer.ToString();
|
||||
}
|
||||
if (Global.ClientControls["Record All"])
|
||||
{
|
||||
Global.MainForm.UserMovie.MultiTrack.CurrentPlayer = 0;
|
||||
Global.MainForm.UserMovie.MultiTrack.RecordAll = true;
|
||||
Global.ClientControls.UnpressButton("Record All");
|
||||
Global.RenderPanel.MT = "Recording All";
|
||||
}
|
||||
if (Global.ClientControls["Record None"])
|
||||
{
|
||||
Global.MainForm.UserMovie.MultiTrack.CurrentPlayer = 0;
|
||||
Global.MainForm.UserMovie.MultiTrack.RecordAll = false;
|
||||
Global.ClientControls.UnpressButton("Record None");
|
||||
Global.RenderPanel.MT = "Recording None";
|
||||
}
|
||||
}
|
||||
|
||||
void StepRunLoop_Throttle()
|
||||
|
|
|
@ -55,8 +55,10 @@ namespace BizHawk.MultiClient
|
|||
{
|
||||
pos = 0;
|
||||
timer.Start();
|
||||
Input.Update();
|
||||
wasPressed = Input.GetPressedKey();
|
||||
//Input.Update();
|
||||
|
||||
//zero: ??? what is this all about ???
|
||||
wasPressed = Input.Instance.GetNextPressedButtonOrNull();
|
||||
}
|
||||
|
||||
protected override void OnLeave(EventArgs e)
|
||||
|
@ -73,8 +75,8 @@ namespace BizHawk.MultiClient
|
|||
|
||||
private void ReadKeys()
|
||||
{
|
||||
Input.Update();
|
||||
string TempBindingStr = Input.GetPressedKey();
|
||||
Input.Instance.Update();
|
||||
string TempBindingStr = Input.Instance.GetNextPressedButtonOrNull();
|
||||
if (wasPressed != "" && TempBindingStr == wasPressed) return;
|
||||
if (TempBindingStr != null)
|
||||
{
|
||||
|
|
|
@ -85,7 +85,6 @@
|
|||
<Compile Include="7z\SevenZipExtractorAsynchronous.cs" />
|
||||
<Compile Include="7z\SevenZipSfx.cs" />
|
||||
<Compile Include="7z\StreamWrappers.cs" />
|
||||
<Compile Include="Dictionaries.cs" />
|
||||
<Compile Include="InputConfigBase.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
|
|
|
@ -1,81 +0,0 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BizHawk
|
||||
{
|
||||
/// <summary>
|
||||
/// a Dictionary-of-lists with key K and values List<V>
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class Bag<K, V> : BagBase<K, V, Dictionary<K, List<V>>, List<V>> { }
|
||||
|
||||
/// <summary>
|
||||
/// a Dictionary-of-lists with key K and values List<V>
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class SortedBag<K, V> : BagBase<K, V, SortedDictionary<K, List<V>>, List<V>> { }
|
||||
|
||||
/// <summary>
|
||||
/// A dictionary that creates new values on the fly as necessary so that any key you need will be defined.
|
||||
/// </summary>
|
||||
/// <typeparam name="K">dictionary keys</typeparam>
|
||||
/// <typeparam name="V">dictionary values</typeparam>
|
||||
public class WorkingDictionary<K, V> : Dictionary<K, V> where V : new() {
|
||||
public new V this[K key] {
|
||||
get {
|
||||
V temp;
|
||||
if(!TryGetValue(key, out temp))
|
||||
temp = this[key] = new V();
|
||||
return temp;
|
||||
}
|
||||
set { base[key] = value; }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// base class for Bag and SortedBag
|
||||
/// </summary>
|
||||
/// <typeparam name="K">dictionary keys</typeparam>
|
||||
/// <typeparam name="V">list values</typeparam>
|
||||
/// <typeparam name="D">dictionary type</typeparam>
|
||||
/// <typeparam name="L">list type</typeparam>
|
||||
[Serializable]
|
||||
public class BagBase<K, V, D, L> : IEnumerable<V>
|
||||
where D : IDictionary<K, L>, new()
|
||||
where L : IList<V>, IEnumerable<V>, new() {
|
||||
D dictionary = new D();
|
||||
public void Add(K key, V val) {
|
||||
this[key].Add(val);
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
|
||||
public IEnumerator<V> GetEnumerator() {
|
||||
foreach(L lv in dictionary.Values)
|
||||
foreach(V v in lv)
|
||||
yield return v;
|
||||
}
|
||||
|
||||
public IEnumerable KeyValuePairEnumerator { get { return dictionary; } }
|
||||
|
||||
/// <summary>
|
||||
/// the list of keys contained herein
|
||||
/// </summary>
|
||||
public IList<K> Keys { get { return new List<K>(dictionary.Keys); } }
|
||||
|
||||
|
||||
|
||||
public L this[K key] {
|
||||
get {
|
||||
L slot;
|
||||
if(!dictionary.TryGetValue(key, out slot))
|
||||
dictionary[key] = slot = new L();
|
||||
return slot;
|
||||
}
|
||||
set {
|
||||
dictionary[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -538,7 +538,7 @@ namespace BizHawk
|
|||
break;
|
||||
}
|
||||
break;
|
||||
//it is conceivable that you will need this. you wouldnt be able to conceive of why, though. obscure message loop flakiness when exceptions are thrown from the message loop...
|
||||
//obscure message loop flakiness when exceptions are thrown from the message loop...
|
||||
case (int)WindowsMessage.WM_SETFOCUS:
|
||||
if (SelectedIndices.Count > 0 && SelectedIndices[0] >= VirtualListSize)
|
||||
messageProcessed = true;
|
||||
|
|
Loading…
Reference in New Issue