我正在使用此处给出的代码的修改版本: https://stackoverflow.com/a/3654821/3179989
如果用户按下 Ctrl + B ,则热键会激活。
如果用户按 Ctrl + B ,它会激活,但继续按住 Ctrl 然后按 B 再次,它确实活跃。
有没有办法让热键的行为更像copy/paste
在Windows中的作用?
例如,按住 Ctrl 并点击 V 将多次粘贴。
编辑:
问题是由于我在推送热键时添加了SendKeys.Send()
。上面的原始代码不包含此问题。现在的问题是如何在不丢失此功能的情况下发送密钥?
答案 0 :(得分:1)
编辑:
回答你的新问题:)
如果您编写自己的全局钩子,则可以指定这些类型的情况。
我相信您遇到的问题是,如果您发送 CTRL + V ,则会发送KeyDown
和KeyUp
对于Control,这使得热键程序假定您不再持有它。
您需要通过在密钥发送期间不更改切换来明确处理此方案。
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (!SENDING_KEYS) //If we're sending keys, ignore everything below
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN) //KeyDown
{
int vkCode = Marshal.ReadInt32(lParam);
string theKey = ((Keys)vkCode).ToString();
Console.Write(theKey);
if (theKey.Contains("ControlKey"))
{
//Our Program still thinks CTRL is down even if we send it using SendKeys
CONTROL_DOWN = true;
}
else if (CONTROL_DOWN && theKey == "B")
{
Console.WriteLine("\n***HOTKEY PRESSED***"); //Our hotkey has been pressed
SENDING_KEYS = true; //Now we will be sending keys
SendKeys.Send("^v"); //Send the keys (CTRL+V) - Paste
SENDING_KEYS = false; //Now we are done sending the keys
return (IntPtr)1; //Block our hotkey from being sent anywhere
}
else if (theKey == "Escape")
{
UnhookWindowsHookEx(_hookID);
Environment.Exit(0);
}
}
else if (nCode >= 0 && wParam == (IntPtr)WM_KEYUP) //KeyUP
{
int vkCode = Marshal.ReadInt32(lParam);
string theKey = ((Keys)vkCode).ToString();
if (theKey.Contains("ControlKey"))
{
//During send keys, this will not be triggered
CONTROL_DOWN = false;
}
}
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
原始答案:
您可以创建自己的Global Keyhook。
以下是使用Windows窗体的示例:
以下是控制台中的示例:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace ConsoleKeyhook
{
class Hooky
{
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private const int WM_KEYUP = 0x0101;
private static LowLevelKeyboardProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
private static bool CONTROL_DOWN = false;
public static void Main()
{
_hookID = SetHook(_proc);
Application.Run();
}
private 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);
}
}
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN) //KeyDown
{
int vkCode = Marshal.ReadInt32(lParam);
string theKey = ((Keys)vkCode).ToString();
Console.Write(theKey);
if (theKey.Contains("ControlKey"))
{
CONTROL_DOWN = true;
}
else if (CONTROL_DOWN && theKey == "B")
{
Console.WriteLine("\n***HOTKEY PRESSED***");
}
else if (theKey == "Escape")
{
UnhookWindowsHookEx(_hookID);
Environment.Exit(0);
}
}
else if (nCode >= 0 && wParam == (IntPtr)WM_KEYUP) //KeyUP
{
int vkCode = Marshal.ReadInt32(lParam);
string theKey = ((Keys)vkCode).ToString();
if (theKey.Contains("ControlKey"))
{
CONTROL_DOWN = false;
}
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
}
}