我实际上正在进行后台处理(在新创建的线程中,而不是deamon),它允许在特殊击键时绑定多个动作。
我的特殊按键是:鼠标左键单击,在释放单击之前,按键盘上的某个键,然后在鼠标左键释放后执行一些操作。这部分仅适用于少数软件。
例如,在html输入的Google Chrome上,或者记事本++,如果我点击然后按某个键,按下的lettre / digit就像往常一样显示,在释放时执行动作(SMFL.Window.Keyboard用于检测按下哪个键)
我想阻止此默认行为,在“左键单击”期间记录按下的键,并在记录这些键的情况下继续处理。
我有两个想法:
1 - 使用来自pInvoke
的BlockInput[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern bool BlockInput([In, MarshalAs(UnmanagedType.Bool)] bool fBlockIt);
但此方法始终返回false (零)。这是因为当前正在执行输入吗? (按下鼠标左键) 它可以是一个非常好的解决方案但是:我无法测试它;它会阻止每个键盘事件吗? (如果我无法检索有关按下的键的任何信息,那对我的应用程序来说是无用的)
2 - 创建焦点不可见的窗口
防止特定窗口上的键盘事件的另一种方法可能是打开一个不可见的窗口,将焦点设置在它上面,关闭鼠标按钮释放时的窗口。 按下鼠标按钮时,无法成功将焦点设置在这个新打开的窗口上
一些代码:
while (true) // background process listening
{
if (Mouse.IsButtonPressed(Mouse.Button.Left)) // keyboard/mouse event with SFML
{
_focus = new focusManager(); // Start new thread to create new invisible window
Thread thread = new Thread(new ThreadStart(_focus.preventFocus));
thread.Start();
_focus.forceFocus ();
}
else
{
_focus.giveFocus ();
}
}
带
class focusManager
{
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
[DllImport("user32.dll")]
static extern IntPtr SetFocus(IntPtr hWnd);
[DllImport("kernel32.dll")]
static extern IntPtr GetCurrentProcess();
private IntPtr _focusedApp; // IntPtr id of "paused" app
private IntPtr _currentId; // IntPtr id of current app for invisible window focus
private Form _f; // invisible window
public void preventFocus ()
{
// save IntPtr of current focused window
_focusedApp = GetForegroundWindow();
// debug print
StringBuilder name = new StringBuilder(256);
GetWindowText(_focusedApp, name, 256);
Console.WriteLine("Steal Focus from " + name);
openInvisibleWindow();
}
private void openInvisibleWindow ()
{
// get process ID to be able to set the focus on the invisible window
_currentId = GetCurrentProcess();
// create invisible window form
_f = new Form();
_f.FormBorderStyle = FormBorderStyle.FixedToolWindow;
_f.ShowInTaskbar = false;
_f.StartPosition = FormStartPosition.Manual;
_f.Location = new System.Drawing.Point(100, 100); // visible for testing
_f.Size = new System.Drawing.Size(100, 100);
_f.Focus();
_f.TopMost = true;
Application.Run(_f);
}
// set the focus on the new window
public void forceFocus ()
{
SetForegroundWindow(_currentId);
// debug print
StringBuilder name = new StringBuilder(256);
GetWindowText(_currentId, name, 256);
Console.WriteLine("have Focus on " + name);
}
// set the focus on the "paused" app to launch keystroke action on it
// close the invisible window
public void giveFocus()
{
SetForegroundWindow(_focusedApp);
Application.Exit();
}
}
知道为什么BlockInput总是返回False? 任何想法为什么我不能把注意力放在这个新窗口上? 最后一种情况:阻止特定应用程序上的键盘行为的任何其他想法(chrome,norepad ++ ...,我的击键动作的目标)
非常感谢
答案 0 :(得分:0)
使用键盘钩是找到的最佳工作解决方案。我使用了来自article的Kb Hook,而不是来自代码项目的这个GitHub,它更容易使用,更紧凑。
为了阻止当前窗口上的键处理,回调必须返回1而不是CallNextHookEx
windows API函数的值。
在Github上找到的项目中,回调是:
private IntPtr LowLevelKeyboardProc(int nCode, UIntPtr wParam, IntPtr lParam);
并替换最后一行:
return InterceptKeys.CallNextHookEx(hookId, nCode, wParam, lParam);
通过
return (IntPtr) 1;
小心
CallNextHookEx
方法(此处在InterceptKeys
类中定义)调用键事件的下一个钩子。如果您替换了呼叫,则不再处理对键事件的处理,这可能很危险,因为目标应用程序可能有自己的键盘Hook。