C# 无焦点捕捉击键

C# 无焦点捕捉击键,c#,java,keyboard,C#,Java,Keyboard,例如,使用winamp(至少在Windows上),您可以在winamp的背景下全屏玩游戏,并使用媒体按钮*控制声音。Winamp不需要获得焦点,允许游戏全屏继续 我更愿意用Java编写这篇文章,但这可能行不通(在JavaAfaik中捕获无焦点的击键已经很困难了),所以任何C#解决方案都可以 所以基本问题是:如何在没有焦点的情况下捕捉击键 *)我相信“后退/前进/停止/邮件/搜索/收藏夹/网页/主页”按钮被称为媒体按钮,但最好有一个更好的名称:)。低级windows挂钩是一种方法。这里有一个,这里

例如,使用winamp(至少在Windows上),您可以在winamp的背景下全屏玩游戏,并使用媒体按钮*控制声音。Winamp不需要获得焦点,允许游戏全屏继续

我更愿意用Java编写这篇文章,但这可能行不通(在JavaAfaik中捕获无焦点的击键已经很困难了),所以任何C#解决方案都可以

所以基本问题是:如何在没有焦点的情况下捕捉击键


*)我相信“后退/前进/停止/邮件/搜索/收藏夹/网页/主页”按钮被称为媒体按钮,但最好有一个更好的名称:)。

低级windows挂钩是一种方法。这里有一个,这里有更多的信息

这是该代码的局部视图:

    private IntPtr LowLevelKeyboardHook(int nCode, WindowsMessages wParam, [In] KBDLLHOOKSTRUCT lParam)
    {
        bool callNext = true;

        bool isKeyDown = (wParam == WindowsMessages.KEYDOWN || wParam == WindowsMessages.SYSKEYDOWN);
        bool isKeyUp = (wParam == WindowsMessages.KEYUP || wParam == WindowsMessages.SYSKEYUP);

        if ((nCode >= 0) && (isKeyDown || isKeyUp))
        {
            // the virtual key codes and the winforms Keys have the same enumeration
            // so we can freely cast back and forth between them
            Keys key = (Keys)lParam.vkCode;

            // Do your other processing here...
        }

        // if any handler returned false, trap the message
        return (callNext) ? User32.CallNextHookEx(_mainHook, nCode, wParam, lParam) : _nullNext;
    }


    /// <summary>
    /// Registers the user's LowLevelKeyboardProc with the system in order to
    /// intercept any keyboard events before processed in the regular fashion.
    /// This can be used to log all keyboard events or ignore them.
    /// </summary>
    /// <param name="hook">Callback function to call whenever a keyboard event occurs.</param>
    /// <returns>The IntPtr assigned by the Windows's sytem that defines the callback.</returns>
    private IntPtr RegisterLowLevelHook(LowLevelKeyboardProc hook)
    {
        IntPtr handle = IntPtr.Zero;

        using (Process currentProcess = Process.GetCurrentProcess())
        using (ProcessModule currentModule = currentProcess.MainModule)
        {
            IntPtr module = Kernel32.GetModuleHandle(currentModule.ModuleName);
            handle = User32.SetWindowsHookEx(HookType.KEYBOARD_LL, hook, module, 0);
        }

        return handle;
    }

    /// <summary>
    /// Unregisters a previously registered callback from the low-level chain.
    /// </summary>
    /// <param name="hook">IntPtr previously assigned to the low-level chain.
    /// Users should have stored the value given by 
    /// <see cref="Drs.Interop.Win32.LowLevelKeyboard.RegisterLowLevelHook"/>,
    /// and use that value as the parameter into this function.</param>
    /// <returns>True if the hook was removed, false otherwise.</returns>
    private bool UnregisterLowLevelHook(IntPtr hook)
    {
        return User32.UnhookWindowsHookEx(hook);
    }
private IntPtr LowLevelKeyboardHook(intncode,WindowsMessages wParam,[In]KBDLLHOOKSTRUCT lParam)
{
bool callNext=true;
bool isKeyDown=(wParam==WindowsMessages.KEYDOWN | | wParam==WindowsMessages.SYSKEYDOWN);
bool isKeyUp=(wParam==WindowsMessages.KEYUP | | wParam==WindowsMessages.SYSKEYUP);
如果((nCode>=0)和&(isKeyDown | | iskeydup))
{
//虚拟密钥代码和winforms密钥具有相同的枚举
//所以我们可以在他们之间自由地来回转换
Keys key=(Keys)lParam.vkCode;
//在这里进行其他处理。。。
}
//如果任何处理程序返回false,则捕获消息
return(callNext)?User32.CallNextHookEx(_mainHook,nCode,wParam,lParam):_nullNext;
}
/// 
///向系统注册用户的低层KeyboardProc,以便
///在以常规方式处理之前拦截任何键盘事件。
///这可用于记录所有键盘事件或忽略它们。
/// 
///每当键盘事件发生时调用的回调函数。
///由定义回调的Windows系统分配的IntPtr。
私有IntPtr寄存器LowlevelHook(LowLevelKeyboardProc hook)
{
IntPtr handle=IntPtr.Zero;
使用(Process currentProcess=Process.GetCurrentProcess())
使用(ProcessModule currentModule=currentProcess.MainModule)
{
IntPtr module=Kernel32.GetModuleHandle(currentModule.ModuleName);
handle=User32.SetWindowsHookEx(HookType.KEYBOARD\LL,钩子,模块,0);
}
返回手柄;
}
/// 
///从低级链注销以前注册的回调。
/// 
///IntPtr以前分配给低级链。
///用户应该已经存储了
/// ,
///并将该值用作此函数的参数。
///如果钩子被移除,则为True,否则为false。
私有bool未注册lowlevelhook(IntPtr hook)
{
返回User32.unhookwindowshookx(hook);
}
只要实现所需的所有p/Invoke声明,它就可以工作了。
我在应用程序中使用这种方法,效果很好。

在Java中,有两个库可以做到这一点:

  • (窗口)
  • (X11)

这些类型在我的应用程序上无法识别,并且无法编译(WindowsMessages、User32等)。您是如何使其正常工作的?您是否有可能将此代码在线?没有,这些是您需要声明的声明。我没有在线代码,但是你可以使用P/Invoke签名创建简单的存根。下一个变量是什么?我也叫它们媒体按钮或媒体键,不知道更好的名称。