Compare commits
8 Commits
ClipForgeB
...
fcd70b699d
| Author | SHA1 | Date | |
|---|---|---|---|
| fcd70b699d | |||
| 7f5d80ff68 | |||
| ae744f1077 | |||
| 9b73bdbb24 | |||
| 4902802615 | |||
| 6aa49c0b07 | |||
| 52a2515e2d | |||
| 742c1d70fe |
@@ -18,12 +18,12 @@
|
|||||||
<PackageCertificateThumbprint>4A55954F2A73A9D620442C7DFBFC7C95A71D8D24</PackageCertificateThumbprint>
|
<PackageCertificateThumbprint>4A55954F2A73A9D620442C7DFBFC7C95A71D8D24</PackageCertificateThumbprint>
|
||||||
<AppxPackageSigningTimestampDigestAlgorithm>SHA256</AppxPackageSigningTimestampDigestAlgorithm>
|
<AppxPackageSigningTimestampDigestAlgorithm>SHA256</AppxPackageSigningTimestampDigestAlgorithm>
|
||||||
<AppxAutoIncrementPackageRevision>True</AppxAutoIncrementPackageRevision>
|
<AppxAutoIncrementPackageRevision>True</AppxAutoIncrementPackageRevision>
|
||||||
<AppxPackageDir>C:\Users\Blade\Desktop\Clipforge Packaged\V1\</AppxPackageDir>
|
<AppxPackageDir>C:\Users\Blade\Desktop\Clipforge Packaged\V0.1\</AppxPackageDir>
|
||||||
<AppxSymbolPackageEnabled>False</AppxSymbolPackageEnabled>
|
<AppxSymbolPackageEnabled>False</AppxSymbolPackageEnabled>
|
||||||
<GenerateTestArtifacts>True</GenerateTestArtifacts>
|
<GenerateTestArtifacts>True</GenerateTestArtifacts>
|
||||||
<AppxBundle>Auto</AppxBundle>
|
<AppxBundle>Auto</AppxBundle>
|
||||||
<AppxBundlePlatforms>x64</AppxBundlePlatforms>
|
<AppxBundlePlatforms>x64</AppxBundlePlatforms>
|
||||||
<AppInstallerUri>J:\Projects\ClipForge\ClipForge\bin\x64\Release\net8.0-windows10.0.19041.0</AppInstallerUri>
|
<AppInstallerUri>C:\Users\Blade\Desktop\Clipforge Packaged</AppInstallerUri>
|
||||||
<HoursBetweenUpdateChecks>0</HoursBetweenUpdateChecks>
|
<HoursBetweenUpdateChecks>0</HoursBetweenUpdateChecks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using Microsoft.UI.Xaml;
|
using Microsoft.UI.Xaml;
|
||||||
|
|
||||||
@@ -6,40 +6,50 @@ namespace ClipForge
|
|||||||
{
|
{
|
||||||
public class GlobalHotkeyService
|
public class GlobalHotkeyService
|
||||||
{
|
{
|
||||||
// These two lines talk directly to Windows to register/unregister hotkeys
|
|
||||||
[DllImport("user32.dll")]
|
[DllImport("user32.dll")]
|
||||||
private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);
|
private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);
|
||||||
|
|
||||||
[DllImport("user32.dll")]
|
[DllImport("user32.dll")]
|
||||||
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
|
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
|
||||||
|
|
||||||
// This is the ID we'll use to identify our clip hotkey
|
|
||||||
private const int HOTKEY_CLIP = 1;
|
private const int HOTKEY_CLIP = 1;
|
||||||
|
private const uint MOD_NOREPEAT = 0x4000; // don't fire on key repeat
|
||||||
|
|
||||||
// Alt key modifier
|
|
||||||
private const uint MOD_ALT = 0x0001;
|
|
||||||
|
|
||||||
// F9 key
|
|
||||||
private const uint VK_F9 = 0x78;
|
|
||||||
|
|
||||||
// This is the "event" that fires when the hotkey is pressed
|
|
||||||
public event Action? ClipRequested;
|
public event Action? ClipRequested;
|
||||||
|
|
||||||
private IntPtr _hwnd;
|
private IntPtr _hwnd;
|
||||||
|
private uint _modifiers;
|
||||||
|
private uint _vk;
|
||||||
|
|
||||||
public void Initialize(IntPtr hwnd)
|
/// <summary>Register the clip hotkey. Use settings values (e.g. HotkeyModifiers, HotkeyVirtualKey).</summary>
|
||||||
|
public void Initialize(IntPtr hwnd, uint modifiers, uint vk)
|
||||||
{
|
{
|
||||||
_hwnd = hwnd;
|
_hwnd = hwnd;
|
||||||
RegisterHotKey(_hwnd, HOTKEY_CLIP, MOD_ALT, VK_F9);
|
_modifiers = modifiers;
|
||||||
|
_vk = vk;
|
||||||
|
TryRegister();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Update the hotkey at runtime (e.g. after user remaps). Unregisters old and registers new.</summary>
|
||||||
|
public bool UpdateHotkey(uint modifiers, uint vk)
|
||||||
|
{
|
||||||
|
UnregisterHotKey(_hwnd, HOTKEY_CLIP);
|
||||||
|
_modifiers = modifiers;
|
||||||
|
_vk = vk;
|
||||||
|
return TryRegister();
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryRegister()
|
||||||
|
{
|
||||||
|
uint mod = _modifiers | MOD_NOREPEAT;
|
||||||
|
return RegisterHotKey(_hwnd, HOTKEY_CLIP, mod, _vk);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ProcessHotkey(int id)
|
public void ProcessHotkey(int id)
|
||||||
{
|
{
|
||||||
if (id == HOTKEY_CLIP)
|
if (id == HOTKEY_CLIP)
|
||||||
{
|
|
||||||
ClipRequested?.Invoke();
|
ClipRequested?.Invoke();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public void Cleanup()
|
public void Cleanup()
|
||||||
{
|
{
|
||||||
|
|||||||
183
ClipForge/HotkeyHelper.cs
Normal file
183
ClipForge/HotkeyHelper.cs
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Windows.System;
|
||||||
|
|
||||||
|
namespace ClipForge
|
||||||
|
{
|
||||||
|
/// <summary>Converts between hotkey modifier/vk and display strings.</summary>
|
||||||
|
public static class HotkeyHelper
|
||||||
|
{
|
||||||
|
public const uint MOD_ALT = 0x0001;
|
||||||
|
public const uint MOD_CONTROL = 0x0002;
|
||||||
|
public const uint MOD_SHIFT = 0x0004;
|
||||||
|
public const uint MOD_WIN = 0x0008;
|
||||||
|
public const uint MOD_NOREPEAT = 0x4000;
|
||||||
|
|
||||||
|
// Built in static ctor with TryAdd so duplicate VirtualKey enum values (e.g. Kana/Hangul = 0x15) don't throw.
|
||||||
|
private static readonly Dictionary<VirtualKey, string> KeyNames = new();
|
||||||
|
|
||||||
|
static HotkeyHelper()
|
||||||
|
{
|
||||||
|
TryAdd(VirtualKey.LeftButton, "LMB");
|
||||||
|
TryAdd(VirtualKey.RightButton, "RMB");
|
||||||
|
TryAdd(VirtualKey.Cancel, "Cancel");
|
||||||
|
TryAdd(VirtualKey.Back, "Backspace");
|
||||||
|
TryAdd(VirtualKey.Tab, "Tab");
|
||||||
|
TryAdd(VirtualKey.Clear, "Clear");
|
||||||
|
TryAdd(VirtualKey.Enter, "Enter");
|
||||||
|
TryAdd(VirtualKey.Shift, "Shift");
|
||||||
|
TryAdd(VirtualKey.Control, "Ctrl");
|
||||||
|
TryAdd(VirtualKey.Menu, "Alt");
|
||||||
|
TryAdd(VirtualKey.Pause, "Pause");
|
||||||
|
TryAdd(VirtualKey.CapitalLock, "Caps Lock");
|
||||||
|
TryAdd(VirtualKey.Kana, "Kana");
|
||||||
|
TryAdd(VirtualKey.Hangul, "Hangul"); // same value as Kana on some SDKs; TryAdd skips duplicate
|
||||||
|
TryAdd(VirtualKey.Junja, "Junja");
|
||||||
|
TryAdd(VirtualKey.Final, "Final");
|
||||||
|
TryAdd(VirtualKey.Hanja, "Hanja");
|
||||||
|
TryAdd(VirtualKey.Kanji, "Kanji");
|
||||||
|
TryAdd(VirtualKey.Escape, "Escape");
|
||||||
|
TryAdd(VirtualKey.Convert, "Convert");
|
||||||
|
TryAdd(VirtualKey.NonConvert, "NonConvert");
|
||||||
|
TryAdd(VirtualKey.Accept, "Accept");
|
||||||
|
TryAdd(VirtualKey.ModeChange, "ModeChange");
|
||||||
|
TryAdd(VirtualKey.Space, "Space");
|
||||||
|
TryAdd(VirtualKey.PageUp, "PgUp");
|
||||||
|
TryAdd(VirtualKey.PageDown, "PgDn");
|
||||||
|
TryAdd(VirtualKey.End, "End");
|
||||||
|
TryAdd(VirtualKey.Home, "Home");
|
||||||
|
TryAdd(VirtualKey.Left, "Left");
|
||||||
|
TryAdd(VirtualKey.Up, "Up");
|
||||||
|
TryAdd(VirtualKey.Right, "Right");
|
||||||
|
TryAdd(VirtualKey.Down, "Down");
|
||||||
|
TryAdd(VirtualKey.Select, "Select");
|
||||||
|
TryAdd(VirtualKey.Print, "Print");
|
||||||
|
TryAdd(VirtualKey.Execute, "Execute");
|
||||||
|
TryAdd(VirtualKey.Snapshot, "Print Screen");
|
||||||
|
TryAdd(VirtualKey.Insert, "Insert");
|
||||||
|
TryAdd(VirtualKey.Delete, "Delete");
|
||||||
|
TryAdd(VirtualKey.Help, "Help");
|
||||||
|
TryAdd(VirtualKey.Number0, "0");
|
||||||
|
TryAdd(VirtualKey.Number1, "1");
|
||||||
|
TryAdd(VirtualKey.Number2, "2");
|
||||||
|
TryAdd(VirtualKey.Number3, "3");
|
||||||
|
TryAdd(VirtualKey.Number4, "4");
|
||||||
|
TryAdd(VirtualKey.Number5, "5");
|
||||||
|
TryAdd(VirtualKey.Number6, "6");
|
||||||
|
TryAdd(VirtualKey.Number7, "7");
|
||||||
|
TryAdd(VirtualKey.Number8, "8");
|
||||||
|
TryAdd(VirtualKey.Number9, "9");
|
||||||
|
TryAdd(VirtualKey.A, "A");
|
||||||
|
TryAdd(VirtualKey.B, "B");
|
||||||
|
TryAdd(VirtualKey.C, "C");
|
||||||
|
TryAdd(VirtualKey.D, "D");
|
||||||
|
TryAdd(VirtualKey.E, "E");
|
||||||
|
TryAdd(VirtualKey.F, "F");
|
||||||
|
TryAdd(VirtualKey.G, "G");
|
||||||
|
TryAdd(VirtualKey.H, "H");
|
||||||
|
TryAdd(VirtualKey.I, "I");
|
||||||
|
TryAdd(VirtualKey.J, "J");
|
||||||
|
TryAdd(VirtualKey.K, "K");
|
||||||
|
TryAdd(VirtualKey.L, "L");
|
||||||
|
TryAdd(VirtualKey.M, "M");
|
||||||
|
TryAdd(VirtualKey.N, "N");
|
||||||
|
TryAdd(VirtualKey.O, "O");
|
||||||
|
TryAdd(VirtualKey.P, "P");
|
||||||
|
TryAdd(VirtualKey.Q, "Q");
|
||||||
|
TryAdd(VirtualKey.R, "R");
|
||||||
|
TryAdd(VirtualKey.S, "S");
|
||||||
|
TryAdd(VirtualKey.T, "T");
|
||||||
|
TryAdd(VirtualKey.U, "U");
|
||||||
|
TryAdd(VirtualKey.V, "V");
|
||||||
|
TryAdd(VirtualKey.W, "W");
|
||||||
|
TryAdd(VirtualKey.X, "X");
|
||||||
|
TryAdd(VirtualKey.Y, "Y");
|
||||||
|
TryAdd(VirtualKey.Z, "Z");
|
||||||
|
TryAdd(VirtualKey.LeftWindows, "Win");
|
||||||
|
TryAdd(VirtualKey.RightWindows, "Win");
|
||||||
|
TryAdd(VirtualKey.Application, "App");
|
||||||
|
TryAdd(VirtualKey.Sleep, "Sleep");
|
||||||
|
TryAdd(VirtualKey.NumberPad0, "Num 0");
|
||||||
|
TryAdd(VirtualKey.NumberPad1, "Num 1");
|
||||||
|
TryAdd(VirtualKey.NumberPad2, "Num 2");
|
||||||
|
TryAdd(VirtualKey.NumberPad3, "Num 3");
|
||||||
|
TryAdd(VirtualKey.NumberPad4, "Num 4");
|
||||||
|
TryAdd(VirtualKey.NumberPad5, "Num 5");
|
||||||
|
TryAdd(VirtualKey.NumberPad6, "Num 6");
|
||||||
|
TryAdd(VirtualKey.NumberPad7, "Num 7");
|
||||||
|
TryAdd(VirtualKey.NumberPad8, "Num 8");
|
||||||
|
TryAdd(VirtualKey.NumberPad9, "Num 9");
|
||||||
|
TryAdd(VirtualKey.Multiply, "Num *");
|
||||||
|
TryAdd(VirtualKey.Add, "Num +");
|
||||||
|
TryAdd(VirtualKey.Separator, "Num ,");
|
||||||
|
TryAdd(VirtualKey.Subtract, "Num -");
|
||||||
|
TryAdd(VirtualKey.Decimal, "Num .");
|
||||||
|
TryAdd(VirtualKey.Divide, "Num /");
|
||||||
|
TryAdd(VirtualKey.F1, "F1");
|
||||||
|
TryAdd(VirtualKey.F2, "F2");
|
||||||
|
TryAdd(VirtualKey.F3, "F3");
|
||||||
|
TryAdd(VirtualKey.F4, "F4");
|
||||||
|
TryAdd(VirtualKey.F5, "F5");
|
||||||
|
TryAdd(VirtualKey.F6, "F6");
|
||||||
|
TryAdd(VirtualKey.F7, "F7");
|
||||||
|
TryAdd(VirtualKey.F8, "F8");
|
||||||
|
TryAdd(VirtualKey.F9, "F9");
|
||||||
|
TryAdd(VirtualKey.F10, "F10");
|
||||||
|
TryAdd(VirtualKey.F11, "F11");
|
||||||
|
TryAdd(VirtualKey.F12, "F12");
|
||||||
|
TryAdd(VirtualKey.F13, "F13");
|
||||||
|
TryAdd(VirtualKey.F14, "F14");
|
||||||
|
TryAdd(VirtualKey.F15, "F15");
|
||||||
|
TryAdd(VirtualKey.F16, "F16");
|
||||||
|
TryAdd(VirtualKey.F17, "F17");
|
||||||
|
TryAdd(VirtualKey.F18, "F18");
|
||||||
|
TryAdd(VirtualKey.F19, "F19");
|
||||||
|
TryAdd(VirtualKey.F20, "F20");
|
||||||
|
TryAdd(VirtualKey.F21, "F21");
|
||||||
|
TryAdd(VirtualKey.F22, "F22");
|
||||||
|
TryAdd(VirtualKey.F23, "F23");
|
||||||
|
TryAdd(VirtualKey.F24, "F24");
|
||||||
|
TryAdd(VirtualKey.NumberKeyLock, "NumLock");
|
||||||
|
TryAdd(VirtualKey.Scroll, "Scroll Lock");
|
||||||
|
TryAdd(VirtualKey.LeftShift, "Shift");
|
||||||
|
TryAdd(VirtualKey.RightShift, "Shift");
|
||||||
|
TryAdd(VirtualKey.LeftControl, "Ctrl");
|
||||||
|
TryAdd(VirtualKey.RightControl, "Ctrl");
|
||||||
|
TryAdd(VirtualKey.LeftMenu, "Alt");
|
||||||
|
TryAdd(VirtualKey.RightMenu, "Alt");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void TryAdd(VirtualKey key, string name)
|
||||||
|
{
|
||||||
|
KeyNames.TryAdd(key, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Format modifier flags + virtual key as display string (e.g. "Alt + PgUp").</summary>
|
||||||
|
public static string ToDisplayString(uint modifiers, uint vk)
|
||||||
|
{
|
||||||
|
var parts = new List<string>();
|
||||||
|
if ((modifiers & MOD_WIN) != 0) parts.Add("Win");
|
||||||
|
if ((modifiers & MOD_CONTROL) != 0) parts.Add("Ctrl");
|
||||||
|
if ((modifiers & MOD_ALT) != 0) parts.Add("Alt");
|
||||||
|
if ((modifiers & MOD_SHIFT) != 0) parts.Add("Shift");
|
||||||
|
var keyName = GetKeyName((VirtualKey)vk);
|
||||||
|
if (!string.IsNullOrEmpty(keyName))
|
||||||
|
parts.Add(keyName);
|
||||||
|
return parts.Count > 0 ? string.Join(" + ", parts) : "None";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetKeyName(VirtualKey key)
|
||||||
|
{
|
||||||
|
return KeyNames.TryGetValue(key, out var name) ? name : key.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>True if the key is typically used only as a modifier (don't use as sole key).</summary>
|
||||||
|
public static bool IsModifierKey(VirtualKey key)
|
||||||
|
{
|
||||||
|
return key == VirtualKey.LeftWindows || key == VirtualKey.RightWindows
|
||||||
|
|| key == VirtualKey.Control || key == VirtualKey.LeftControl || key == VirtualKey.RightControl
|
||||||
|
|| key == VirtualKey.Menu || key == VirtualKey.LeftMenu || key == VirtualKey.RightMenu
|
||||||
|
|| key == VirtualKey.Shift || key == VirtualKey.LeftShift || key == VirtualKey.RightShift;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
<MicaBackdrop />
|
<MicaBackdrop />
|
||||||
</Window.SystemBackdrop>
|
</Window.SystemBackdrop>
|
||||||
|
|
||||||
<Grid>
|
<Grid x:Name="RootGrid">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="200"/>
|
<ColumnDefinition Width="200"/>
|
||||||
<ColumnDefinition Width="*"/>
|
<ColumnDefinition Width="*"/>
|
||||||
@@ -371,22 +371,22 @@
|
|||||||
FontWeight="SemiBold"
|
FontWeight="SemiBold"
|
||||||
VerticalAlignment="Center"/>
|
VerticalAlignment="Center"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<TextBlock Text="The key combination to save a clip."
|
<TextBlock Text="Click the key below, then press your desired combination."
|
||||||
FontSize="12"
|
FontSize="12"
|
||||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"/>
|
Foreground="{ThemeResource TextFillColorSecondaryBrush}"/>
|
||||||
<Border Background="#1a1a2e"
|
<Button x:Name="HotkeyRecorderButton"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
Click="HotkeyRecorderButton_Click"
|
||||||
|
Background="#1a1a2e"
|
||||||
|
BorderThickness="0"
|
||||||
CornerRadius="6"
|
CornerRadius="6"
|
||||||
Padding="16,10"
|
Padding="16,10"
|
||||||
HorizontalAlignment="Left">
|
MinWidth="140"
|
||||||
<TextBlock Text="Alt + F9"
|
|
||||||
FontFamily="Consolas"
|
FontFamily="Consolas"
|
||||||
FontSize="14"
|
FontSize="14"
|
||||||
FontWeight="Bold"
|
FontWeight="Bold"
|
||||||
Foreground="#E8FF47"/>
|
Foreground="#E8FF47"
|
||||||
</Border>
|
Content="Alt + F9"/>
|
||||||
<TextBlock Text="Hotkey remapping coming in a future update."
|
|
||||||
FontSize="11"
|
|
||||||
Foreground="{ThemeResource TextFillColorTertiaryBrush}"/>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
using Microsoft.UI.Xaml;
|
using Microsoft.UI.Xaml;
|
||||||
using Microsoft.UI.Xaml.Controls;
|
using Microsoft.UI.Xaml.Controls;
|
||||||
|
using Microsoft.UI.Xaml.Input;
|
||||||
using Microsoft.UI.Xaml.Media.Animation;
|
using Microsoft.UI.Xaml.Media.Animation;
|
||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using Windows.System;
|
||||||
using WinRT.Interop;
|
using WinRT.Interop;
|
||||||
|
|
||||||
namespace ClipForge
|
namespace ClipForge
|
||||||
@@ -16,6 +18,7 @@ namespace ClipForge
|
|||||||
private ClipLibraryService _clipLibrary;
|
private ClipLibraryService _clipLibrary;
|
||||||
private SettingsService _settingsService;
|
private SettingsService _settingsService;
|
||||||
private ThumbnailService _thumbnailService;
|
private ThumbnailService _thumbnailService;
|
||||||
|
private bool _isRecordingHotkey;
|
||||||
|
|
||||||
private delegate IntPtr WinProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
|
private delegate IntPtr WinProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
|
||||||
private WinProc _newWndProc;
|
private WinProc _newWndProc;
|
||||||
@@ -41,6 +44,13 @@ namespace ClipForge
|
|||||||
private static extern IntPtr SendMessage(IntPtr hWnd, uint msg,
|
private static extern IntPtr SendMessage(IntPtr hWnd, uint msg,
|
||||||
IntPtr wParam, IntPtr lParam);
|
IntPtr wParam, IntPtr lParam);
|
||||||
|
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
private static extern short GetAsyncKeyState(int vk);
|
||||||
|
|
||||||
|
private const int VK_SHIFT = 0x10;
|
||||||
|
private const int VK_CONTROL = 0x11;
|
||||||
|
private const int VK_MENU = 0x12; // Alt
|
||||||
|
private const int VK_LWIN = 0x5B;
|
||||||
private const int GWLP_WNDPROC = -4;
|
private const int GWLP_WNDPROC = -4;
|
||||||
private const uint WM_HOTKEY = 0x0312;
|
private const uint WM_HOTKEY = 0x0312;
|
||||||
private const int GWL_EXSTYLE = -20;
|
private const int GWL_EXSTYLE = -20;
|
||||||
@@ -78,7 +88,10 @@ namespace ClipForge
|
|||||||
|
|
||||||
_hotkeyService = new GlobalHotkeyService();
|
_hotkeyService = new GlobalHotkeyService();
|
||||||
_hotkeyService.ClipRequested += OnClipRequested;
|
_hotkeyService.ClipRequested += OnClipRequested;
|
||||||
_hotkeyService.Initialize(hwnd);
|
var mod = _settingsService.Settings.HotkeyModifiers;
|
||||||
|
var vk = _settingsService.Settings.HotkeyVirtualKey;
|
||||||
|
if (mod == 0 && vk == 0) { mod = 1; vk = 0x78; }
|
||||||
|
_hotkeyService.Initialize(hwnd, (uint)mod, (uint)vk);
|
||||||
|
|
||||||
ClipGrid.ItemsSource = _clipLibrary.Clips;
|
ClipGrid.ItemsSource = _clipLibrary.Clips;
|
||||||
UpdateClipCount();
|
UpdateClipCount();
|
||||||
@@ -169,6 +182,8 @@ namespace ClipForge
|
|||||||
QualityLabel.Text = $"{s.VideoQuality}%";
|
QualityLabel.Text = $"{s.VideoQuality}%";
|
||||||
FramerateCombo.SelectedIndex = s.Framerate == 30 ? 0 : 1;
|
FramerateCombo.SelectedIndex = s.Framerate == 30 ? 0 : 1;
|
||||||
StartupToggle.IsOn = IsStartupEnabled();
|
StartupToggle.IsOn = IsStartupEnabled();
|
||||||
|
if (HotkeyRecorderButton != null)
|
||||||
|
HotkeyRecorderButton.Content = HotkeyHelper.ToDisplayString((uint)s.HotkeyModifiers, (uint)s.HotkeyVirtualKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- STARTUP WITH WINDOWS ---
|
// --- STARTUP WITH WINDOWS ---
|
||||||
@@ -235,6 +250,89 @@ namespace ClipForge
|
|||||||
_ = ShowToastAsync("✅ Settings saved!");
|
_ = ShowToastAsync("✅ Settings saved!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- CUSTOM HOTKEY ---
|
||||||
|
private void HotkeyRecorderButton_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (_isRecordingHotkey) return;
|
||||||
|
_isRecordingHotkey = true;
|
||||||
|
HotkeyRecorderButton.Content = "Press any key... (Esc to cancel)";
|
||||||
|
HotkeyRecorderButton.Focus(FocusState.Programmatic);
|
||||||
|
HotkeyRecorderButton.KeyDown += OnHotkeyCaptureKeyDown;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnHotkeyCaptureKeyDown(object sender, KeyRoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (!_isRecordingHotkey) return;
|
||||||
|
e.Handled = true;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var key = e.Key;
|
||||||
|
// Escape cancels without changing the hotkey
|
||||||
|
if (key == VirtualKey.Escape)
|
||||||
|
{
|
||||||
|
StopRecordingHotkey(restoreDisplay: true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (HotkeyHelper.IsModifierKey(key))
|
||||||
|
return; // wait for a non-modifier key
|
||||||
|
if (key == VirtualKey.None)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint mod = 0;
|
||||||
|
if ((GetAsyncKeyState(VK_CONTROL) & 0x8000) != 0) mod |= HotkeyHelper.MOD_CONTROL;
|
||||||
|
if ((GetAsyncKeyState(VK_MENU) & 0x8000) != 0) mod |= HotkeyHelper.MOD_ALT;
|
||||||
|
if ((GetAsyncKeyState(VK_SHIFT) & 0x8000) != 0) mod |= HotkeyHelper.MOD_SHIFT;
|
||||||
|
if ((GetAsyncKeyState(VK_LWIN) & 0x8000) != 0) mod |= HotkeyHelper.MOD_WIN;
|
||||||
|
|
||||||
|
uint vk = (uint)key;
|
||||||
|
_settingsService.Settings.HotkeyModifiers = (int)mod;
|
||||||
|
_settingsService.Settings.HotkeyVirtualKey = (int)vk;
|
||||||
|
|
||||||
|
var display = HotkeyHelper.ToDisplayString(mod, vk);
|
||||||
|
StopRecordingHotkey(restoreDisplay: false);
|
||||||
|
HotkeyRecorderButton.Content = display;
|
||||||
|
|
||||||
|
// Defer registration so the key is released first; otherwise the new hotkey can fire
|
||||||
|
// immediately and re-enter (e.g. OnClipRequested) and crash.
|
||||||
|
_ = DelayedHotkeyRegister(mod, vk, display);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
StopRecordingHotkey(restoreDisplay: true);
|
||||||
|
_ = ShowToastAsync("⚠ " + ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StopRecordingHotkey(bool restoreDisplay)
|
||||||
|
{
|
||||||
|
HotkeyRecorderButton.KeyDown -= OnHotkeyCaptureKeyDown;
|
||||||
|
_isRecordingHotkey = false;
|
||||||
|
if (restoreDisplay)
|
||||||
|
{
|
||||||
|
var s = _settingsService.Settings;
|
||||||
|
HotkeyRecorderButton.Content = HotkeyHelper.ToDisplayString((uint)s.HotkeyModifiers, (uint)s.HotkeyVirtualKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async System.Threading.Tasks.Task DelayedHotkeyRegister(uint mod, uint vk, string display)
|
||||||
|
{
|
||||||
|
await System.Threading.Tasks.Task.Delay(300);
|
||||||
|
App.MainQueue?.TryEnqueue(() =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var ok = _hotkeyService.UpdateHotkey(mod, vk);
|
||||||
|
HotkeyRecorderButton.Content = ok ? display : display + " (in use?)";
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
HotkeyRecorderButton.Content = display;
|
||||||
|
_ = ShowToastAsync("⚠ " + ex.Message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// --- NAV ---
|
// --- NAV ---
|
||||||
private void NavClips_Click(object sender, RoutedEventArgs e)
|
private void NavClips_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
<Identity
|
<Identity
|
||||||
Name="735fb287-32b4-4217-b84a-302365dc5e23"
|
Name="735fb287-32b4-4217-b84a-302365dc5e23"
|
||||||
Publisher="CN=SCOPEDD"
|
Publisher="CN=SCOPEDD"
|
||||||
Version="1.0.0.0" />
|
Version="0.1.0.0" />
|
||||||
|
|
||||||
<mp:PhoneIdentity PhoneProductId="735fb287-32b4-4217-b84a-302365dc5e23" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
|
<mp:PhoneIdentity PhoneProductId="735fb287-32b4-4217-b84a-302365dc5e23" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
|
||||||
@@ -9,7 +9,10 @@ namespace ClipForge
|
|||||||
public int ClipLengthSeconds { get; set; } = 30;
|
public int ClipLengthSeconds { get; set; } = 30;
|
||||||
public int VideoQuality { get; set; } = 70;
|
public int VideoQuality { get; set; } = 70;
|
||||||
public int Framerate { get; set; } = 60;
|
public int Framerate { get; set; } = 60;
|
||||||
public string HotkeyDisplay { get; set; } = "Alt + F9";
|
/// <summary>Windows modifier flags: Alt=1, Ctrl=2, Shift=4, Win=8.</summary>
|
||||||
|
public int HotkeyModifiers { get; set; } = 1; // MOD_ALT
|
||||||
|
/// <summary>Windows virtual key code (e.g. VK_F9=0x78, VK_PRIOR=0x21 for PgUp).</summary>
|
||||||
|
public int HotkeyVirtualKey { get; set; } = 0x78; // VK_F9
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SettingsService
|
public class SettingsService
|
||||||
|
|||||||
Reference in New Issue
Block a user