Skip to content

Commit

Permalink
Hotkeys and small things
Browse files Browse the repository at this point in the history
  • Loading branch information
Jiiks committed Apr 8, 2019
1 parent 768600c commit da21fd4
Show file tree
Hide file tree
Showing 13 changed files with 496 additions and 178 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -328,3 +328,4 @@ ASALocalRun/

# MFractors (Xamarin productivity tool) working folder
.mfractor/
/UiTests
10 changes: 10 additions & 0 deletions SekiroSpeedrunUtil.sln
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ VisualStudioVersion = 16.0.28606.126
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SekiroSpeedrunUtil", "SekiroSpeedrunUtil\SekiroSpeedrunUtil.csproj", "{B3A8E464-E789-42B2-9A20-F7B055790FF8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UiTests", "UiTests\UiTests.csproj", "{BDC316F6-055D-447C-86BD-F510E0A72F72}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -21,6 +23,14 @@ Global
{B3A8E464-E789-42B2-9A20-F7B055790FF8}.Release|Any CPU.Build.0 = Release|Any CPU
{B3A8E464-E789-42B2-9A20-F7B055790FF8}.Release|x64.ActiveCfg = Release|x64
{B3A8E464-E789-42B2-9A20-F7B055790FF8}.Release|x64.Build.0 = Release|x64
{BDC316F6-055D-447C-86BD-F510E0A72F72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BDC316F6-055D-447C-86BD-F510E0A72F72}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BDC316F6-055D-447C-86BD-F510E0A72F72}.Debug|x64.ActiveCfg = Debug|x64
{BDC316F6-055D-447C-86BD-F510E0A72F72}.Debug|x64.Build.0 = Debug|x64
{BDC316F6-055D-447C-86BD-F510E0A72F72}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BDC316F6-055D-447C-86BD-F510E0A72F72}.Release|Any CPU.Build.0 = Release|Any CPU
{BDC316F6-055D-447C-86BD-F510E0A72F72}.Release|x64.ActiveCfg = Release|Any CPU
{BDC316F6-055D-447C-86BD-F510E0A72F72}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
93 changes: 93 additions & 0 deletions SekiroSpeedrunUtil/HotKeyManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
using System;
using System.Threading;
using System.Windows.Forms;

namespace SekiroSpeedrunUtil {
public static class HotKeyManager {

public static event EventHandler<HotKeyEventArgs> HotKeyPressed;
private static volatile MessageWindow _wnd;
private static volatile IntPtr _hwnd;
private static readonly ManualResetEvent _windowReadyEvent = new ManualResetEvent(false);

public static int RegisterHotKey(Keys key, KeyModifiers modifiers) {
_windowReadyEvent.WaitOne();
var id = Interlocked.Increment(ref _id);
_wnd.Invoke(new RegisterHotKeyDelegate(RegisterHotKeyInternal), _hwnd, id, (uint)modifiers, (uint)key);
return id;
}

public static void UnregisterHotKey(int id) => _wnd.Invoke(new UnRegisterHotKeyDelegate(UnRegisterHotKeyInternal), _hwnd, id);

private delegate void RegisterHotKeyDelegate(IntPtr hwnd, int id, uint modifiers, uint key);

private delegate void UnRegisterHotKeyDelegate(IntPtr hwnd, int id);

private static void RegisterHotKeyInternal(IntPtr hwnd, int id, uint modifiers, uint key) => Native.RegisterHotKey(hwnd, id, modifiers, key);

private static void UnRegisterHotKeyInternal(IntPtr hwnd, int id) => Native.UnregisterHotKey(_hwnd, id);

private static void OnHotKeyPressed(HotKeyEventArgs e) => HotKeyPressed?.Invoke(null, e);


static HotKeyManager() {
var messageLoop = new Thread(delegate () {
Application.Run(new MessageWindow());
}) {
Name = "MessageLoopThread",
IsBackground = true
};
messageLoop.Start();
}

private class MessageWindow : Form {
public MessageWindow() {
_wnd = this;
_hwnd = this.Handle;
_windowReadyEvent.Set();
}

protected override void WndProc(ref Message m) {
if (m.Msg == WM_HOTKEY) {
var e = new HotKeyEventArgs(m.LParam);
OnHotKeyPressed(e);
}

base.WndProc(ref m);
}

protected override void SetVisibleCore(bool value) => base.SetVisibleCore(false);

private const int WM_HOTKEY = 0x312;
}

private static int _id;
}


public class HotKeyEventArgs : EventArgs
{
public readonly Keys Key;
public readonly KeyModifiers Modifiers;

public HotKeyEventArgs(Keys key, KeyModifiers modifiers = KeyModifiers.NoRepeat) {
Key = key;
Modifiers = modifiers;
}

public HotKeyEventArgs(IntPtr hotKeyParam) {
var param = (uint)hotKeyParam.ToInt64();
Key = (Keys)((param & 0xffff0000) >> 16);
Modifiers = (KeyModifiers)(param & 0x0000ffff);
}
}

[Flags]
public enum KeyModifiers {
Alt = 1,
Control = 2,
Shift = 4,
Windows = 8,
NoRepeat = 0x4000
}
}
145 changes: 79 additions & 66 deletions SekiroSpeedrunUtil/KeyboardHook.cs
Original file line number Diff line number Diff line change
@@ -1,93 +1,106 @@
using System;
using System.Threading;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Newtonsoft.Json;
using SekiroSpeedrunUtil.structs;

namespace SekiroSpeedrunUtil {
public static class HotKeyManager {

public static event EventHandler<HotKeyEventArgs> HotKeyPressed;
private static volatile MessageWindow _wnd;
private static volatile IntPtr _hwnd;
private static readonly ManualResetEvent _windowReadyEvent = new ManualResetEvent(false);

public static int RegisterHotKey(Keys key, KeyModifiers modifiers) {
_windowReadyEvent.WaitOne();
var id = Interlocked.Increment(ref _id);
_wnd.Invoke(new RegisterHotKeyDelegate(RegisterHotKeyInternal), _hwnd, id, (uint)modifiers, (uint)key);
return id;
}
public class KeyboardHook : IDisposable {

public static void UnregisterHotKey(int id) => _wnd.Invoke(new UnRegisterHotKeyDelegate(UnRegisterHotKeyInternal), _hwnd, id);
//private List<Hotkey> _hotkeys;

private delegate void RegisterHotKeyDelegate(IntPtr hwnd, int id, uint modifiers, uint key);
public KeyboardHook() {
_keyboardProc = Callback;
/*
_keyboardProc = Callback;
var hotkeyFile = "hotkeys2.json";
if (File.Exists($"{Utils.DataDir()}/hotkeys2.json")) hotkeyFile = $"{Utils.DataDir()}/hotkeys2.json";
private delegate void UnRegisterHotKeyDelegate(IntPtr hwnd, int id);
_hotkeys = JsonConvert.DeserializeObject <List<Hotkey>>(File.ReadAllText(hotkeyFile));
*/
}

private static void RegisterHotKeyInternal(IntPtr hwnd, int id, uint modifiers, uint key) => Native.RegisterHotKey(hwnd, id, modifiers, key);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr SetWindowsHookEx(int idHook, KeyboardHook.KeyboardProc lpfn, IntPtr hMod, uint dwThreadId);

private static void UnRegisterHotKeyInternal(IntPtr hwnd, int id) => Native.UnregisterHotKey(_hwnd, id);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool UnhookWindowsHookEx(IntPtr hookId);

private static void OnHotKeyPressed(HotKeyEventArgs e) => HotKeyPressed?.Invoke(null, e);
[DllImport("user32", CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr CallNextHookEx(IntPtr hookId, int nCode, IntPtr wParam, IntPtr lParam);


static HotKeyManager() {
var messageLoop = new Thread(delegate () {
Application.Run(new MessageWindow());
}) {
Name = "MessageLoopThread",
IsBackground = true
};
messageLoop.Start();
}
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
public static extern short GetKeyState(int keyCode);

private class MessageWindow : Form {
public MessageWindow() {
_wnd = this;
_hwnd = this.Handle;
_windowReadyEvent.Set();
}
//Modifier key vkCode constants
private const int VK_SHIFT = 0x10;
private const int VK_CONTROL = 0x11;
private const int VK_MENU = 0x12;
private const int VK_CAPITAL = 0x14;

protected override void WndProc(ref Message m) {
if (m.Msg == WM_HOTKEY) {
var e = new HotKeyEventArgs(m.LParam);
OnHotKeyPressed(e);
}
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;

base.WndProc(ref m);
}
public delegate IntPtr KeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);

private Keys GetModifiers () {
var key = new Keys();
if ((GetKeyState(VK_SHIFT) & 0x8000) != 0) key |= Keys.Shift;
if ((GetKeyState(VK_CONTROL) & 0x8000) != 0) key |= Keys.Control;
if ((GetKeyState(VK_MENU) & 0x8000) != 0) key |= Keys.Alt;
return key;
}

public event EventHandler<KeyPressEventArgs> OnKeyPressed;

protected override void SetVisibleCore(bool value) => base.SetVisibleCore(false);
private static KeyboardProc _keyboardProc;
private IntPtr _hookId = IntPtr.Zero;

private const int WM_HOTKEY = 0x312;
public void Hook() {
_hookId = SetWindowsHookEx(WH_KEYBOARD_LL, _keyboardProc, IntPtr.Zero, 0);
}

private static int _id;
}

private IntPtr Callback(int nCode, IntPtr wParam, IntPtr lParam) {
if(nCode < 0 || wParam != (IntPtr)WM_KEYDOWN) return CallNextHookEx(_hookId, nCode, wParam, lParam);

public class HotKeyEventArgs : EventArgs
{
public readonly Keys Key;
public readonly KeyModifiers Modifiers;
try {
var vkCode = Marshal.ReadInt32(lParam);
var eargs = new KeyPressEventArgs {
KeyPressed = (Keys)vkCode,
Modifiers = GetModifiers()
};
var modifiers = GetModifiers();
OnKeyPressed?.Invoke(this, eargs);
} catch (Exception ex) {
Diag.WriteLine($"[KeyboardHook] {ex.Message}");
}

public HotKeyEventArgs(Keys key, KeyModifiers modifiers = KeyModifiers.NoRepeat) {
Key = key;
Modifiers = modifiers;
return CallNextHookEx(_hookId, nCode, wParam, lParam);
}

public HotKeyEventArgs(IntPtr hotKeyParam) {
var param = (uint)hotKeyParam.ToInt64();
Key = (Keys)((param & 0xffff0000) >> 16);
Modifiers = (KeyModifiers)(param & 0x0000ffff);
public void Dispose() {
if (_hookId == IntPtr.Zero) return;
UnhookWindowsHookEx(_hookId);
}
}

[Flags]
public enum KeyModifiers {
Alt = 1,
Control = 2,
Shift = 4,
Windows = 8,
NoRepeat = 0x4000
public struct KeyPressEventArgs {
public Keys KeyPressed;
public Keys Modifiers;
}

/*
public class KeyPressedArgs : EventArgs {
public Key KeyPressed { get; }
public KeyPressedArgs(Key key) {
KeyPressed = key;
}
}
*/
}
}
4 changes: 2 additions & 2 deletions SekiroSpeedrunUtil/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,5 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("0.3.3.0")]
[assembly: AssemblyFileVersion("0.3.3.0")]
[assembly: AssemblyVersion("0.3.4.0")]
[assembly: AssemblyFileVersion("0.3.4.0")]
2 changes: 2 additions & 0 deletions SekiroSpeedrunUtil/SekiroSpeedrunUtil.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -128,11 +128,13 @@
<Compile Include="injects\AreaTeleport.cs" />
<Compile Include="injects\IdolTeleport.cs" />
<Compile Include="injects\InjectBase.cs" />
<Compile Include="HotKeyManager.cs" />
<Compile Include="KeyboardHook.cs" />
<Compile Include="MemoryThread.cs" />
<Compile Include="MemoryThreadMan.cs" />
<Compile Include="MouseDetector.cs" />
<Compile Include="RemoteProc.cs" />
<Compile Include="structs\Hotkey.cs" />
<Compile Include="structs\IntPtrE.cs" />
<Compile Include="structs\Item.cs" />
<Compile Include="structs\Pattern.cs" />
Expand Down
24 changes: 18 additions & 6 deletions SekiroSpeedrunUtil/hotkeys.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,48 @@
"HotkeyString": "Shift+F1",
"Name": "SaveCurrentCoordinates",
"Key": 112,
"Modifiers": 4
"Modifiers": 65536,
"Invalid": false,
"Unset": false
},
{
"HotkeyString": "Shift+F2",
"Name": "TeleportToCoordinates",
"Key": 113,
"Modifiers": 4
"Modifiers": 65536,
"Invalid": false,
"Unset": false
},
{
"HotkeyString": "Shift+F3",
"Name": "BackupSave",
"Key": 114,
"Modifiers": 4
"Modifiers": 65536,
"Invalid": false,
"Unset": false
},
{
"HotkeyString": "Shift+F4",
"Name": "LoadSave",
"Key": 115,
"Modifiers": 4
"Modifiers": 65536,
"Invalid": false,
"Unset": false
},
{
"HotkeyString": "Shift+F5",
"Name": "LoadLastQuickSave",
"Key": 116,
"Modifiers": 4
"Modifiers": 65536,
"Invalid": false,
"Unset": false
},
{
"HotkeyString": "Shift+F6",
"Name": "ForceQuit",
"Key": 117,
"Modifiers": 4
"Modifiers": 65536,
"Invalid": false,
"Unset": false
}
]
12 changes: 12 additions & 0 deletions SekiroSpeedrunUtil/structs/Hotkey.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System.Windows.Forms;

namespace SekiroSpeedrunUtil.structs {
public class Hotkey {
public string HotkeyString;
public string Name;
public Keys Key;
public Keys Modifiers;
public bool Invalid;
public bool Unset;
}
}
Loading

0 comments on commit da21fd4

Please sign in to comment.