Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/sql-server-2008/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Mono和Gtk中的全局热键#_C#_Mono_X11_Gtk# - Fatal编程技术网

C# Mono和Gtk中的全局热键#

C# Mono和Gtk中的全局热键#,c#,mono,x11,gtk#,C#,Mono,X11,Gtk#,我正在尝试使用Mono在Linux上运行一个全局热键。我找到了XGrabKey和XUngrabKey的签名,但似乎无法让它们正常工作。每当我试图调用XGrabKey时,应用程序就会因SIGSEGV而崩溃 这就是我到目前为止所做的: using System; using Gtk; using System.Runtime.InteropServices; namespace GTKTest { class MainClass { const int GrabMo

我正在尝试使用Mono在Linux上运行一个全局热键。我找到了
XGrabKey
XUngrabKey
的签名,但似乎无法让它们正常工作。每当我试图调用
XGrabKey
时,应用程序就会因SIGSEGV而崩溃

这就是我到目前为止所做的:

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)
    }
}
使用系统;
使用Gtk;
使用System.Runtime.InteropServices;
名称空间GTKTest
{
类主类
{
const int GrabModeAsync=1;
公共静态void Main(字符串[]args)
{
Application.Init();
MainWindow win=新的MainWindow();
win.Show();
//在这里撞车
XGrabKey(
win.Display.Handle,
(int)Gdk.Key.A,
(uint)键掩码.ShiftMask,
赢,处理,
是的,
GrabModeAsync,
GrabModeAsync);
Application.Run();
迅拉基(
win.Display.Handle,
(int)Gdk.Key.A,
(uint)键掩码.ShiftMask,
赢,处理);
}
[DllImport(“libX11”)]
内部静态外部内部XGrabKey(
IntPtr显示器,
int键码,
uint修饰符,
IntPtr抓取窗口,
bool owner_事件,
int pointer_模式,
int键盘(U模式);
[DllImport(“libX11”)]
内部静态外部int XUngrabKey(
IntPtr显示器,
int键码,
uint修饰符,
IntPtr抓斗(U窗口);
}
公共枚举密钥掩码
{

移位键=(1Tomboy有一些代码知道如何做到这一点,我将从那里获取代码。

我终于在托管代码中找到了一个有效的解决方案。之所以出现SIGSEGV,是因为我混淆了非托管Gdk对象的句柄与X11对象的句柄。多亏了Paul的回答,我找到了一个非托管示例然后,我编写了自己的非托管测试程序,以了解我需要做什么,而不必处理任何托管特性。成功后,我创建了一个托管解决方案

以下是托管解决方案:

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      

}
下面是测试程序:

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!");
}
我不确定
XKeyEvent
结构在其他具有不同大小的C
int
s和
long
s的系统上的行为,因此此解决方案是否适用于所有系统仍有待观察

编辑:由于底层C类型大小的不同性质,此解决方案似乎不会像我担心的那样独立于体系结构。看起来很有希望避免使用托管程序集部署和编译自定义非托管库


注意:现在你需要明确定义
BUILD\u FOR_32\u BIT\u X11
BUILD\u FOR_64\u BIT\u X11
,这取决于你操作系统的字数大小。

我是这个网站的新手,似乎我不能对前面的问题发表评论,因为我没有足够的声誉。(对不起,我甚至不能投票给你!)

关于不同基础大小的问题,我认为这可以通过对long使用IntPtr来解决。这遵循Mono项目文档中的建议,请参阅。C类型int和Bool应该映射到C#int

关于GAPI包装器,我试过了,但没能让它工作。如果扎克能发布他是如何做到的,我将不胜感激


此外,我无法使示例程序正常工作。与SDX2000一样,我必须编辑库名称,并使用语句添加。我在Application.Init()中遇到问题,最后我用它来创建表单。但我的注册调用仍然失败,请求失败。如果有人能够更新代码使其更完整,我将不胜感激。

谢谢!由于Tomboy的解决方案是非托管的,我使用它来熟悉全局热键的工作方式,然后创建了一个托管解决方案您在64位平台上试过了吗?演示程序似乎正在运行(在对库名称进行了一些修改之后)但似乎什么也没做。我已经自由地修改了您的代码,使其在64位系统上工作。@SDX2000:不,我还没有在64位系统上尝试过它。要将类型大小与操作系统相匹配太麻烦了,我的目标是32/64独立程序集,所以我决定在libgtkhotkey上使用托管GAPI包装器。我我有两台ubuntu 14.04电脑,都是64位的。一台电脑工作得很好,另一台电脑的按键事件从未出现。你有什么调试技巧吗?@ZachJohnson:非常感谢你的例子!它最终对我很好。但是对于其他可能使用它的人来说:请注意,NumLock按键也被视为一个修饰符。它花了很长时间我花了一个多小时才弄明白标志Gdk.ModifierType.None意味着NumLock也不能启用。经过测试,它似乎可以工作。特别是在这种情况下,此代码不会在Windows上运行(因为sizeof(uintpttr)==4 idiossincrasy)。