mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-16 19:57:57 +01:00
[Settings/Run] LowLevel Keyboard hooking for Hotkeys (#3825)
* [Launcher/Settings] Low Level Keyboard Hooks * [Run] LowLevel Keyboard Hook for Hotkeys * Prevent shortcuts from auto repeating when keeping the keys pressed down
This commit is contained in:
committed by
GitHub
parent
fa7e4cc817
commit
670033c4da
@@ -783,7 +783,7 @@
|
|||||||
<Fragment>
|
<Fragment>
|
||||||
<ComponentGroup Id="LauncherComponents">
|
<ComponentGroup Id="LauncherComponents">
|
||||||
<Component Id="launcherInstallComponent" Directory="LauncherInstallFolder" Guid="5E688DB4-C522-4268-BA54-ED1CDFFE9DB6">
|
<Component Id="launcherInstallComponent" Directory="LauncherInstallFolder" Guid="5E688DB4-C522-4268-BA54-ED1CDFFE9DB6">
|
||||||
<?foreach File in concrt140_app.dll;ICSharpCode.SharpZipLib.dll;JetBrains.Annotations.dll;Mages.Core.dll;Microsoft.Search.Interop.dll;EntityFramework.SqlServer.dll;EntityFramework.dll;Mono.Cecil.dll;Mono.Cecil.Mdb.dll;Mono.Cecil.Pdb.dll;Mono.Cecil.Rocks.dll;msvcp140_1_app.dll;msvcp140_2_app.dll;msvcp140_app.dll;Newtonsoft.Json.dll;NHotkey.dll;NHotkey.Wpf.dll;NLog.dll;NLog.Extensions.Logging.dll;Pinyin4Net.dll;PowerLauncher.deps.json;PowerLauncher.dll;PowerLauncher.exe;Microsoft.Toolkit.Win32.UI.XamlHost.Managed.dll;Microsoft.Toolkit.Wpf.UI.XamlHost.dll;Microsoft.Xaml.Behaviors.dll;System.Text.Json.dll;sni.dll;System.Data.SQLite.EF6.dll;PowerLauncher.runtimeconfig.json;SQLite.Interop.dll;System.Data.OleDb.dll;System.Data.SqlClient.dll;System.Data.SQLite.dll;vcamp140_app.dll;vccorlib140_app.dll;vcomp140_app.dll;vcruntime140_1_app.dll;vcruntime140_app.dll;WindowsInput.dll;Wox.Core.dll;Wox.dll;Wox.Infrastructure.dll;Wox.Plugin.dll;PowerToysInterop.dll;Telemetry.dll;PowerLauncher.Telemetry.dll;PropertyChanged.dll;Microsoft.Extensions.Configuration.Abstractions.dll;Microsoft.Extensions.Configuration.Binder.dll;Microsoft.Extensions.Configuration.dll;Microsoft.Extensions.DependencyInjection.Abstractions.dll;Microsoft.Extensions.DependencyInjection.dll;Microsoft.Extensions.Logging.Abstractions.dll;Microsoft.Extensions.Logging.dll;Microsoft.Extensions.Options.dll;Microsoft.Extensions.Primitives.dll;ControlzEx.dll;MahApps.Metro.dll?>
|
<?foreach File in concrt140_app.dll;ICSharpCode.SharpZipLib.dll;JetBrains.Annotations.dll;Mages.Core.dll;Microsoft.Search.Interop.dll;EntityFramework.SqlServer.dll;EntityFramework.dll;Mono.Cecil.dll;Mono.Cecil.Mdb.dll;Mono.Cecil.Pdb.dll;Mono.Cecil.Rocks.dll;msvcp140_1_app.dll;msvcp140_2_app.dll;msvcp140_app.dll;Newtonsoft.Json.dll;NLog.dll;NLog.Extensions.Logging.dll;Pinyin4Net.dll;PowerLauncher.deps.json;PowerLauncher.dll;PowerLauncher.exe;Microsoft.Toolkit.Win32.UI.XamlHost.Managed.dll;Microsoft.Toolkit.Wpf.UI.XamlHost.dll;Microsoft.Xaml.Behaviors.dll;System.Text.Json.dll;sni.dll;System.Data.SQLite.EF6.dll;PowerLauncher.runtimeconfig.json;SQLite.Interop.dll;System.Data.OleDb.dll;System.Data.SqlClient.dll;System.Data.SQLite.dll;vcamp140_app.dll;vccorlib140_app.dll;vcomp140_app.dll;vcruntime140_1_app.dll;vcruntime140_app.dll;WindowsInput.dll;Wox.Core.dll;Wox.dll;Wox.Infrastructure.dll;Wox.Plugin.dll;PowerToysInterop.dll;Telemetry.dll;PowerLauncher.Telemetry.dll;PropertyChanged.dll;Microsoft.Extensions.Configuration.Abstractions.dll;Microsoft.Extensions.Configuration.Binder.dll;Microsoft.Extensions.Configuration.dll;Microsoft.Extensions.DependencyInjection.Abstractions.dll;Microsoft.Extensions.DependencyInjection.dll;Microsoft.Extensions.Logging.Abstractions.dll;Microsoft.Extensions.Logging.dll;Microsoft.Extensions.Options.dll;Microsoft.Extensions.Primitives.dll;ControlzEx.dll;MahApps.Metro.dll?>
|
||||||
<File Id="File_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\$(var.File)" />
|
<File Id="File_$(var.File)" Source="$(var.BinX64Dir)modules\launcher\$(var.File)" />
|
||||||
<?endforeach?>
|
<?endforeach?>
|
||||||
<File Source="$(var.BinX64Dir)SettingsUIRunner\Microsoft.PowerToys.Settings.UI.Lib.dll" />
|
<File Source="$(var.BinX64Dir)SettingsUIRunner\Microsoft.PowerToys.Settings.UI.Lib.dll" />
|
||||||
|
|||||||
133
src/common/interop/HotkeyManager.cpp
Normal file
133
src/common/interop/HotkeyManager.cpp
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#include "HotkeyManager.h"
|
||||||
|
|
||||||
|
using namespace interop;
|
||||||
|
|
||||||
|
HotkeyManager::HotkeyManager()
|
||||||
|
{
|
||||||
|
keyboardEventCallback = gcnew KeyboardEventCallback(this, &HotkeyManager::KeyboardEventProc);
|
||||||
|
isActiveCallback = gcnew IsActiveCallback(this, &HotkeyManager::IsActiveProc);
|
||||||
|
filterKeyboardCallback = gcnew FilterKeyboardEvent(this, &HotkeyManager::FilterKeyboardProc);
|
||||||
|
|
||||||
|
keyboardHook = gcnew KeyboardHook(
|
||||||
|
keyboardEventCallback,
|
||||||
|
isActiveCallback,
|
||||||
|
filterKeyboardCallback
|
||||||
|
);
|
||||||
|
hotkeys = gcnew Dictionary<HOTKEY_HANDLE, HotkeyCallback ^>();
|
||||||
|
pressedKeys = gcnew Hotkey();
|
||||||
|
keyboardHook->Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
HotkeyManager::~HotkeyManager()
|
||||||
|
{
|
||||||
|
delete keyboardHook;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When all Shortcut keys are pressed, fire the HotkeyCallback event.
|
||||||
|
void HotkeyManager::KeyboardEventProc(KeyboardEvent^ ev)
|
||||||
|
{
|
||||||
|
auto pressedKeysHandle = GetHotkeyHandle(pressedKeys);
|
||||||
|
if (hotkeys->ContainsKey(pressedKeysHandle))
|
||||||
|
{
|
||||||
|
hotkeys[pressedKeysHandle]->Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hotkeys are intended to be global, therefore they are always active no matter the
|
||||||
|
// context in which the keypress occurs.
|
||||||
|
bool HotkeyManager::IsActiveProc()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeyboardEvent callback is only fired for relevant key events.
|
||||||
|
bool HotkeyManager::FilterKeyboardProc(KeyboardEvent^ ev)
|
||||||
|
{
|
||||||
|
auto oldHandle = GetHotkeyHandle(pressedKeys);
|
||||||
|
|
||||||
|
// Updating the pressed keys here so we know if the keypress event
|
||||||
|
// should be propagated or not.
|
||||||
|
UpdatePressedKeys(ev);
|
||||||
|
|
||||||
|
auto pressedKeysHandle = GetHotkeyHandle(pressedKeys);
|
||||||
|
|
||||||
|
// Check if the hotkey matches the pressed keys, and check if the pressed keys aren't duplicate
|
||||||
|
// (there shouldn't be auto repeating hotkeys)
|
||||||
|
if (hotkeys->ContainsKey(pressedKeysHandle) && oldHandle != pressedKeysHandle)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Replaces old hotkey if one already present.
|
||||||
|
HOTKEY_HANDLE HotkeyManager::RegisterHotkey(Hotkey ^ hotkey, HotkeyCallback ^ callback)
|
||||||
|
{
|
||||||
|
auto handle = GetHotkeyHandle(hotkey);
|
||||||
|
hotkeys[handle] = callback;
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HotkeyManager::UnregisterHotkey(HOTKEY_HANDLE handle)
|
||||||
|
{
|
||||||
|
hotkeys->Remove(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
HOTKEY_HANDLE HotkeyManager::GetHotkeyHandle(Hotkey ^ hotkey)
|
||||||
|
{
|
||||||
|
HOTKEY_HANDLE handle = hotkey->Key;
|
||||||
|
handle |= hotkey->Win << 8;
|
||||||
|
handle |= hotkey->Ctrl << 9;
|
||||||
|
handle |= hotkey->Shift << 10;
|
||||||
|
handle |= hotkey->Alt << 11;
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HotkeyManager::UpdatePressedKey(DWORD code, bool replaceWith, unsigned char replaceWithKey)
|
||||||
|
{
|
||||||
|
switch (code)
|
||||||
|
{
|
||||||
|
case VK_LWIN:
|
||||||
|
case VK_RWIN:
|
||||||
|
pressedKeys->Win = replaceWith;
|
||||||
|
break;
|
||||||
|
case VK_CONTROL:
|
||||||
|
case VK_LCONTROL:
|
||||||
|
case VK_RCONTROL:
|
||||||
|
pressedKeys->Ctrl = replaceWith;
|
||||||
|
break;
|
||||||
|
case VK_SHIFT:
|
||||||
|
case VK_LSHIFT:
|
||||||
|
case VK_RSHIFT:
|
||||||
|
pressedKeys->Shift = replaceWith;
|
||||||
|
break;
|
||||||
|
case VK_MENU:
|
||||||
|
case VK_LMENU:
|
||||||
|
case VK_RMENU:
|
||||||
|
pressedKeys->Alt = replaceWith;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
pressedKeys->Key = replaceWithKey;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HotkeyManager::UpdatePressedKeys(KeyboardEvent ^ ev)
|
||||||
|
{
|
||||||
|
switch (ev->message)
|
||||||
|
{
|
||||||
|
case WM_KEYDOWN:
|
||||||
|
case WM_SYSKEYDOWN:
|
||||||
|
{
|
||||||
|
UpdatePressedKey(ev->key, true, ev->key);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WM_KEYUP:
|
||||||
|
case WM_SYSKEYUP:
|
||||||
|
{
|
||||||
|
UpdatePressedKey(ev->key, false, 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
57
src/common/interop/HotkeyManager.h
Normal file
57
src/common/interop/HotkeyManager.h
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <Windows.h>
|
||||||
|
#include "KeyboardHook.h"
|
||||||
|
|
||||||
|
namespace interop
|
||||||
|
{
|
||||||
|
public
|
||||||
|
ref struct Hotkey
|
||||||
|
{
|
||||||
|
bool Win;
|
||||||
|
bool Ctrl;
|
||||||
|
bool Shift;
|
||||||
|
bool Alt;
|
||||||
|
unsigned char Key;
|
||||||
|
|
||||||
|
Hotkey()
|
||||||
|
{
|
||||||
|
Win = false;
|
||||||
|
Ctrl = false;
|
||||||
|
Shift = false;
|
||||||
|
Alt = false;
|
||||||
|
Key = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public
|
||||||
|
delegate void HotkeyCallback();
|
||||||
|
|
||||||
|
typedef unsigned short HOTKEY_HANDLE;
|
||||||
|
|
||||||
|
public
|
||||||
|
ref class HotkeyManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HotkeyManager();
|
||||||
|
~HotkeyManager();
|
||||||
|
|
||||||
|
HOTKEY_HANDLE RegisterHotkey(Hotkey ^ hotkey, HotkeyCallback ^ callback);
|
||||||
|
void UnregisterHotkey(HOTKEY_HANDLE handle);
|
||||||
|
|
||||||
|
private:
|
||||||
|
KeyboardHook ^ keyboardHook;
|
||||||
|
Dictionary<HOTKEY_HANDLE, HotkeyCallback ^> ^ hotkeys;
|
||||||
|
Hotkey ^ pressedKeys;
|
||||||
|
KeyboardEventCallback ^ keyboardEventCallback;
|
||||||
|
IsActiveCallback ^ isActiveCallback;
|
||||||
|
FilterKeyboardEvent ^ filterKeyboardCallback;
|
||||||
|
|
||||||
|
|
||||||
|
void KeyboardEventProc(KeyboardEvent ^ ev);
|
||||||
|
bool IsActiveProc();
|
||||||
|
bool FilterKeyboardProc(KeyboardEvent ^ ev);
|
||||||
|
HOTKEY_HANDLE GetHotkeyHandle(Hotkey ^ hotkey);
|
||||||
|
void UpdatePressedKeys(KeyboardEvent ^ ev);
|
||||||
|
void UpdatePressedKey(DWORD code, bool replaceWith, unsigned char replaceWithKey);
|
||||||
|
};
|
||||||
|
}
|
||||||
96
src/common/interop/KeyboardHook.cpp
Normal file
96
src/common/interop/KeyboardHook.cpp
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#include "KeyboardHook.h"
|
||||||
|
#include <exception>
|
||||||
|
#include <msclr\marshal.h>
|
||||||
|
#include <msclr\marshal_cppstd.h>
|
||||||
|
|
||||||
|
using namespace interop;
|
||||||
|
using namespace System::Runtime::InteropServices;
|
||||||
|
using namespace System;
|
||||||
|
using namespace System::Diagnostics;
|
||||||
|
|
||||||
|
KeyboardHook::KeyboardHook(
|
||||||
|
KeyboardEventCallback ^ keyboardEventCallback,
|
||||||
|
IsActiveCallback ^ isActiveCallback,
|
||||||
|
FilterKeyboardEvent ^ filterKeyboardEvent)
|
||||||
|
{
|
||||||
|
kbEventDispatch = gcnew Thread(gcnew ThreadStart(this, &KeyboardHook::DispatchProc));
|
||||||
|
queue = gcnew Queue<KeyboardEvent ^>();
|
||||||
|
this->keyboardEventCallback = keyboardEventCallback;
|
||||||
|
this->isActiveCallback = isActiveCallback;
|
||||||
|
this->filterKeyboardEvent = filterKeyboardEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyboardHook::~KeyboardHook()
|
||||||
|
{
|
||||||
|
quit = true;
|
||||||
|
kbEventDispatch->Join();
|
||||||
|
|
||||||
|
// Unregister low level hook procedure
|
||||||
|
UnhookWindowsHookEx(hookHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyboardHook::DispatchProc()
|
||||||
|
{
|
||||||
|
Monitor::Enter(queue);
|
||||||
|
quit = false;
|
||||||
|
while (!quit)
|
||||||
|
{
|
||||||
|
if (queue->Count == 0)
|
||||||
|
{
|
||||||
|
Monitor::Wait(queue);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto nextEv = queue->Dequeue();
|
||||||
|
|
||||||
|
// Release lock while callback is being invoked
|
||||||
|
Monitor::Exit(queue);
|
||||||
|
|
||||||
|
keyboardEventCallback->Invoke(nextEv);
|
||||||
|
|
||||||
|
// Re-aquire lock
|
||||||
|
Monitor::Enter(queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
Monitor::Exit(queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyboardHook::Start()
|
||||||
|
{
|
||||||
|
hookProc = gcnew HookProcDelegate(this, &KeyboardHook::HookProc);
|
||||||
|
Process ^ curProcess = Process::GetCurrentProcess();
|
||||||
|
ProcessModule ^ curModule = curProcess->MainModule;
|
||||||
|
// register low level hook procedure
|
||||||
|
hookHandle = SetWindowsHookEx(
|
||||||
|
WH_KEYBOARD_LL,
|
||||||
|
(HOOKPROC)(void*)Marshal::GetFunctionPointerForDelegate(hookProc),
|
||||||
|
0,
|
||||||
|
0);
|
||||||
|
if (hookHandle == nullptr)
|
||||||
|
{
|
||||||
|
throw std::exception("SetWindowsHookEx failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
kbEventDispatch->Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
LRESULT CALLBACK KeyboardHook::HookProc(int nCode, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
if (nCode == HC_ACTION && isActiveCallback->Invoke())
|
||||||
|
{
|
||||||
|
KeyboardEvent ^ ev = gcnew KeyboardEvent();
|
||||||
|
ev->message = wParam;
|
||||||
|
ev->key = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam)->vkCode;
|
||||||
|
if (filterKeyboardEvent != nullptr && !filterKeyboardEvent->Invoke(ev))
|
||||||
|
{
|
||||||
|
return CallNextHookEx(hookHandle, nCode, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
Monitor::Enter(queue);
|
||||||
|
queue->Enqueue(ev);
|
||||||
|
Monitor::Pulse(queue);
|
||||||
|
Monitor::Exit(queue);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return CallNextHookEx(hookHandle, nCode, wParam, lParam);
|
||||||
|
}
|
||||||
49
src/common/interop/KeyboardHook.h
Normal file
49
src/common/interop/KeyboardHook.h
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
using namespace System::Threading;
|
||||||
|
using namespace System::Collections::Generic;
|
||||||
|
|
||||||
|
namespace interop
|
||||||
|
{
|
||||||
|
public
|
||||||
|
ref struct KeyboardEvent
|
||||||
|
{
|
||||||
|
WPARAM message;
|
||||||
|
int key;
|
||||||
|
};
|
||||||
|
|
||||||
|
public
|
||||||
|
delegate void KeyboardEventCallback(KeyboardEvent ^ ev);
|
||||||
|
public
|
||||||
|
delegate bool IsActiveCallback();
|
||||||
|
public
|
||||||
|
delegate bool FilterKeyboardEvent(KeyboardEvent ^ ev);
|
||||||
|
|
||||||
|
public
|
||||||
|
ref class KeyboardHook
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KeyboardHook(
|
||||||
|
KeyboardEventCallback ^ keyboardEventCallback,
|
||||||
|
IsActiveCallback ^ isActiveCallback,
|
||||||
|
FilterKeyboardEvent ^ filterKeyboardEvent);
|
||||||
|
~KeyboardHook();
|
||||||
|
|
||||||
|
void Start();
|
||||||
|
|
||||||
|
private:
|
||||||
|
delegate LRESULT HookProcDelegate(int nCode, WPARAM wParam, LPARAM lParam);
|
||||||
|
Thread ^ kbEventDispatch;
|
||||||
|
Queue<KeyboardEvent ^> ^ queue;
|
||||||
|
KeyboardEventCallback ^ keyboardEventCallback;
|
||||||
|
IsActiveCallback ^ isActiveCallback;
|
||||||
|
FilterKeyboardEvent ^ filterKeyboardEvent;
|
||||||
|
bool quit;
|
||||||
|
HHOOK hookHandle;
|
||||||
|
HookProcDelegate ^ hookProc;
|
||||||
|
|
||||||
|
void DispatchProc();
|
||||||
|
LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<Import Project="..\..\..\installer\Version.props" />
|
<Import Project="..\..\..\installer\Version.props" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
@@ -124,13 +124,17 @@
|
|||||||
<WriteLinesToFile File="Generated Files\AssemblyInfo.cpp" Lines="@(HeaderLines)" Overwrite="true" Encoding="Unicode" WriteOnlyWhenDifferent="true" />
|
<WriteLinesToFile File="Generated Files\AssemblyInfo.cpp" Lines="@(HeaderLines)" Overwrite="true" Encoding="Unicode" WriteOnlyWhenDifferent="true" />
|
||||||
</Target>
|
</Target>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClInclude Include="HotkeyManager.h" />
|
||||||
<ClInclude Include="interop.h" />
|
<ClInclude Include="interop.h" />
|
||||||
|
<ClInclude Include="KeyboardHook.h" />
|
||||||
<ClInclude Include="pch.h" />
|
<ClInclude Include="pch.h" />
|
||||||
<ClInclude Include="Resource.h" />
|
<ClInclude Include="Resource.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="Generated Files\AssemblyInfo.cpp" />
|
<ClCompile Include="Generated Files\AssemblyInfo.cpp" />
|
||||||
|
<ClCompile Include="HotkeyManager.cpp" />
|
||||||
<ClCompile Include="interop.cpp" />
|
<ClCompile Include="interop.cpp" />
|
||||||
|
<ClCompile Include="KeyboardHook.cpp" />
|
||||||
<ClCompile Include="pch.cpp">
|
<ClCompile Include="pch.cpp">
|
||||||
<PrecompiledHeader Condition="'$(CIBuild)'!='true'">Create</PrecompiledHeader>
|
<PrecompiledHeader Condition="'$(CIBuild)'!='true'">Create</PrecompiledHeader>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|||||||
@@ -24,6 +24,12 @@
|
|||||||
<ClInclude Include="pch.h">
|
<ClInclude Include="pch.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="KeyboardHook.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="HotkeyManager.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="interop.cpp">
|
<ClCompile Include="interop.cpp">
|
||||||
@@ -35,6 +41,12 @@
|
|||||||
<ClCompile Include="Generated Files\AssemblyInfo.cpp">
|
<ClCompile Include="Generated Files\AssemblyInfo.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="KeyboardHook.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="HotkeyManager.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ResourceCompile Include="app.rc">
|
<ResourceCompile Include="app.rc">
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
#ifndef PCH_H
|
#ifndef PCH_H
|
||||||
#define PCH_H
|
#define PCH_H
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
// add headers that you want to pre-compile here
|
// add headers that you want to pre-compile here
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
#endif //PCH_H
|
#endif //PCH_H
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
// See the LICENSE file in the project root for more information.
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
using Microsoft.PowerToys.Settings.UI.Lib.Utilities;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Lib.Utilities;
|
||||||
|
|
||||||
namespace Microsoft.PowerToys.Settings.UI.Lib
|
namespace Microsoft.PowerToys.Settings.UI.Lib
|
||||||
{
|
{
|
||||||
@@ -30,6 +30,11 @@ namespace Microsoft.PowerToys.Settings.UI.Lib
|
|||||||
Code = code;
|
Code = code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public HotkeySettings Clone()
|
||||||
|
{
|
||||||
|
return new HotkeySettings(Win, Ctrl, Alt, Shift, Key, Code);
|
||||||
|
}
|
||||||
|
|
||||||
[JsonPropertyName("win")]
|
[JsonPropertyName("win")]
|
||||||
public bool Win { get; set; }
|
public bool Win { get; set; }
|
||||||
|
|
||||||
@@ -72,8 +77,16 @@ namespace Microsoft.PowerToys.Settings.UI.Lib
|
|||||||
output.Append("Shift + ");
|
output.Append("Shift + ");
|
||||||
}
|
}
|
||||||
|
|
||||||
var localKey = Helper.GetKeyName((uint) Code);
|
if (Code > 0)
|
||||||
|
{
|
||||||
|
var localKey = Helper.GetKeyName((uint)Code);
|
||||||
output.Append(localKey);
|
output.Append(localKey);
|
||||||
|
}
|
||||||
|
else if (output.Length >= 2)
|
||||||
|
{
|
||||||
|
output.Remove(output.Length - 2, 2);
|
||||||
|
}
|
||||||
|
|
||||||
return output.ToString();
|
return output.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using interop;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.Settings.UI.Lib
|
||||||
|
{
|
||||||
|
public delegate void KeyEvent(int key);
|
||||||
|
|
||||||
|
public delegate bool IsActive();
|
||||||
|
|
||||||
|
public class HotkeySettingsControlHook
|
||||||
|
{
|
||||||
|
const int WM_KEYDOWN = 0x100;
|
||||||
|
const int WM_KEYUP = 0x101;
|
||||||
|
const int WM_SYSKEYDOWN = 0x0104;
|
||||||
|
const int WM_SYSKEYUP = 0x0105;
|
||||||
|
|
||||||
|
private KeyboardHook hook;
|
||||||
|
private KeyEvent keyDown;
|
||||||
|
private KeyEvent keyUp;
|
||||||
|
private IsActive isActive;
|
||||||
|
|
||||||
|
public HotkeySettingsControlHook(KeyEvent keyDown, KeyEvent keyUp, IsActive isActive)
|
||||||
|
{
|
||||||
|
this.keyDown = keyDown;
|
||||||
|
this.keyUp = keyUp;
|
||||||
|
this.isActive = isActive;
|
||||||
|
hook = new KeyboardHook(HotkeySettingsHookCallback, IsActive, null);
|
||||||
|
hook.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsActive()
|
||||||
|
{
|
||||||
|
return isActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HotkeySettingsHookCallback(KeyboardEvent ev)
|
||||||
|
{
|
||||||
|
switch (ev.message)
|
||||||
|
{
|
||||||
|
case WM_KEYDOWN:
|
||||||
|
case WM_SYSKEYDOWN:
|
||||||
|
keyDown(ev.key);
|
||||||
|
break;
|
||||||
|
case WM_KEYUP:
|
||||||
|
case WM_SYSKEYUP:
|
||||||
|
keyUp(ev.key);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ using Windows.UI.Core;
|
|||||||
using Windows.UI.Xaml;
|
using Windows.UI.Xaml;
|
||||||
using Windows.UI.Xaml.Controls;
|
using Windows.UI.Xaml.Controls;
|
||||||
using Windows.UI.Xaml.Input;
|
using Windows.UI.Xaml.Input;
|
||||||
|
using System;
|
||||||
|
|
||||||
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
|
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
|
||||||
namespace Microsoft.PowerToys.Settings.UI.Controls
|
namespace Microsoft.PowerToys.Settings.UI.Controls
|
||||||
@@ -23,7 +24,10 @@ namespace Microsoft.PowerToys.Settings.UI.Controls
|
|||||||
null);
|
null);
|
||||||
|
|
||||||
private HotkeySettings hotkeySettings;
|
private HotkeySettings hotkeySettings;
|
||||||
private HotkeySettings internalSettings = new HotkeySettings();
|
private HotkeySettings internalSettings;
|
||||||
|
private HotkeySettings lastValidSettings;
|
||||||
|
private HotkeySettingsControlHook hook;
|
||||||
|
private bool _isActive;
|
||||||
|
|
||||||
public HotkeySettings HotkeySettings
|
public HotkeySettings HotkeySettings
|
||||||
{
|
{
|
||||||
@@ -48,74 +52,85 @@ namespace Microsoft.PowerToys.Settings.UI.Controls
|
|||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
internalSettings = new HotkeySettings();
|
internalSettings = new HotkeySettings();
|
||||||
|
|
||||||
HotkeyTextBox.PreviewKeyDown += HotkeyTextBox_KeyDown;
|
HotkeyTextBox.GettingFocus += HotkeyTextBox_GettingFocus;
|
||||||
HotkeyTextBox.LostFocus += HotkeyTextBox_LosingFocus;
|
HotkeyTextBox.LosingFocus += HotkeyTextBox_LosingFocus;
|
||||||
|
hook = new HotkeySettingsControlHook(Hotkey_KeyDown, Hotkey_KeyUp, Hotkey_IsActive);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsDown(Windows.System.VirtualKey key)
|
private void KeyEventHandler(int key, bool matchValue, int matchValueCode, string matchValueText)
|
||||||
{
|
{
|
||||||
return Window.Current.CoreWindow.GetKeyState(key).HasFlag(CoreVirtualKeyStates.Down);
|
switch ((Windows.System.VirtualKey)key)
|
||||||
}
|
|
||||||
|
|
||||||
private void HotkeyTextBox_KeyDown(object sender, KeyRoutedEventArgs e)
|
|
||||||
{
|
|
||||||
e.Handled = true;
|
|
||||||
if (
|
|
||||||
e.Key == Windows.System.VirtualKey.LeftWindows ||
|
|
||||||
e.Key == Windows.System.VirtualKey.RightWindows ||
|
|
||||||
e.Key == Windows.System.VirtualKey.Control ||
|
|
||||||
e.Key == Windows.System.VirtualKey.Menu ||
|
|
||||||
e.Key == Windows.System.VirtualKey.Shift)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e.Key == Windows.System.VirtualKey.Escape)
|
|
||||||
{
|
{
|
||||||
|
case Windows.System.VirtualKey.LeftWindows:
|
||||||
|
case Windows.System.VirtualKey.RightWindows:
|
||||||
|
internalSettings.Win = matchValue;
|
||||||
|
break;
|
||||||
|
case Windows.System.VirtualKey.Control:
|
||||||
|
case Windows.System.VirtualKey.LeftControl:
|
||||||
|
case Windows.System.VirtualKey.RightControl:
|
||||||
|
internalSettings.Ctrl = matchValue;
|
||||||
|
break;
|
||||||
|
case Windows.System.VirtualKey.Menu:
|
||||||
|
case Windows.System.VirtualKey.LeftMenu:
|
||||||
|
case Windows.System.VirtualKey.RightMenu:
|
||||||
|
internalSettings.Alt = matchValue;
|
||||||
|
break;
|
||||||
|
case Windows.System.VirtualKey.Shift:
|
||||||
|
case Windows.System.VirtualKey.LeftShift:
|
||||||
|
case Windows.System.VirtualKey.RightShift:
|
||||||
|
internalSettings.Shift = matchValue;
|
||||||
|
break;
|
||||||
|
case Windows.System.VirtualKey.Escape:
|
||||||
internalSettings = new HotkeySettings();
|
internalSettings = new HotkeySettings();
|
||||||
HotkeySettings = new HotkeySettings();
|
HotkeySettings = new HotkeySettings();
|
||||||
return;
|
return;
|
||||||
|
default:
|
||||||
|
internalSettings.Code = matchValueCode;
|
||||||
|
internalSettings.Key = matchValueText;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var settings = new HotkeySettings();
|
private async void Hotkey_KeyDown(int key)
|
||||||
|
|
||||||
// Display HotKey value
|
|
||||||
if (IsDown(Windows.System.VirtualKey.LeftWindows) ||
|
|
||||||
IsDown(Windows.System.VirtualKey.RightWindows))
|
|
||||||
{
|
{
|
||||||
settings.Win = true;
|
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
|
||||||
}
|
|
||||||
|
|
||||||
if (IsDown(Windows.System.VirtualKey.Control))
|
|
||||||
{
|
{
|
||||||
settings.Ctrl = true;
|
KeyEventHandler(key, true, key, Lib.Utilities.Helper.GetKeyName((uint)key));
|
||||||
}
|
if (internalSettings.Code > 0)
|
||||||
|
|
||||||
if (IsDown(Windows.System.VirtualKey.Menu))
|
|
||||||
{
|
{
|
||||||
settings.Alt = true;
|
lastValidSettings = internalSettings.Clone();
|
||||||
|
HotkeyTextBox.Text = lastValidSettings.ToString();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsDown(Windows.System.VirtualKey.Shift))
|
private async void Hotkey_KeyUp(int key)
|
||||||
{
|
{
|
||||||
settings.Shift = true;
|
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
|
||||||
|
{
|
||||||
|
KeyEventHandler(key, false, 0, string.Empty);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.Key = Lib.Utilities.Helper.GetKeyName((uint)e.Key);
|
private bool Hotkey_IsActive()
|
||||||
|
{
|
||||||
|
return _isActive;
|
||||||
|
}
|
||||||
|
|
||||||
settings.Code = (int)e.OriginalKey;
|
private void HotkeyTextBox_GettingFocus(object sender, RoutedEventArgs e)
|
||||||
internalSettings = settings;
|
{
|
||||||
HotkeyTextBox.Text = internalSettings.ToString();
|
_isActive = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HotkeyTextBox_LosingFocus(object sender, RoutedEventArgs e)
|
private void HotkeyTextBox_LosingFocus(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if (internalSettings.IsValid() || internalSettings.IsEmpty())
|
if (lastValidSettings != null && (lastValidSettings.IsValid() || lastValidSettings.IsEmpty()))
|
||||||
{
|
{
|
||||||
HotkeySettings = internalSettings;
|
HotkeySettings = lastValidSettings.Clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
HotkeyTextBox.Text = hotkeySettings.ToString();
|
HotkeyTextBox.Text = hotkeySettings.ToString();
|
||||||
|
_isActive = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ using System.Threading.Tasks;
|
|||||||
using System.Windows;
|
using System.Windows;
|
||||||
using WindowsInput;
|
using WindowsInput;
|
||||||
using WindowsInput.Native;
|
using WindowsInput.Native;
|
||||||
using Wox.Infrastructure.Hotkey;
|
|
||||||
using Wox.Infrastructure.Logger;
|
using Wox.Infrastructure.Logger;
|
||||||
using Wox.Infrastructure.Storage;
|
using Wox.Infrastructure.Storage;
|
||||||
using Wox.Plugin.SharedCommands;
|
using Wox.Plugin.SharedCommands;
|
||||||
@@ -289,7 +288,6 @@ namespace Microsoft.Plugin.Shell
|
|||||||
public void Init(PluginInitContext context)
|
public void Init(PluginInitContext context)
|
||||||
{
|
{
|
||||||
this._context = context;
|
this._context = context;
|
||||||
context.API.GlobalKeyboardEvent += API_GlobalKeyboardEvent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool API_GlobalKeyboardEvent(int keyevent, int vkcode, SpecialKeyState state)
|
bool API_GlobalKeyboardEvent(int keyevent, int vkcode, SpecialKeyState state)
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
<UserControl x:Class="Wox.HotkeyControl"
|
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
|
||||||
xmlns:input="clr-namespace:System.Windows.Input;assembly=PresentationCore"
|
|
||||||
mc:Ignorable="d"
|
|
||||||
Height="24"
|
|
||||||
d:DesignHeight="300" d:DesignWidth="300">
|
|
||||||
<Grid>
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="150" />
|
|
||||||
<ColumnDefinition Width="120" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<TextBox x:Name="tbHotkey" TabIndex="100" VerticalContentAlignment="Center" Grid.Column="0"
|
|
||||||
PreviewKeyDown="TbHotkey_OnPreviewKeyDown" input:InputMethod.IsInputMethodEnabled="False"/>
|
|
||||||
<TextBlock x:Name="tbMsg" Visibility="Hidden" Margin="5 0 0 0" VerticalAlignment="Center" Grid.Column="1" />
|
|
||||||
</Grid>
|
|
||||||
</UserControl>
|
|
||||||
@@ -1,117 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
using System.Windows.Input;
|
|
||||||
using System.Windows.Media;
|
|
||||||
using NHotkey.Wpf;
|
|
||||||
using Wox.Core.Resource;
|
|
||||||
using Wox.Infrastructure.Hotkey;
|
|
||||||
using Wox.Plugin;
|
|
||||||
|
|
||||||
namespace Wox
|
|
||||||
{
|
|
||||||
public partial class HotkeyControl : UserControl
|
|
||||||
{
|
|
||||||
public HotkeyModel CurrentHotkey { get; private set; }
|
|
||||||
public bool CurrentHotkeyAvailable { get; private set; }
|
|
||||||
|
|
||||||
public event EventHandler HotkeyChanged;
|
|
||||||
|
|
||||||
protected virtual void OnHotkeyChanged()
|
|
||||||
{
|
|
||||||
EventHandler handler = HotkeyChanged;
|
|
||||||
if (handler != null) handler(this, EventArgs.Empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
public HotkeyControl()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TbHotkey_OnPreviewKeyDown(object sender, KeyEventArgs e)
|
|
||||||
{
|
|
||||||
e.Handled = true;
|
|
||||||
tbMsg.Visibility = Visibility.Hidden;
|
|
||||||
|
|
||||||
//when alt is pressed, the real key should be e.SystemKey
|
|
||||||
Key key = (e.Key == Key.System ? e.SystemKey : e.Key);
|
|
||||||
|
|
||||||
SpecialKeyState specialKeyState = GlobalHotkey.Instance.CheckModifiers();
|
|
||||||
|
|
||||||
var hotkeyModel = new HotkeyModel(
|
|
||||||
specialKeyState.AltPressed,
|
|
||||||
specialKeyState.ShiftPressed,
|
|
||||||
specialKeyState.WinPressed,
|
|
||||||
specialKeyState.CtrlPressed,
|
|
||||||
key);
|
|
||||||
|
|
||||||
var hotkeyString = hotkeyModel.ToString();
|
|
||||||
|
|
||||||
if (hotkeyString == tbHotkey.Text)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Dispatcher.InvokeAsync(async () =>
|
|
||||||
{
|
|
||||||
await Task.Delay(500);
|
|
||||||
SetHotkey(hotkeyModel);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetHotkey(HotkeyModel keyModel, bool triggerValidate = true)
|
|
||||||
{
|
|
||||||
CurrentHotkey = keyModel;
|
|
||||||
|
|
||||||
tbHotkey.Text = CurrentHotkey.ToString();
|
|
||||||
tbHotkey.Select(tbHotkey.Text.Length, 0);
|
|
||||||
|
|
||||||
if (triggerValidate)
|
|
||||||
{
|
|
||||||
CurrentHotkeyAvailable = CheckHotkeyAvailability();
|
|
||||||
if (!CurrentHotkeyAvailable)
|
|
||||||
{
|
|
||||||
tbMsg.Foreground = new SolidColorBrush(Colors.Red);
|
|
||||||
tbMsg.Text = InternationalizationManager.Instance.GetTranslation("hotkeyUnavailable");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tbMsg.Foreground = new SolidColorBrush(Colors.Green);
|
|
||||||
tbMsg.Text = InternationalizationManager.Instance.GetTranslation("success");
|
|
||||||
}
|
|
||||||
tbMsg.Visibility = Visibility.Visible;
|
|
||||||
OnHotkeyChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetHotkey(string keyStr, bool triggerValidate = true)
|
|
||||||
{
|
|
||||||
SetHotkey(new HotkeyModel(keyStr), triggerValidate);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool CheckHotkeyAvailability()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
HotkeyManager.Current.AddOrReplace("HotkeyAvailabilityTest", CurrentHotkey.CharKey, CurrentHotkey.ModifierKeys, (sender, e) => { });
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
HotkeyManager.Current.Remove("HotkeyAvailabilityTest");
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public new bool IsFocused
|
|
||||||
{
|
|
||||||
get { return tbHotkey.IsFocused; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -59,7 +59,6 @@
|
|||||||
<PackageReference Include="Mages" Version="1.6.0" />
|
<PackageReference Include="Mages" Version="1.6.0" />
|
||||||
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.19" />
|
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.19" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||||
<PackageReference Include="NHotkey.Wpf" Version="2.0.1" />
|
|
||||||
<PackageReference Include="NuGet.CommandLine" Version="5.5.1">
|
<PackageReference Include="NuGet.CommandLine" Version="5.5.1">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ namespace PowerLauncher
|
|||||||
var openPowerlauncher = ConvertHotkey(overloadSettings.properties.open_powerlauncher);
|
var openPowerlauncher = ConvertHotkey(overloadSettings.properties.open_powerlauncher);
|
||||||
if (_settings.Hotkey != openPowerlauncher)
|
if (_settings.Hotkey != openPowerlauncher)
|
||||||
{
|
{
|
||||||
_settings.Hotkey = ConvertHotkey(overloadSettings.properties.open_powerlauncher);
|
_settings.Hotkey = openPowerlauncher;
|
||||||
}
|
}
|
||||||
|
|
||||||
var shell = PluginManager.AllPlugins.Find(pp => pp.Metadata.Name == "Shell");
|
var shell = PluginManager.AllPlugins.Find(pp => pp.Metadata.Name == "Shell");
|
||||||
|
|||||||
@@ -1,107 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using Wox.Plugin;
|
|
||||||
|
|
||||||
namespace Wox.Infrastructure.Hotkey
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Listens keyboard globally.
|
|
||||||
/// <remarks>Uses WH_KEYBOARD_LL.</remarks>
|
|
||||||
/// </summary>
|
|
||||||
public class GlobalHotkey : IDisposable
|
|
||||||
{
|
|
||||||
private static GlobalHotkey instance;
|
|
||||||
private InterceptKeys.LowLevelKeyboardProc hookedLowLevelKeyboardProc;
|
|
||||||
private IntPtr hookId = IntPtr.Zero;
|
|
||||||
public delegate bool KeyboardCallback(KeyEvent keyEvent, int vkCode, SpecialKeyState state);
|
|
||||||
public event KeyboardCallback hookedKeyboardCallback;
|
|
||||||
|
|
||||||
//Modifier key constants
|
|
||||||
private const int VK_SHIFT = 0x10;
|
|
||||||
private const int VK_CONTROL = 0x11;
|
|
||||||
private const int VK_ALT = 0x12;
|
|
||||||
private const int VK_WIN = 91;
|
|
||||||
|
|
||||||
public static GlobalHotkey Instance
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (instance == null)
|
|
||||||
{
|
|
||||||
instance = new GlobalHotkey();
|
|
||||||
}
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private GlobalHotkey()
|
|
||||||
{
|
|
||||||
// We have to store the LowLevelKeyboardProc, so that it is not garbage collected runtime
|
|
||||||
hookedLowLevelKeyboardProc = LowLevelKeyboardProc;
|
|
||||||
// Set the hook
|
|
||||||
hookId = InterceptKeys.SetHook(hookedLowLevelKeyboardProc);
|
|
||||||
}
|
|
||||||
|
|
||||||
public SpecialKeyState CheckModifiers()
|
|
||||||
{
|
|
||||||
SpecialKeyState state = new SpecialKeyState();
|
|
||||||
if ((InterceptKeys.GetKeyState(VK_SHIFT) & 0x8000) != 0)
|
|
||||||
{
|
|
||||||
//SHIFT is pressed
|
|
||||||
state.ShiftPressed = true;
|
|
||||||
}
|
|
||||||
if ((InterceptKeys.GetKeyState(VK_CONTROL) & 0x8000) != 0)
|
|
||||||
{
|
|
||||||
//CONTROL is pressed
|
|
||||||
state.CtrlPressed = true;
|
|
||||||
}
|
|
||||||
if ((InterceptKeys.GetKeyState(VK_ALT) & 0x8000) != 0)
|
|
||||||
{
|
|
||||||
//ALT is pressed
|
|
||||||
state.AltPressed = true;
|
|
||||||
}
|
|
||||||
if ((InterceptKeys.GetKeyState(VK_WIN) & 0x8000) != 0)
|
|
||||||
{
|
|
||||||
//WIN is pressed
|
|
||||||
state.WinPressed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
|
||||||
private IntPtr LowLevelKeyboardProc(int nCode, UIntPtr wParam, IntPtr lParam)
|
|
||||||
{
|
|
||||||
bool continues = true;
|
|
||||||
|
|
||||||
if (nCode >= 0)
|
|
||||||
{
|
|
||||||
if (wParam.ToUInt32() == (int)KeyEvent.WM_KEYDOWN ||
|
|
||||||
wParam.ToUInt32() == (int)KeyEvent.WM_KEYUP ||
|
|
||||||
wParam.ToUInt32() == (int)KeyEvent.WM_SYSKEYDOWN ||
|
|
||||||
wParam.ToUInt32() == (int)KeyEvent.WM_SYSKEYUP)
|
|
||||||
{
|
|
||||||
if (hookedKeyboardCallback != null)
|
|
||||||
continues = hookedKeyboardCallback((KeyEvent)wParam.ToUInt32(), Marshal.ReadInt32(lParam), CheckModifiers());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (continues)
|
|
||||||
{
|
|
||||||
return InterceptKeys.CallNextHookEx(hookId, nCode, wParam, lParam);
|
|
||||||
}
|
|
||||||
return (IntPtr)1;
|
|
||||||
}
|
|
||||||
|
|
||||||
~GlobalHotkey()
|
|
||||||
{
|
|
||||||
Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
InterceptKeys.UnhookWindowsHookEx(hookId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -45,6 +45,11 @@ namespace Wox.Infrastructure.Hotkey
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public HotkeyModel()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public HotkeyModel(string hotkeyString)
|
public HotkeyModel(string hotkeyString)
|
||||||
{
|
{
|
||||||
Parse(hotkeyString);
|
Parse(hotkeyString);
|
||||||
|
|||||||
@@ -1,38 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace Wox.Infrastructure.Hotkey
|
|
||||||
{
|
|
||||||
internal static class InterceptKeys
|
|
||||||
{
|
|
||||||
public delegate IntPtr LowLevelKeyboardProc(int nCode, UIntPtr wParam, IntPtr lParam);
|
|
||||||
|
|
||||||
private const int WH_KEYBOARD_LL = 13;
|
|
||||||
|
|
||||||
public static IntPtr SetHook(LowLevelKeyboardProc proc)
|
|
||||||
{
|
|
||||||
using (Process curProcess = Process.GetCurrentProcess())
|
|
||||||
using (ProcessModule curModule = curProcess.MainModule)
|
|
||||||
{
|
|
||||||
return SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
|
||||||
public static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
|
|
||||||
|
|
||||||
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
|
||||||
[return: MarshalAs(UnmanagedType.Bool)]
|
|
||||||
public static extern bool UnhookWindowsHookEx(IntPtr hhk);
|
|
||||||
|
|
||||||
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
|
||||||
public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, UIntPtr wParam, IntPtr lParam);
|
|
||||||
|
|
||||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
|
||||||
public static extern IntPtr GetModuleHandle(string lpModuleName);
|
|
||||||
|
|
||||||
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
|
|
||||||
public static extern short GetKeyState(int keyCode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -8,15 +8,6 @@ namespace Wox.Plugin
|
|||||||
|
|
||||||
public delegate void ResultItemDropEventHandler(Result result, IDataObject dropObject, DragEventArgs e);
|
public delegate void ResultItemDropEventHandler(Result result, IDataObject dropObject, DragEventArgs e);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Global keyboard events
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="keyevent">WM_KEYDOWN = 256,WM_KEYUP = 257,WM_SYSKEYUP = 261,WM_SYSKEYDOWN = 260</param>
|
|
||||||
/// <param name="vkcode"></param>
|
|
||||||
/// <param name="state"></param>
|
|
||||||
/// <returns>return true to continue handling, return false to intercept system handling</returns>
|
|
||||||
public delegate bool WoxGlobalKeyboardEventHandler(int keyevent, int vkcode, SpecialKeyState state);
|
|
||||||
|
|
||||||
public class WoxKeyDownEventArgs
|
public class WoxKeyDownEventArgs
|
||||||
{
|
{
|
||||||
public string Query { get; set; }
|
public string Query { get; set; }
|
||||||
|
|||||||
@@ -114,11 +114,5 @@ namespace Wox.Plugin
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
List<PluginPair> GetAllPlugins();
|
List<PluginPair> GetAllPlugins();
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Fired after global keyboard events
|
|
||||||
/// if you want to hook something like Ctrl+R, you should use this event
|
|
||||||
/// </summary>
|
|
||||||
event WoxGlobalKeyboardEventHandler GlobalKeyboardEvent;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
37
src/modules/launcher/Wox/Helper/KeyboardHelper.cs
Normal file
37
src/modules/launcher/Wox/Helper/KeyboardHelper.cs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using Wox.Plugin;
|
||||||
|
|
||||||
|
namespace Wox.Helper
|
||||||
|
{
|
||||||
|
class KeyboardHelper
|
||||||
|
{
|
||||||
|
public static SpecialKeyState CheckModifiers()
|
||||||
|
{
|
||||||
|
SpecialKeyState state = new SpecialKeyState();
|
||||||
|
if ((Keyboard.GetKeyStates(Key.LeftShift) & KeyStates.Down) > 0 ||
|
||||||
|
(Keyboard.GetKeyStates(Key.RightShift) & KeyStates.Down) > 0)
|
||||||
|
{
|
||||||
|
state.ShiftPressed = true;
|
||||||
|
}
|
||||||
|
if ((Keyboard.GetKeyStates(Key.LWin) & KeyStates.Down) > 0 ||
|
||||||
|
(Keyboard.GetKeyStates(Key.RWin) & KeyStates.Down) > 0)
|
||||||
|
{
|
||||||
|
state.WinPressed = true;
|
||||||
|
}
|
||||||
|
if ((Keyboard.GetKeyStates(Key.LeftCtrl) & KeyStates.Down) > 0 ||
|
||||||
|
(Keyboard.GetKeyStates(Key.RightCtrl) & KeyStates.Down) > 0)
|
||||||
|
{
|
||||||
|
state.CtrlPressed = true;
|
||||||
|
}
|
||||||
|
if ((Keyboard.GetKeyStates(Key.LeftAlt) & KeyStates.Down) > 0 ||
|
||||||
|
(Keyboard.GetKeyStates(Key.RightAlt) & KeyStates.Down) > 0)
|
||||||
|
{
|
||||||
|
state.AltPressed = true;
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
<UserControl x:Class="Wox.HotkeyControl"
|
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
|
||||||
xmlns:input="clr-namespace:System.Windows.Input;assembly=PresentationCore"
|
|
||||||
mc:Ignorable="d"
|
|
||||||
Height="24"
|
|
||||||
d:DesignHeight="300" d:DesignWidth="300">
|
|
||||||
<Grid>
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="150" />
|
|
||||||
<ColumnDefinition Width="120" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<TextBox x:Name="tbHotkey" TabIndex="100" VerticalContentAlignment="Center" Grid.Column="0"
|
|
||||||
PreviewKeyDown="TbHotkey_OnPreviewKeyDown" input:InputMethod.IsInputMethodEnabled="False"/>
|
|
||||||
<TextBlock x:Name="tbMsg" Visibility="Hidden" Margin="5 0 0 0" VerticalAlignment="Center" Grid.Column="1" />
|
|
||||||
</Grid>
|
|
||||||
</UserControl>
|
|
||||||
@@ -1,117 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
using System.Windows.Input;
|
|
||||||
using System.Windows.Media;
|
|
||||||
using NHotkey.Wpf;
|
|
||||||
using Wox.Core.Resource;
|
|
||||||
using Wox.Infrastructure.Hotkey;
|
|
||||||
using Wox.Plugin;
|
|
||||||
|
|
||||||
namespace Wox
|
|
||||||
{
|
|
||||||
public partial class HotkeyControl : UserControl
|
|
||||||
{
|
|
||||||
public HotkeyModel CurrentHotkey { get; private set; }
|
|
||||||
public bool CurrentHotkeyAvailable { get; private set; }
|
|
||||||
|
|
||||||
public event EventHandler HotkeyChanged;
|
|
||||||
|
|
||||||
protected virtual void OnHotkeyChanged()
|
|
||||||
{
|
|
||||||
EventHandler handler = HotkeyChanged;
|
|
||||||
if (handler != null) handler(this, EventArgs.Empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
public HotkeyControl()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TbHotkey_OnPreviewKeyDown(object sender, KeyEventArgs e)
|
|
||||||
{
|
|
||||||
e.Handled = true;
|
|
||||||
tbMsg.Visibility = Visibility.Hidden;
|
|
||||||
|
|
||||||
//when alt is pressed, the real key should be e.SystemKey
|
|
||||||
Key key = (e.Key == Key.System ? e.SystemKey : e.Key);
|
|
||||||
|
|
||||||
SpecialKeyState specialKeyState = GlobalHotkey.Instance.CheckModifiers();
|
|
||||||
|
|
||||||
var hotkeyModel = new HotkeyModel(
|
|
||||||
specialKeyState.AltPressed,
|
|
||||||
specialKeyState.ShiftPressed,
|
|
||||||
specialKeyState.WinPressed,
|
|
||||||
specialKeyState.CtrlPressed,
|
|
||||||
key);
|
|
||||||
|
|
||||||
var hotkeyString = hotkeyModel.ToString();
|
|
||||||
|
|
||||||
if (hotkeyString == tbHotkey.Text)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Dispatcher.InvokeAsync(async () =>
|
|
||||||
{
|
|
||||||
await Task.Delay(500);
|
|
||||||
SetHotkey(hotkeyModel);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetHotkey(HotkeyModel keyModel, bool triggerValidate = true)
|
|
||||||
{
|
|
||||||
CurrentHotkey = keyModel;
|
|
||||||
|
|
||||||
tbHotkey.Text = CurrentHotkey.ToString();
|
|
||||||
tbHotkey.Select(tbHotkey.Text.Length, 0);
|
|
||||||
|
|
||||||
if (triggerValidate)
|
|
||||||
{
|
|
||||||
CurrentHotkeyAvailable = CheckHotkeyAvailability();
|
|
||||||
if (!CurrentHotkeyAvailable)
|
|
||||||
{
|
|
||||||
tbMsg.Foreground = new SolidColorBrush(Colors.Red);
|
|
||||||
tbMsg.Text = InternationalizationManager.Instance.GetTranslation("hotkeyUnavailable");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tbMsg.Foreground = new SolidColorBrush(Colors.Green);
|
|
||||||
tbMsg.Text = InternationalizationManager.Instance.GetTranslation("success");
|
|
||||||
}
|
|
||||||
tbMsg.Visibility = Visibility.Visible;
|
|
||||||
OnHotkeyChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetHotkey(string keyStr, bool triggerValidate = true)
|
|
||||||
{
|
|
||||||
SetHotkey(new HotkeyModel(keyStr), triggerValidate);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool CheckHotkeyAvailability()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
HotkeyManager.Current.AddOrReplace("HotkeyAvailabilityTest", CurrentHotkey.CharKey, CurrentHotkey.ModifierKeys, (sender, e) => { });
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
HotkeyManager.Current.Remove("HotkeyAvailabilityTest");
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public new bool IsFocused
|
|
||||||
{
|
|
||||||
get { return tbHotkey.IsFocused; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -8,7 +8,6 @@ using Wox.Core.Plugin;
|
|||||||
using Wox.Core.Resource;
|
using Wox.Core.Resource;
|
||||||
using Wox.Helper;
|
using Wox.Helper;
|
||||||
using Wox.Infrastructure;
|
using Wox.Infrastructure;
|
||||||
using Wox.Infrastructure.Hotkey;
|
|
||||||
using Wox.Infrastructure.Image;
|
using Wox.Infrastructure.Image;
|
||||||
using Wox.Plugin;
|
using Wox.Plugin;
|
||||||
using Wox.ViewModel;
|
using Wox.ViewModel;
|
||||||
@@ -28,7 +27,6 @@ namespace Wox
|
|||||||
_settingsVM = settingsVM;
|
_settingsVM = settingsVM;
|
||||||
_mainVM = mainVM;
|
_mainVM = mainVM;
|
||||||
_alphabet = alphabet;
|
_alphabet = alphabet;
|
||||||
GlobalHotkey.Instance.hookedKeyboardCallback += KListener_hookedKeyboardCallback;
|
|
||||||
WebRequest.RegisterPrefix("data", new DataWebRequestFactory());
|
WebRequest.RegisterPrefix("data", new DataWebRequestFactory());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,7 +122,6 @@ namespace Wox
|
|||||||
return PluginManager.AllPlugins.ToList();
|
return PluginManager.AllPlugins.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public event WoxGlobalKeyboardEventHandler GlobalKeyboardEvent;
|
|
||||||
|
|
||||||
[Obsolete("This will be removed in Wox 1.3")]
|
[Obsolete("This will be removed in Wox 1.3")]
|
||||||
public void PushResults(Query query, PluginMetadata plugin, List<Result> results)
|
public void PushResults(Query query, PluginMetadata plugin, List<Result> results)
|
||||||
@@ -145,14 +142,6 @@ namespace Wox
|
|||||||
|
|
||||||
#region Private Methods
|
#region Private Methods
|
||||||
|
|
||||||
private bool KListener_hookedKeyboardCallback(KeyEvent keyevent, int vkcode, SpecialKeyState state)
|
|
||||||
{
|
|
||||||
if (GlobalKeyboardEvent != null)
|
|
||||||
{
|
|
||||||
return GlobalKeyboardEvent((int)keyevent, vkcode, state);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ using System.Threading.Tasks;
|
|||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using NHotkey;
|
|
||||||
using NHotkey.Wpf;
|
|
||||||
using Wox.Core.Plugin;
|
using Wox.Core.Plugin;
|
||||||
using Wox.Core.Resource;
|
using Wox.Core.Resource;
|
||||||
using Wox.Helper;
|
using Wox.Helper;
|
||||||
@@ -20,6 +18,7 @@ using Wox.Plugin;
|
|||||||
using Microsoft.PowerLauncher.Telemetry;
|
using Microsoft.PowerLauncher.Telemetry;
|
||||||
using Wox.Storage;
|
using Wox.Storage;
|
||||||
using Microsoft.PowerToys.Telemetry;
|
using Microsoft.PowerToys.Telemetry;
|
||||||
|
using interop;
|
||||||
|
|
||||||
namespace Wox.ViewModel
|
namespace Wox.ViewModel
|
||||||
{
|
{
|
||||||
@@ -42,7 +41,8 @@ namespace Wox.ViewModel
|
|||||||
private CancellationTokenSource _updateSource;
|
private CancellationTokenSource _updateSource;
|
||||||
private CancellationToken _updateToken;
|
private CancellationToken _updateToken;
|
||||||
private bool _saved;
|
private bool _saved;
|
||||||
|
private HotkeyManager _hotkeyManager;
|
||||||
|
private ushort _hotkeyHandle;
|
||||||
private readonly Internationalization _translator = InternationalizationManager.Instance;
|
private readonly Internationalization _translator = InternationalizationManager.Instance;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@@ -51,6 +51,7 @@ namespace Wox.ViewModel
|
|||||||
|
|
||||||
public MainViewModel(Settings settings)
|
public MainViewModel(Settings settings)
|
||||||
{
|
{
|
||||||
|
_hotkeyManager = new HotkeyManager();
|
||||||
_saved = false;
|
_saved = false;
|
||||||
_queryTextBeforeLeaveResults = "";
|
_queryTextBeforeLeaveResults = "";
|
||||||
_lastQuery = new Query();
|
_lastQuery = new Query();
|
||||||
@@ -80,7 +81,7 @@ namespace Wox.ViewModel
|
|||||||
{
|
{
|
||||||
if (_settings.PreviousHotkey != "")
|
if (_settings.PreviousHotkey != "")
|
||||||
{
|
{
|
||||||
RemoveHotkey(_settings.PreviousHotkey);
|
_hotkeyManager.UnregisterHotkey(_hotkeyHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_settings.Hotkey != "")
|
if (_settings.Hotkey != "")
|
||||||
@@ -111,6 +112,13 @@ namespace Wox.ViewModel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~MainViewModel()
|
||||||
|
{
|
||||||
|
if (_hotkeyHandle != 0)
|
||||||
|
{
|
||||||
|
_hotkeyManager.UnregisterHotkey(_hotkeyHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void InitializeKeyCommands()
|
private void InitializeKeyCommands()
|
||||||
{
|
{
|
||||||
@@ -186,11 +194,11 @@ namespace Wox.ViewModel
|
|||||||
{
|
{
|
||||||
MainWindowVisibility = Visibility.Collapsed;
|
MainWindowVisibility = Visibility.Collapsed;
|
||||||
|
|
||||||
Task.Run(() =>
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
result.Action(new ActionContext
|
result.Action(new ActionContext
|
||||||
{
|
{
|
||||||
SpecialKeyState = GlobalHotkey.Instance.CheckModifiers()
|
SpecialKeyState = KeyboardHelper.CheckModifiers()
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -524,18 +532,25 @@ namespace Wox.ViewModel
|
|||||||
}
|
}
|
||||||
#region Hotkey
|
#region Hotkey
|
||||||
|
|
||||||
private void SetHotkey(string hotkeyStr, EventHandler<HotkeyEventArgs> action)
|
private void SetHotkey(string hotkeyStr, HotkeyCallback action)
|
||||||
{
|
{
|
||||||
var hotkey = new HotkeyModel(hotkeyStr);
|
var hotkey = new HotkeyModel(hotkeyStr);
|
||||||
SetHotkey(hotkey, action);
|
SetHotkey(hotkey, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetHotkey(HotkeyModel hotkey, EventHandler<HotkeyEventArgs> action)
|
private void SetHotkey(HotkeyModel hotkeyModel, HotkeyCallback action)
|
||||||
{
|
{
|
||||||
string hotkeyStr = hotkey.ToString();
|
string hotkeyStr = hotkeyModel.ToString();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
HotkeyManager.Current.AddOrReplace(hotkeyStr, hotkey.CharKey, hotkey.ModifierKeys, action);
|
Hotkey hotkey = new Hotkey();
|
||||||
|
hotkey.Alt = hotkeyModel.Alt;
|
||||||
|
hotkey.Shift = hotkeyModel.Shift;
|
||||||
|
hotkey.Ctrl = hotkeyModel.Ctrl;
|
||||||
|
hotkey.Win = hotkeyModel.Win;
|
||||||
|
hotkey.Key = (byte) KeyInterop.VirtualKeyFromKey(hotkeyModel.CharKey);
|
||||||
|
|
||||||
|
_hotkeyHandle = _hotkeyManager.RegisterHotkey(hotkey, action);
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
@@ -545,14 +560,6 @@ namespace Wox.ViewModel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveHotkey(string hotkeyStr)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(hotkeyStr))
|
|
||||||
{
|
|
||||||
HotkeyManager.Current.Remove(hotkeyStr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if Wox should ignore any hotkeys
|
/// Checks if Wox should ignore any hotkeys
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -572,7 +579,7 @@ namespace Wox.ViewModel
|
|||||||
if (_settings.CustomPluginHotkeys == null) return;
|
if (_settings.CustomPluginHotkeys == null) return;
|
||||||
foreach (CustomPluginHotkey hotkey in _settings.CustomPluginHotkeys)
|
foreach (CustomPluginHotkey hotkey in _settings.CustomPluginHotkeys)
|
||||||
{
|
{
|
||||||
SetHotkey(hotkey.Hotkey, (s, e) =>
|
SetHotkey(hotkey.Hotkey, () =>
|
||||||
{
|
{
|
||||||
if (ShouldIgnoreHotkeys()) return;
|
if (ShouldIgnoreHotkeys()) return;
|
||||||
MainWindowVisibility = Visibility.Visible;
|
MainWindowVisibility = Visibility.Visible;
|
||||||
@@ -581,7 +588,9 @@ namespace Wox.ViewModel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnHotkey(object sender, HotkeyEventArgs e)
|
private void OnHotkey()
|
||||||
|
{
|
||||||
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
if (!ShouldIgnoreHotkeys())
|
if (!ShouldIgnoreHotkeys())
|
||||||
{
|
{
|
||||||
@@ -604,8 +613,8 @@ namespace Wox.ViewModel
|
|||||||
}
|
}
|
||||||
|
|
||||||
ToggleWox();
|
ToggleWox();
|
||||||
e.Handled = true;
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ToggleWox()
|
private void ToggleWox()
|
||||||
|
|||||||
@@ -7,11 +7,10 @@ using System.Windows.Input;
|
|||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using Wox.Core.Plugin;
|
using Wox.Core.Plugin;
|
||||||
using Wox.Infrastructure;
|
using Wox.Infrastructure;
|
||||||
using Wox.Infrastructure.Hotkey;
|
|
||||||
using Wox.Infrastructure.Image;
|
using Wox.Infrastructure.Image;
|
||||||
using Wox.Infrastructure.Logger;
|
using Wox.Infrastructure.Logger;
|
||||||
using Wox.Plugin;
|
using Wox.Plugin;
|
||||||
|
using Wox.Helper;
|
||||||
|
|
||||||
namespace Wox.ViewModel
|
namespace Wox.ViewModel
|
||||||
{
|
{
|
||||||
@@ -128,7 +127,7 @@ namespace Wox.ViewModel
|
|||||||
{
|
{
|
||||||
bool hideWindow = r.Action != null && r.Action(new ActionContext
|
bool hideWindow = r.Action != null && r.Action(new ActionContext
|
||||||
{
|
{
|
||||||
SpecialKeyState = GlobalHotkey.Instance.CheckModifiers()
|
SpecialKeyState = KeyboardHelper.CheckModifiers()
|
||||||
});
|
});
|
||||||
|
|
||||||
if (hideWindow)
|
if (hideWindow)
|
||||||
|
|||||||
@@ -51,7 +51,6 @@
|
|||||||
<PackageReference Include="JetBrains.Annotations" Version="2020.1.0" />
|
<PackageReference Include="JetBrains.Annotations" Version="2020.1.0" />
|
||||||
<PackageReference Include="Mages" Version="1.6.0" />
|
<PackageReference Include="Mages" Version="1.6.0" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||||
<PackageReference Include="NHotkey.Wpf" Version="2.0.1" />
|
|
||||||
<PackageReference Include="NuGet.CommandLine" Version="5.5.1">
|
<PackageReference Include="NuGet.CommandLine" Version="5.5.1">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
@@ -66,6 +65,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\common\interop\interop.vcxproj" />
|
||||||
<ProjectReference Include="..\PowerLauncher.Telemetry\PowerLauncher.Telemetry.csproj" />
|
<ProjectReference Include="..\PowerLauncher.Telemetry\PowerLauncher.Telemetry.csproj" />
|
||||||
<ProjectReference Include="..\Wox.Core\Wox.Core.csproj" />
|
<ProjectReference Include="..\Wox.Core\Wox.Core.csproj" />
|
||||||
<ProjectReference Include="..\Wox.Infrastructure\Wox.Infrastructure.csproj" />
|
<ProjectReference Include="..\Wox.Infrastructure\Wox.Infrastructure.csproj" />
|
||||||
|
|||||||
Reference in New Issue
Block a user