title: XGrabKey not working
body: <p>I'm currently working on a media key recognition for my application AudioCuesheetEditor. The application uses mono and gtk#. So I made wrapper for direct access to XGrabKey on linux (on windows I use the SetWindowsHookEx). But now the filter function doesn't get called, and I have no idea, why?!</p>
  
  <p>class code:</p>
  
  <pre><code>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 &gt;= 0 &amp;&amp; wParam == (IntPtr)WM_KEYDOWN)
              {
                  int vkCode = Marshal.ReadInt32(lParam);
                  log.debug("vk = " + vkCode);
                  if ((this.HotkeyPressed != null) &amp;&amp; (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
      }
  </code></pre>
  
  <p>I made a breakpoint inside FilterFunction, but the system didn't break :(.</p>
  
  <p>Usage for hotkeylistener:</p>
  
  <pre><code>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();
  </code></pre>
  
  <p>The full project code can be viewed here: <a href="http://sourceforge.net/p/audiocuesheet/code/HEAD/tree/" rel="nofollow">http://sourceforge.net/p/audiocuesheet/code/HEAD/tree/</a></p>
  
  <p>Thanks for everybody helping me.</p>