c - GTK keypress event propagation either causes recursion or does not work
问题描述
I have a simple GTK program containing a single webkit2 widget in a window and nothing else. I want to be able to filter the keypresses going to the webkit2 widget. At first I added a key mask to the webkit widget and added a callback function, however after propogating the event in the callback function it just calls itself recursively which results in a crash. To resolve this I attached my key mask to the main-window, which is parent to my webkit widget, however this no longer prevents input from getting stopped and sometimes key release events recursively call each other. I was wondering how to achieve my goal? (I've used all different types of propogation mentioned on the GTK+ input event handeling documentation page.)
current key mask:
gtk_widget_add_events(GTK_WIDGET(main_window), GDK_KEY_PRESS_MASK);
g_signal_connect(G_OBJECT(GTK_WIDGET(main_window)), "key_press_event", G_CALLBACK(keypressHandeler), NULL);
g_signal_connect(G_OBJECT(GTK_WIDGET(main_window)), "key_release_event", G_CALLBACK(keypressHandeler), NULL);
current callback function (the return is just to see if the propogation worked at the moment)
gboolean keypressHandeler(GtkWidget *widget, GdkEventKey *event, gpointer data){
if(event->type == GDK_KEY_PRESS)
printf("Key press\n");
if(event->type == GDK_KEY_RELEASE)
printf("Key release\n");
return gtk_widget_event(GTK_WIDGET(webView), event);
}
解决方案
您的代码中的问题是您通过 gtk_widget_event() 手动模拟信号(https://developer.gnome.org/gtk3/stable/GtkWidget.html#gtk-widget-event)
因此,在第一次调用 keypressHandeler 之后,gtk_widget_event 将再次模拟相同的事件,因此它将在无限循环中运行。
如果您在“keypressHandeler”中返回 false 或 true,您的代码将起作用
#include <gtk/gtk.h>
#include <webkit2/webkit2.h>
WebKitWebView *webView;
gboolean keypressHandeler(GtkWidget *widget, GdkEventKey *event, gpointer data)
{
if (event->type == GDK_KEY_PRESS)
printf("Key press from mainwindow\n");
if (event->type == GDK_KEY_RELEASE)
printf("Key release\n");
//for the key use want to propogate
if (dont wanna propogate )
{
return TRUE;
} else {
return FALSE;
}
}
gboolean keypressHandeler2(GtkWidget *widget, GdkEventKey *event, gpointer data)
{
if (event->type == GDK_KEY_PRESS)
printf("Key press from webkit\n");
if (event->type == GDK_KEY_RELEASE)
printf("Key release\n");
// set it as TRUE to stop porpogation.. (for some reason it propogating to mainwindow once)
return TRUE;
}
static void destroyWindowCb(GtkWidget* widget, GtkWidget* window);
static gboolean closeWebViewCb(WebKitWebView* webView, GtkWidget* window);
int main(int argc, char* argv[])
{
// Initialize GTK+
gtk_init(&argc, &argv);
// Create an 800x600 window that will contain the browser instance
GtkWidget *main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size(GTK_WINDOW(main_window), 800, 600);
// Create a browser instance
webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
// Put the browser area into the main window
gtk_container_add(GTK_CONTAINER(main_window), GTK_WIDGET(webView));
// Set up callbacks so that if either the main window or the browser instance is
// closed, the program will exit
gtk_widget_add_events(GTK_WIDGET(main_window), GDK_KEY_PRESS_MASK);
g_signal_connect(G_OBJECT(GTK_WIDGET(main_window)), "key_press_event", G_CALLBACK(keypressHandeler), NULL);
g_signal_connect(G_OBJECT(GTK_WIDGET(webView)), "key_press_event", G_CALLBACK(keypressHandeler2), NULL);
g_signal_connect(G_OBJECT(GTK_WIDGET(main_window)), "key_release_event", G_CALLBACK(keypressHandeler), NULL);
g_signal_connect(G_OBJECT(GTK_WIDGET(webView)), "key_release_event", G_CALLBACK(keypressHandeler2), NULL);
g_signal_connect(main_window, "destroy", G_CALLBACK(destroyWindowCb), NULL);
g_signal_connect(webView, "close", G_CALLBACK(closeWebViewCb), main_window);
// Load a web page into the browser instance
webkit_web_view_load_uri(webView, "http://www.webkitgtk.org/");
// Make sure that when the browser area becomes visible, it will get mouse
// and keyboard events
gtk_widget_grab_focus(GTK_WIDGET(webView));
// Make sure the main window and all its contents are visible
gtk_widget_show_all(main_window);
// Run the main GTK+ event loop
gtk_main();
return 0;
}
static void destroyWindowCb(GtkWidget* widget, GtkWidget* window)
{
gtk_main_quit();
}
static gboolean closeWebViewCb(WebKitWebView* webView, GtkWidget* window)
{
gtk_widget_destroy(window);
return TRUE;
}
如果这是您的尝试.. 发生的事情是,当您设置 GDK_KEY_PRESS_MASK 时,它也会反映在 webkit 上。
所以如果你评论“ g_signal_connect(G_OBJECT(GTK_WIDGET(main_window)), "key_press_event", G_CALLBACK(keypressHandeler), NULL);" 该程序应该可以正常工作
为 mainwindow 处理程序返回 true 将停止传播到 webview,返回 false 将允许传播。
推荐阅读
- amazon-web-services - 为什么没有正确假设我在 aws 上的角色?
- r - 哪个三角函数最合适?
- python - IndexError: Dimension out of range - PyTorch 维度预计在 [-1, 0] 范围内,但得到 1
- ruby-on-rails - 使用 Mongoid 将 active_storage 添加到 Rails6 应用程序?
- python - 如何使用基于json的python创建新表并将数据插入表中
- android - 动态行宽组合
- python - Redis Django - 如何在python(django)中根据特定模式重命名所有缓存键
- c++ - 错误:没有匹配函数调用 'std::vector
::push_back(std::vector &) 常量' - php - 使用供应商商店名称 (Dokan) 在 WooCommerce 中自定义电子邮件主题
- pentaho - 如何使用带标记的表格输入?