【发布时间】:2020-08-17 10:10:45
【问题描述】:
如何在 C# 中为 Electron.NET 应用程序制作全局键盘挂钩?我相信只要它在控制台应用程序中运行,它就应该在 Electron.Net 应用程序中正常运行。
我为这个问题制定了一个“解决方案”,但它往往会占用大量 CPU (7-10%)。如果没有其他选择,也许有人能够以某种方式使其真正有效:
using System;
using System.Runtime.InteropServices;
using System.Threading;
[DllImport("User32.dll")]
public static extern short GetAsyncKeyState(int vKey);
// Other VKey codes: https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
public enum VKeys {
LBUTTON = 0x01, // Left mouse button
RBUTTON = 0x02, // Right mouse button
KEY_0 = 0x30, // 0 key
KEY_1 = 0x31, // 1 key
KEY_2 = 0x32, // 2 key
KEY_3 = 0x33, // 3 key
KEY_4 = 0x34, // 4 key
KEY_5 = 0x35, // 5 key
KEY_6 = 0x36, // 6 key
KEY_7 = 0x37, // 7 key
KEY_8 = 0x38, // 8 key
KEY_9 = 0x39 // 9 key
}
public void Start()
{
Thread HookThread = new Thread(delegate ()
{
var keys = Enum.GetValues(typeof(VKeys));
while (true)
{
foreach (int key in keys)
{
var ks = GetAsyncKeyState(key);
if (ks < 0)
{
Console.WriteLine($"pressed {key}");
//Thread.Sleep(100);
}
//Thread.Sleep(1); // Even sleeping for '1ms' will delay it too much
}
}
});
HookThread.Start();
}
我发现的很多东西只有在我使用 WinForms 或 WPF 时才有效。
编辑:
我尝试了 hanabanashiku 的this 回答,以及我在网上找到的许多其他人,但他们似乎都只是滞后于键盘输入,而且他们的回调函数似乎永远不会被调用。
我决定用 C++ 编写键盘钩子,将其编译为 DLL,然后在我的 C# 代码中引用该 DLL,以希望制作一个能够正常工作且不会导致任何明显输入延迟的键盘钩子,但这并没有也可以工作。
当在 C++ 中作为 .exe 运行时,键盘挂钩完美运行,但是当我将其编译为 DLL 并在 C# 中运行时,它导致了与以前相同的问题 - 大量输入延迟和回调函数似乎没有调用。
如果有人想尝试,这里是代码:
KeyboardHook.cpp
#include "KeyboardHook.h"
#include <iostream>
#define __event void KeyDown(int key), KeyUp(int key);
using namespace Hooks;
void KeyDown(int key)
{
std::cout << "KeyDown\n";
}
void KeyUp(int key)
{
std::cout << "KeyUp\n";
}
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HC_ACTION)
{
PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT)lParam;
switch (wParam)
{
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
KeyDown(p->vkCode);
break;
case WM_KEYUP:
case WM_SYSKEYUP:
KeyUp(p->vkCode);
break;
}
}
// Not processing keys so always return CallNextHookEx
return(CallNextHookEx(NULL, nCode, wParam, lParam));
}
void KeyboardHook::Install() {
// Install keyboard hook
keyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, 0, 0);
std::cout << "Installed\n";
}
void KeyboardHook::Uninstall() {
// Unhook keyboard hook
UnhookWindowsHookEx(keyboardHook);
}
KeyboardHook.h
#include <Windows.h>
HHOOK keyboardHook;
namespace Hooks
{
class KeyboardHook
{
public:
__declspec(dllexport) void Install();
__declspec(dllexport) void Uninstall();
};
}
Program.cs
using System;
using System.Runtime.InteropServices;
namespace HelloMyNameIsSpindiNiceToMeetYou
{
class Program
{
private const string hooksPath = @"C:\Path\To\Hooks.dll";
// If EntryPoint doesn't work, yours might be different
// https://docs.microsoft.com/en-us/dotnet/framework/interop/identifying-functions-in-dlls
//
// "For example, you can use dumpbin /exports Hooks.dll [...] to obtain function names."
// you need to be in the folder with the dll for above to work in Command Prompt for VS
[DllImport(hooksPath, EntryPoint = "?Install@KeyboardHook@Hooks@@QEAAXXZ", CallingConvention = CallingConvention.Cdecl)]
private extern static void Install();
static void Main(string[] args)
{
Install();
// keep console app running
while (true)
{
continue;
}
// or keep it running with this
// Console.ReadKey();
}
}
}
我现在正在一个 electron.net 应用程序之外测试这些东西,只是在一个控制台应用程序中,但仍然无法正常工作。我发现的所有内容都导致使用我无法使用的 winforms。
【问题讨论】:
标签: c# asp.net electron.net