Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 653127
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 13, 20262026-05-13T22:20:52+00:00 2026-05-13T22:20:52+00:00

I’m trying to get a global hotkey working in Linux using Mono. I found

  • 0

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!

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-13T22:20:52+00:00Added an answer on May 13, 2026 at 10:20 pm

    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:

    public class X11Hotkey
    {
        private const int KeyPress = 2;
        private const int GrabModeAsync = 1;
        private Gdk.Key key;
        private Gdk.ModifierType modifiers;
        private int keycode;
    
        public X11Hotkey(Gdk.Key key, Gdk.ModifierType modifiers)
        {
            this.key = key;
            this.modifiers = modifiers;
    
            Gdk.Window rootWin = Gdk.Global.DefaultRootWindow;
            IntPtr xDisplay = GetXDisplay(rootWin);
            this.keycode = XKeysymToKeycode(xDisplay, (int)this.key);
            rootWin.AddFilter(new Gdk.FilterFunc(FilterFunction));
        }
    
        public event EventHandler Pressed;
    
        public void Register()
        {
            Gdk.Window rootWin = Gdk.Global.DefaultRootWindow;
            IntPtr xDisplay = GetXDisplay(rootWin);
    
            XGrabKey(
                     xDisplay,
                     this.keycode,
                     (uint)this.modifiers,
                     GetXWindow(rootWin),
                     false,
                     GrabModeAsync,
                     GrabModeAsync);     
        }
    
        public void Unregister()
        {
            Gdk.Window rootWin = Gdk.Global.DefaultRootWindow;
            IntPtr xDisplay = GetXDisplay(rootWin);
    
            XUngrabKey(
                     xDisplay,
                     this.keycode,
                     (uint)this.modifiers,
                     GetXWindow(rootWin));
        }
    
        private Gdk.FilterReturn FilterFunction(IntPtr xEvent, Gdk.Event evnt)
        {
            XKeyEvent xKeyEvent = (XKeyEvent)Marshal.PtrToStructure(
                xEvent, 
                typeof(XKeyEvent));
    
            if (xKeyEvent.type == KeyPress)
            {
                if (xKeyEvent.keycode == this.keycode 
                    && xKeyEvent.state == (uint)this.modifiers)
                {
                    this.OnPressed(EventArgs.Empty);
                }
            }
    
            return Gdk.FilterReturn.Continue;
        }
    
        protected virtual void OnPressed(EventArgs e)
        {
            EventHandler handler = this.Pressed;
            if (handler != null)
            {
                handler(this, e);
            }
        }
    
        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 XKeysymToKeycode(IntPtr display, int key);
    
        [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);
    
    #if BUILD_FOR_32_BIT_X11        
    
        [StructLayout(LayoutKind.Sequential)]
        internal struct XKeyEvent
        {
            public short type;
            public uint serial;
            public short send_event;
            public IntPtr display;
            public uint window;
            public uint root;
            public uint subwindow;
            public uint time;
            public int x, y;
            public int x_root, y_root;
            public uint state;
            public uint keycode;
            public short same_screen;
        }       
    #elif BUILD_FOR_64_BIT_X11
    
        [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      
    
    }
    

    And here is the test program:

    public static void Main (string[] args)
    {
        Application.Init();
    
        X11Hotkey hotkey = new X11Hotkey(Gdk.Key.A, Gdk.ModifierType.ControlMask);
        hotkey.Pressed += HotkeyPressed;;
        hotkey.Register();
    
        Application.Run();
    
        hotkey.Unregister();
    }
    
    private static void HotkeyPressed(object sender, EventArgs e)
    {
        Console.WriteLine("Hotkey Pressed!");
    }
    

    I’m not sure how the XKeyEvent structure will behave on other systems with different sizes for C ints and longs, 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_X11 or BUILD_FOR_64_BIT_X11 depending on the word-size of your OS.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Ask A Question

Stats

  • Questions 384k
  • Answers 384k
  • Best Answers 0
  • User 1
  • Popular
  • Answers
  • Editorial Team

    How to approach applying for a job at a company ...

    • 7 Answers
  • Editorial Team

    What is a programmer’s life like?

    • 5 Answers
  • Editorial Team

    How to handle personal stress caused by utterly incompetent and ...

    • 5 Answers
  • Editorial Team
    Editorial Team added an answer While, as @Jeff said, you can't encrypt your HTML output,… May 14, 2026 at 11:03 pm
  • Editorial Team
    Editorial Team added an answer As Joonas said, UNIX timestamps are by definition UTC, but… May 14, 2026 at 11:03 pm
  • Editorial Team
    Editorial Team added an answer To take total control over what columns are rendered in… May 14, 2026 at 11:03 pm

Trending Tags

analytics british company computer developers django employee employer english facebook french google interview javascript language life php programmer programs salary

Top Members

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.