如何通过键盘修改GTK3鼠标光标行为?
实现GTK3中通过键盘修改鼠标光标行为
Got it, let's build on your existing hover cursor logic to add keyboard-controlled cursor switching. Here's a complete, practical implementation tailored to your setup:
核心思路
We'll extend your code by:
- Adding a keyboard event listener to the drawing area
- Mapping specific keys to different cursor types
- Keeping your original hover-based cursor switch logic intact (so both methods work together)
完整代码示例
#include <cairo.h> #include <gtk/gtk.h> /* Compile with: gcc example_mouse_cursor.c `pkg-config --cflags gtk+-3.0 --libs gtk+-3.0 cairo` -lm -o example && ./example */ // Your existing drawing data structure struct { int count; double coordx[100]; double coordy[100]; } glob; // Your existing drawing callback (keep your logic here) static void do_drawing(cairo_t *cr) { // Add your custom drawing code here } // Hover-in cursor switch (your original logic) static gboolean enter_notify_event(GtkWidget *widget, GdkEventCrossing *event, gpointer user_data) { GdkCursor *cursor = gdk_cursor_new_from_name(gdk_display_get_default(), "crosshair"); gtk_widget_set_cursor(widget, cursor); g_object_unref(cursor); return TRUE; } // Hover-out cursor switch (your original logic) static gboolean leave_notify_event(GtkWidget *widget, GdkEventCrossing *event, gpointer user_data) { GdkCursor *cursor = gdk_cursor_new_from_name(gdk_display_get_default(), "default"); gtk_widget_set_cursor(widget, cursor); g_object_unref(cursor); return TRUE; } // Keyboard cursor switch callback static gboolean key_press_event(GtkWidget *widget, GdkEventKey *event, gpointer user_data) { GdkCursor *cursor = NULL; // Map keys to cursor types switch (event->keyval) { case GDK_KEY_c: // Press C for crosshair cursor = gdk_cursor_new_from_name(gdk_display_get_default(), "crosshair"); g_print("Switched to crosshair cursor\n"); break; case GDK_KEY_d: // Press D for default arrow cursor = gdk_cursor_new_from_name(gdk_display_get_default(), "default"); g_print("Switched to default cursor\n"); break; case GDK_KEY_m: // Press M for move cursor cursor = gdk_cursor_new_from_name(gdk_display_get_default(), "move"); g_print("Switched to move cursor\n"); break; case GDK_KEY_h: // Press H for help cursor cursor = gdk_cursor_new_from_name(gdk_display_get_default(), "help"); g_print("Switched to help cursor\n"); break; default: // Ignore unhandled keys, let the event propagate return FALSE; } if (cursor) { gtk_widget_set_cursor(widget, cursor); g_object_unref(cursor); // Clean up to avoid memory leaks } return TRUE; // Mark event as handled } static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr, gpointer user_data) { do_drawing(cr); return FALSE; } int main(int argc, char *argv[]) { GtkWidget *window; GtkWidget *darea; gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); darea = gtk_drawing_area_new(); gtk_container_add(GTK_CONTAINER(window), darea); // Connect existing signals g_signal_connect(G_OBJECT(darea), "draw", G_CALLBACK(on_draw_event), NULL); g_signal_connect(G_OBJECT(darea), "enter-notify-event", G_CALLBACK(enter_notify_event), NULL); g_signal_connect(G_OBJECT(darea), "leave-notify-event", G_CALLBACK(leave_notify_event), NULL); // Connect keyboard signal g_signal_connect(G_OBJECT(darea), "key-press-event", G_CALLBACK(key_press_event), NULL); // Critical: Allow drawing area to receive keyboard input gtk_widget_set_can_focus(darea, TRUE); gtk_widget_grab_focus(darea); // Auto-focus on launch so keys work immediately gtk_window_set_title(GTK_WINDOW(window), "Keyboard-Controlled Cursor"); gtk_window_set_default_size(GTK_WINDOW(window), 400, 300); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL); gtk_widget_show_all(window); gtk_main(); return 0; }
关键细节说明
- Keyboard Focus: The drawing area needs
gtk_widget_set_can_focus(darea, TRUE)to receive keyboard events. We callgtk_widget_grab_focus(darea)so you don't have to click the area first to use keys. - Cursor Management: Always use
g_object_unref(cursor)after setting the cursor to avoid memory leaks. GDK supports many standard cursor names (check GDK docs for more options likepointer,text,wait). - Event Propagation: Return
TRUEfor handled keys to stop the event from reaching other widgets, andFALSEfor unhandled keys to let them pass through. - Coexistence: Your original hover logic still works—if you switch to a move cursor via keyboard, hovering out will revert to default, and hovering back will switch to crosshair again.
编译与测试
Use the adjusted compile command (cleaner pkg-config order):
gcc example_mouse_cursor.c `pkg-config --cflags gtk+-3.0 --libs gtk+-3.0 cairo` -lm -o example && ./example
Test it out:
- Hover over the drawing area to switch to crosshair
- Press
C/D/M/Hto switch cursors manually, regardless of mouse position
内容的提问来源于stack exchange,提问作者PintoDoido
相关产品推荐
相关产品推荐

