为 Gnome 中的按钮启用“Alt”热键?

Ele*_*eno 7 keyboard-shortcuts gnome3

我的意思是:每当按钮文本中的一个字母带有下划线时,按下Alt加上那个字母就会点击按钮。我已经通过KeyboardTweak Tool小程序和小程序但没有成功。

Alt确实会给字母加下划线,但我更愿意事先给它们加下划线。

Gil*_*il' 7

对于 GTK 2,将以下行添加到~/.gtkrc-2.0

gtk-auto-mnemonic = 0
Run Code Online (Sandbox Code Playgroud)

对于 GTK 3 到 GTK 3.9:

do_dconf /org/gnome/desktop/interface/automatic-mnemonics false
Run Code Online (Sandbox Code Playgroud)

在 GTK 3.10 中,该选项已被删除(在此提交中,其日志消息仅说明该功能已被删除)。看源码,没办法开启。仅在Alt按下至少 300 毫秒(超时被硬编码为编译时常量)后才显示助记符的疯狂行为是唯一可能的行为。

我开始通过预加载强制助记符可见的库包装器来覆盖此行为。这并不容易,因为大多数调用都是内部调用。我终于找到了一种方法来让查询告诉标签显示器小部件是否要显示助记符总是返回 true。它主要有效,我可以在 GEdit 和 Evince 的对话框中一直看到助记符,但不完全:缺少一些菜单加速器,我不知道为什么。

编码:

#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <glib.h>
#include <gtk/gtk.h>

#define PROP_MNEMONICS_VISIBLE 31

#ifdef DEBUG
#define DBG(args...) printf(args)
#else
#define DBG(args...)
#endif

static void (*original_gtk_window_get_property)(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
static void wrap_gtk_window_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
{
    original_gtk_window_get_property(object, prop_id, value, pspec);
    if (prop_id == PROP_MNEMONICS_VISIBLE) {
        DBG("%s(%p, %u, &%u, %p)\n", __FUNCTION__, object, prop_id, *(unsigned*)value, pspec);
        g_value_set_boolean(value, TRUE);
    }
}

inline void override_gtk_window_get_property(GType object_type, GObject *obj)
{
    static int first_window_creation = 1;
    if (object_type == GTK_TYPE_WINDOW && first_window_creation) {
        first_window_creation = 0;
        GtkWidgetClass *gtk_widget_class = GTK_WIDGET_GET_CLASS(obj);
        GObjectClass *gobject_class = G_OBJECT_CLASS(gtk_widget_class);
        original_gtk_window_get_property = gobject_class->get_property;
        gobject_class->get_property = wrap_gtk_window_get_property;
    }
}

GObject* g_object_new_valist(GType object_type, const gchar *first_property_name, va_list var_args)
{
    static GObject* (*original_g_object_new_valist)(GType object_type, const gchar *first_property_name, va_list var_args) = NULL;
    if (original_g_object_new_valist == NULL) {
        original_g_object_new_valist = dlsym(RTLD_NEXT, "g_object_new_valist");
    }
    GObject* obj = original_g_object_new_valist(object_type, first_property_name, var_args);
    override_gtk_window_get_property(object_type, obj);
    return obj;
}
gpointer g_object_new(GType object_type, const gchar *first_property_name, ...)
{
    va_list var_args;
    va_start(var_args, first_property_name);
    gpointer obj = g_object_new_valist(object_type, first_property_name, var_args);
    va_end(var_args);
    return obj;
}
gpointer g_object_newv(GType object_type, guint n_parameters, GParameter *parameters)
{
    static gpointer (*original_g_object_newv)(GType object_type, guint n_parameters, GParameter *parameters);
    if (original_g_object_newv == NULL) {
        original_g_object_newv = dlsym(RTLD_NEXT, "g_object_newv");
    }
    GObject* obj = original_g_object_newv(object_type, n_parameters, parameters);
    override_gtk_window_get_property(object_type, obj);
    return obj;
}
Run Code Online (Sandbox Code Playgroud)

如何使用它:将其写入一个名为gtk_window_get_mnemonics_visible.c. 安装 GCC 和 GTK3 开发包(例如sudo apt-get install gcc libgtk-3-dev在 Debian/Ubuntu 上)。编译

gcc -Wall -fPIC -shared `pkg-config --cflags gtk+-3.0` `pkg-config --libs gtk+-3.0` -o gtk_window_get_mnemonics_visible.so gtk_window_get_mnemonics_visible.c
Run Code Online (Sandbox Code Playgroud)

像这样运行 Gnome 应用程序:

LD_PRELOAD=/path/to/gtk_window_get_mnemonics_visible.so gedit
Run Code Online (Sandbox Code Playgroud)

或者把它放在你的.profile

export LD_PRELOAD=/path/to/gtk_window_get_mnemonics_visible.so
Run Code Online (Sandbox Code Playgroud)

请注意,这LD_PRELOAD是一个 hack,它有时可能会导致奇怪的行为。我只是粗略地测试了一下。已知错误:

  • 如果GTK_IM_MODULE设置为xim,则LD_PRELOAD用于任何内容(甚至是空的 C 文件!)会导致 GEdit 在我按下时挂起Alt(在 Debian jessie 上观察到)。我不知道为什么。