Skip to content
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

refactor: Rewrite Keybind system #141

Merged
merged 5 commits into from
Aug 8, 2023
Merged
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
92 changes: 57 additions & 35 deletions Classes/Services/HotkeyService.cs
Original file line number Diff line number Diff line change
@@ -1,81 +1,103 @@
#if WINDOWS
using RePlays.Classes.Services.Hotkeys;
using RePlays.Classes.Services.Keybinds;
using RePlays.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace RePlays.Services {
public static class HotkeyService {
public delegate IntPtr CallbackDelegate(int Code, IntPtr W, IntPtr L);

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct KBDLLHookStruct {
public Int32 vkCode;
public Int32 scanCode;
public Int32 flags;
public Int32 time;
public Int32 dwExtraInfo;
}
public delegate IntPtr WinHookProc(int Code, IntPtr W, IntPtr L);

[DllImport("user32", CallingConvention = CallingConvention.StdCall)]
private static extern IntPtr SetWindowsHookEx(int idHook, CallbackDelegate lpfn, int hInstance, int threadId);
private static extern IntPtr SetWindowsHookEx(int idHook, WinHookProc lpfn, int hInstance, int threadId);

[DllImport("user32", CallingConvention = CallingConvention.StdCall)]
private static extern bool UnhookWindowsHookEx(IntPtr idHook);

[DllImport("user32", CallingConvention = CallingConvention.StdCall)]
private static extern IntPtr CallNextHookEx(IntPtr idHook, int nCode, IntPtr wParam, IntPtr lParam);

[DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall)]
private static extern int GetCurrentThreadId();
public static string EditId = null;
private static List<Hotkey> _hotkeys = new();
private static IntPtr HookID;
static CallbackDelegate TheHookCB = null;
private static readonly List<Keybind> keybinds = new();
private static readonly HashSet<Keys> pressedKeys = new();
private static readonly HashSet<Keys> cachePressedKeys = new();
static nint keyboardHook;
static WinHookProc keyboardDele;

public static string EditId { get; internal set; }

public static void Start() {
//Create hotkeys
_hotkeys.Add(new BookmarkHotkey());
_hotkeys.Add(new RecordingHotkey());
//Create keybinds
keybinds.Add(new BookmarkKeybind());
keybinds.Add(new RecordingKeybind());

//Create hook
TheHookCB = KeybHookProc;
HookID = SetWindowsHookEx(13, TheHookCB, 0, 0);
keyboardDele = OnKeyEvent;
keyboardHook = SetWindowsHookEx(13, keyboardDele, 0, 0);
Logger.WriteLine("Loaded KeyboardHook...");
}

public static void Stop() {
_hotkeys.Clear();
UnhookWindowsHookEx(HookID);
keybinds.Clear();
UnhookWindowsHookEx(keyboardHook);
Logger.WriteLine("Unloaded KeyboardHook...");
}

private static IntPtr KeybHookProc(int Code, IntPtr W, IntPtr L) {
private static IntPtr OnKeyEvent(int Code, IntPtr W, IntPtr L) {
if (Code < 0)
return CallNextHookEx(HookID, Code, W, L);
return CallNextHookEx(keyboardHook, Code, W, L);

try {
KeyEvents kEvent = (KeyEvents)W;
if (kEvent == KeyEvents.KeyDown) {
Keys vkCode = (Keys)Marshal.ReadInt32(L);
vkCode |= Control.ModifierKeys;
foreach (Hotkey h in _hotkeys) {
if (vkCode == h.Keybind) h.Action();
Keys vkCode = (Keys)Marshal.ReadInt32(L);
if (kEvent == KeyEvents.KeyDown || kEvent == KeyEvents.SysKeyDown) {
pressedKeys.Add(vkCode);
if (EditId == null) {
foreach (Keybind h in keybinds) {
if (string.Join(",", pressedKeys.OrderBy(s => s.ToString())) == string.Join(",", h.Keys.OrderBy(s => s.ToString())) &&
!pressedKeys.SetEquals(cachePressedKeys) && !SettingsService.Settings.keybindSettings[h.Id].disabled) {
h.Action();
Logger.WriteLine($"Key: [{string.Join(",", h.Keys)}], Action: [{h.Id}]");
}
}
}
else {
if (!pressedKeys.SetEquals(cachePressedKeys)) {
Logger.WriteLine($"KeysDown: [{string.Join(",", pressedKeys)}]");
}
}
cachePressedKeys.Add(vkCode);
}
else if (kEvent == KeyEvents.KeyUp || kEvent == KeyEvents.SysKeyUp) {
if (EditId != null) {
int hkIndex = keybinds.FindIndex(h => h.Id == EditId);
if (hkIndex == -1) {
Logger.WriteLine($"Error, could not find keybind action: {EditId}");
}
else {
keybinds[hkIndex].SetKeybind(pressedKeys.Select(p => p.ToString()).ToArray());
}
Logger.WriteLine($"Exiting keybind edit mode.");
EditId = null;
}
pressedKeys.Remove(vkCode);
cachePressedKeys.Remove(vkCode);
}
}
catch (Exception e) {
Logger.WriteLine("Error getting current keypress: " + e.ToString());
}

return CallNextHookEx(HookID, Code, W, L);
return CallNextHookEx(keyboardHook, Code, W, L);
}


public enum KeyEvents {
KeyDown = 0x0100,
KeyUp = 0x0101
KeyUp = 0x0101,
SysKeyDown = 0x0104,
SysKeyUp = 0x0105,
}
}
}
Expand Down
18 changes: 0 additions & 18 deletions Classes/Services/Hotkeys/BookmarkHotkey.cs

This file was deleted.

49 changes: 0 additions & 49 deletions Classes/Services/Hotkeys/Hotkey.cs

This file was deleted.

19 changes: 0 additions & 19 deletions Classes/Services/Hotkeys/RecordingHotkey.cs

This file was deleted.

16 changes: 16 additions & 0 deletions Classes/Services/Keybinds/BookmarkKeybind.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#if WINDOWS
using RePlays.Services;

namespace RePlays.Classes.Services.Keybinds {
public class BookmarkKeybind : Keybind {
public BookmarkKeybind() {
Id = "CreateBookmark";
DefaultKeys = new string[] { "F8" };
SetKeybind();
}
public override void Action() {
if (RecordingService.IsRecording) BookmarkService.AddBookmark(new Bookmark { type = Bookmark.BookmarkType.Manual });
}
}
}
#endif
41 changes: 41 additions & 0 deletions Classes/Services/Keybinds/Keybind.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#if WINDOWS
using RePlays.Services;
using RePlays.Utils;

namespace RePlays.Classes.Services.Keybinds {
public abstract class Keybind {
public string Id { get; internal set; }
internal string[] DefaultKeys { get; set; }
public string[] Keys { get; internal set; }

public abstract void Action();

public virtual void SetKeybind(string[] Keys = null) {
if (Keys == null) {
bool exists = SettingsService.Settings.keybindSettings.TryGetValue(Id, out CustomKeybind existingBind);
if (!exists) {
SettingsService.Settings.keybindSettings[Id] = new CustomKeybind {
keys = DefaultKeys,
};
SettingsService.SaveSettings();
Keys = DefaultKeys;
Logger.WriteLine($"Set new keybind: Action={Id}, Keys={Keys}");
}
else {
Keys = existingBind.keys;
Logger.WriteLine($"Set existing keybind: Action={Id}, Keys={string.Join(",", Keys)}");
}
}
else {
SettingsService.Settings.keybindSettings[Id] = new CustomKeybind {
keys = Keys,
};
SettingsService.SaveSettings();
Logger.WriteLine($"Set new keybind: Action={Id}, Keys={string.Join(",", Keys)}");
WebMessage.SendMessage(Functions.GetUserSettings());
}
this.Keys = Keys;
}
}
}
#endif
17 changes: 17 additions & 0 deletions Classes/Services/Keybinds/RecordingKeybind.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#if WINDOWS
using RePlays.Services;

namespace RePlays.Classes.Services.Keybinds {
public class RecordingKeybind : Keybind {
public RecordingKeybind() {
Id = "StartStopRecording";
DefaultKeys = new string[] { "LControlKey", "F9" };
SetKeybind();
}
public override void Action() {
if (RecordingService.IsRecording) RecordingService.StopRecording();
else RecordingService.StartRecording();
}
}
}
#endif
6 changes: 3 additions & 3 deletions Classes/Services/SettingsService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ public class SettingsJson {
private DetectionSettings _detectionSettings = new();
public DetectionSettings detectionSettings { get { return _detectionSettings; } set { _detectionSettings = value; } }

private Dictionary<string, string[]> _keybindings = new Dictionary<string, string[]>() { };
public Dictionary<string, string[]> keybindings { get { return _keybindings; } set { _keybindings = value; } }
private KeybindSettings _keybindSettings = new();
public KeybindSettings keybindSettings { get { return _keybindSettings; } set { _keybindSettings = value; } }
}

public static void LoadSettings() {
Expand All @@ -44,7 +44,7 @@ public static void LoadSettings() {
}
}
else {
Logger.WriteLine(string.Format("{0} did not exist, using default values", settingsFile));
Logger.WriteLine($"{settingsFile} did not exist, using default values");
}
}

Expand Down
14 changes: 14 additions & 0 deletions Classes/Utils/JSONObjects.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using RePlays.Classes.Services.Keybinds;
using Squirrel;
using System;
using System.Collections.Generic;
Expand Down Expand Up @@ -248,6 +249,19 @@ public class DetectionSettings {
public List<string> blacklist { get { return _blacklist; } set { _blacklist = value; } }
}

public class KeybindSettings : Dictionary<string, CustomKeybind> { }

public struct CustomKeybind {
public CustomKeybind(bool disabled, string[] keys) {
this._disabled = disabled;
this._keys = keys;
}
private bool _disabled;
public bool disabled { get { return _disabled; } set { _disabled = value; } }
private string[] _keys;
public string[] keys { get { return _keys; } set { _keys = value; } }
}

public struct CustomGame {
public CustomGame(string gameExe, string gameName) {
this._gameExe = gameExe;
Expand Down
9 changes: 7 additions & 2 deletions Classes/Utils/Messages.cs
Original file line number Diff line number Diff line change
Expand Up @@ -202,9 +202,14 @@ public static async Task<WebMessage> RecieveMessage(string message) {
}
break;
#if WINDOWS
case "EditKeybind": {
case "EnterEditKeybind": {
var id = webMessage.data.Replace("\"", "");
frmMain.Instance.EditKeybind(id);
HotkeyService.EditId = id;
}
break;
case "ExitEditKeybind": {
var id = webMessage.data.Replace("\"", "");
HotkeyService.EditId = null;
}
break;
case "SelectFolder": {
Expand Down
Loading