I’m trying to get a global hotkey working in Linux using Mono. I found the signatures of XGrabKey and XUngrabKey, but I can’t seem to get them working. Whenever I try to invoke XGrabKey, the application crashes with a SIGSEGV.
This is what I have so far:
using System;
using Gtk;
using System.Runtime.InteropServices;
namespace GTKTest
{
class MainClass
{
const int GrabModeAsync = 1;
public static void Main(string[] args)
{
Application.Init();
MainWindow win = new MainWindow();
win.Show();
// Crashes here
XGrabKey(
win.Display.Handle,
(int)Gdk.Key.A,
(uint)KeyMasks.ShiftMask,
win.Handle,
true,
GrabModeAsync,
GrabModeAsync);
Application.Run();
XUngrabKey(
win.Display.Handle,
(int)Gdk.Key.A,
(uint)KeyMasks.ShiftMask,
win.Handle);
}
[DllImport("libX11")]
internal static extern int XGrabKey(
IntPtr display,
int keycode,
uint modifiers,
IntPtr grab_window,
bool owner_events,
int pointer_mode,
int keyboard_mode);
[DllImport("libX11")]
internal static extern int XUngrabKey(
IntPtr display,
int keycode,
uint modifiers,
IntPtr grab_window);
}
public enum KeyMasks
{
ShiftMask = (1 << 0),
LockMask = (1 << 1),
ControlMask = (1 << 2),
Mod1Mask = (1 << 3),
Mod2Mask = (1 << 4),
Mod3Mask = (1 << 5),
Mod4Mask = (1 << 6),
Mod5Mask = (1 << 7)
}
}
Does anyone have a working example of XGrabKey?
Thanks!
Well, I finally found a working solution in managed code. The SIGSEGV was happening because I was confusing the handles of the unmanaged Gdk objects with the handles of their X11 counterparts. Thanks to Paul’s answer, I was able to find an unmanaged example of global hotkeys and familiarized myself with how it worked. Then I wrote my own unmanaged test program to find out what I needed to do without having to deal with any managed idiosyncrasies. After that was successful, I created a managed solution.
Here is the managed solution:
And here is the test program:
I’m not sure how the
XKeyEventstructure will behave on other systems with different sizes for Cints andlongs, so whether this solution will work on all systems remains to be seen.Edit: It looks like this solution is not going to be architecture-independent as I feared, due to the varying nature of the underlying C type sizes. libgtkhotkey looks promising as way to avoid deploying and compiling custom unmanaged libraries with your managed assemblies.
Note: Now you need to explicity define
BUILD_FOR_32_BIT_X11orBUILD_FOR_64_BIT_X11depending on the word-size of your OS.