我目前正在为我的应用程序AudioCuesheetEditor进行媒体密钥识别。该应用程序使用mono和gtk#。因此,我制作了用于直接访问linux上XGrabKey的包装器(在Windows上,我使用SetWindowsHookEx)。但是现在没有调用filter函数,我也不知道为什么?!
类(class)代码:
public class HotkeyListener
{
#if BUILD_FOR_WINDOWS
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
public const int VK_MEDIA_PLAY_PAUSE = 0xB3;
public const int VK_MEDIA_NEXT_TRACK = 0xB0;
public const int VK_MEDIA_PREV_TRACK = 0xB1;
public const int VK_MEDIA_STOP = 0xB2;
private LowLevelKeyboardProc _proc;
private static IntPtr _hookID = IntPtr.Zero;
#endif
#if BUILD_FOR_LINUX
private const int KeyPress = 2;
private const int GrabModeAsync = 1;
public const int VK_MEDIA_PLAY_PAUSE = 172;
public const int VK_MEDIA_NEXT_TRACK = 153;
public const int VK_MEDIA_PREV_TRACK = 144;
public const int VK_MEDIA_STOP = 164;
#endif
private static readonly Logfile log = Logfile.getLogfile(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private int keyCode;
public HotkeyListener(int vkCode)
{
#if BUILD_FOR_WINDOWS
_proc = HookCallback;
#endif
this.keyCode = vkCode;
}
public event HotKeyEvent HotkeyPressed;
public void Register()
{
#if BUILD_FOR_WINDOWS
_hookID = SetHook(_proc);
#endif
#if BUILD_FOR_LINUX
Gdk.Window rootWin = Gdk.Global.DefaultRootWindow;
IntPtr xDisplay = GetXDisplay(rootWin);
XGrabKey(xDisplay,this.keyCode,(uint)Gdk.ModifierType.ModifierMask,GetXWindow(rootWin),false,GrabModeAsync,GrabModeAsync);
#endif
}
public void Unregister()
{
#if BUILD_FOR_WINDOWS
UnhookWindowsHookEx(_hookID);
#endif
#if BUILD_FOR_LINUX
Gdk.Window rootWin = Gdk.Global.DefaultRootWindow;
IntPtr xDisplay = GetXDisplay(rootWin);
XUngrabKey(xDisplay,this.keyCode,(uint)Gdk.ModifierType.ModifierMask,GetXWindow(rootWin));
#endif
}
public delegate void HotKeyEvent();
#if BUILD_FOR_WINDOWS
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 IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
log.debug("vk = " + vkCode);
if ((this.HotkeyPressed != null) && (this.keyCode == vkCode))
{
this.HotkeyPressed();
}
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
[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);
#endif
#if BUILD_FOR_LINUX
private Gdk.FilterReturn FilterFunction(IntPtr xEvent, Gdk.Event evnt)
{
XKeyEvent xKeyEvent = (XKeyEvent)Marshal.PtrToStructure(xEvent, typeof(XKeyEvent));
if (xKeyEvent.type == KeyPress)
{
log.debug("vk = " + xKeyEvent.keycode);
if (xKeyEvent.keycode == this.keyCode)
{
this.HotkeyPressed();
}
}
return Gdk.FilterReturn.Continue;
}
private static IntPtr GetXWindow(Gdk.Window window)
{
return gdk_x11_drawable_get_xid(window.Handle);
}
private static IntPtr GetXDisplay(Gdk.Window window)
{
return gdk_x11_drawable_get_xdisplay(gdk_x11_window_get_drawable_impl(window.Handle));
}
[DllImport("libgtk-x11-2.0")]
private static extern IntPtr gdk_x11_drawable_get_xid(IntPtr gdkWindow);
[DllImport("libgtk-x11-2.0")]
private static extern IntPtr gdk_x11_drawable_get_xdisplay(IntPtr gdkDrawable);
[DllImport("libgtk-x11-2.0")]
private static extern IntPtr gdk_x11_window_get_drawable_impl(IntPtr gdkWindow);
[DllImport("libX11")]
private static extern int XGrabKey(IntPtr display, int keycode, uint modifiers, IntPtr grab_window, bool owner_events, int pointer_mode, int keyboard_mode);
[DllImport("libX11")]
private static extern int XUngrabKey(IntPtr display, int keycode, uint modifiers, IntPtr grab_window);
[StructLayout(LayoutKind.Sequential)]
internal struct XKeyEvent
{
public int type;
public ulong serial;
public int send_event;
public IntPtr display;
public ulong window;
public ulong root;
public ulong subwindow;
public ulong time;
public int x, y;
public int x_root, y_root;
public uint state;
public uint keycode;
public int same_screen;
}
#endif
}
我在FilterFunction中创建了一个断点,但是系统没有中断:(。
hotkeylistener的用法:
this.hotkeyMediaPlayListener = new HotkeyListener(HotkeyListener.VK_MEDIA_PLAY_PAUSE);
this.hotkeyMediaPlayListener.HotkeyPressed += delegate {
if (this.objProgram.getObjOption().getBMediakeyboardHotkeyRecognition() == true)
{
if (this.objProgram.getAudioManager().PlayStatus != AudioCuesheetEditor.AudioBackend.PlayState.Playing)
{
this.objProgram.getAudioManager().play();
}
else
{
this.objProgram.getAudioManager().pause();
}
}
};
this.hotkeyMediaPlayListener.Register();
完整的项目代码可以在这里查看:http://sourceforge.net/p/audiocuesheet/code/HEAD/tree/
谢谢大家的帮助。
最佳答案
我自己解决了这个问题,我没有将过滤器函数附加到构造函数的根窗口中。这是所有代码:
public class HotkeyListener
{
#if BUILD_FOR_WINDOWS
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
public const int VK_MEDIA_PLAY_PAUSE = 0xB3;
public const int VK_MEDIA_NEXT_TRACK = 0xB0;
public const int VK_MEDIA_PREV_TRACK = 0xB1;
public const int VK_MEDIA_STOP = 0xB2;
private LowLevelKeyboardProc _proc;
private static IntPtr _hookID = IntPtr.Zero;
#endif
#if BUILD_FOR_LINUX
private const int KeyPress = 2;
private const int GrabModeAsync = 1;
public const int VK_MEDIA_PLAY_PAUSE = 172;
public const int VK_MEDIA_NEXT_TRACK = 153;
public const int VK_MEDIA_PREV_TRACK = 144;
public const int VK_MEDIA_STOP = 164;
#endif
private static readonly Logfile log = Logfile.getLogfile(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private int keyCode;
public HotkeyListener(int vkCode)
{
#if BUILD_FOR_WINDOWS
_proc = HookCallback;
#endif
Gdk.Window rootWin = Gdk.Global.DefaultRootWindow;
this.keyCode = vkCode;
rootWin.AddFilter(new Gdk.FilterFunc(FilterFunction));
}
public event HotKeyEvent HotkeyPressed;
public void Register()
{
#if BUILD_FOR_WINDOWS
_hookID = SetHook(_proc);
#endif
#if BUILD_FOR_LINUX
Gdk.Window rootWin = Gdk.Global.DefaultRootWindow;
IntPtr xDisplay = GetXDisplay(rootWin);
foreach(Gdk.ModifierType mod in Enum.GetValues(typeof(Gdk.ModifierType)))
{
XGrabKey(xDisplay,this.keyCode,(uint)mod,GetXWindow(rootWin),false,GrabModeAsync,GrabModeAsync);
}
#endif
}
public void Unregister()
{
#if BUILD_FOR_WINDOWS
UnhookWindowsHookEx(_hookID);
#endif
#if BUILD_FOR_LINUX
Gdk.Window rootWin = Gdk.Global.DefaultRootWindow;
IntPtr xDisplay = GetXDisplay(rootWin);
foreach(Gdk.ModifierType mod in Enum.GetValues(typeof(Gdk.ModifierType)))
{
XUngrabKey(xDisplay,this.keyCode,(uint)mod,GetXWindow(rootWin));
}
#endif
}
public delegate void HotKeyEvent();
#if BUILD_FOR_WINDOWS
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 IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
log.debug("vk = " + vkCode);
if ((this.HotkeyPressed != null) && (this.keyCode == vkCode))
{
this.HotkeyPressed();
}
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
[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);
#endif
#if BUILD_FOR_LINUX
private Gdk.FilterReturn FilterFunction(IntPtr xEvent, Gdk.Event evnt)
{
XKeyEvent xKeyEvent = (XKeyEvent)Marshal.PtrToStructure(xEvent, typeof(XKeyEvent));
if (xKeyEvent.type == KeyPress)
{
log.debug("vk = " + xKeyEvent.keycode);
if ((this.HotkeyPressed != null) && (this.keyCode == xKeyEvent.keycode))
{
if (this.HotkeyPressed != null)
this.HotkeyPressed();
}
}
return Gdk.FilterReturn.Continue;
}
private static IntPtr GetXWindow(Gdk.Window window)
{
return gdk_x11_drawable_get_xid(window.Handle);
}
private static IntPtr GetXDisplay(Gdk.Window window)
{
return gdk_x11_drawable_get_xdisplay(gdk_x11_window_get_drawable_impl(window.Handle));
}
[DllImport("libgtk-x11-2.0")]
private static extern IntPtr gdk_x11_drawable_get_xid(IntPtr gdkWindow);
[DllImport("libgtk-x11-2.0")]
private static extern IntPtr gdk_x11_drawable_get_xdisplay(IntPtr gdkDrawable);
[DllImport("libgtk-x11-2.0")]
private static extern IntPtr gdk_x11_window_get_drawable_impl(IntPtr gdkWindow);
[DllImport("libX11")]
private static extern int XGrabKey(IntPtr display, int keycode, uint modifiers, IntPtr grab_window, bool owner_events, int pointer_mode, int keyboard_mode);
[DllImport("libX11")]
private static extern int XUngrabKey(IntPtr display, int keycode, uint modifiers, IntPtr grab_window);
[StructLayout(LayoutKind.Sequential)]
internal struct XKeyEvent
{
public int type;
public ulong serial;
public int send_event;
public IntPtr display;
public ulong window;
public ulong root;
public ulong subwindow;
public ulong time;
public int x, y;
public int x_root, y_root;
public uint state;
public uint keycode;
public int same_screen;
}
#endif
}
关于linux - XGrabKey不起作用,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/28852538/