You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过键盘修改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 call gtk_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 like pointer, text, wait).
  • Event Propagation: Return TRUE for handled keys to stop the event from reaching other widgets, and FALSE for 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/H to switch cursors manually, regardless of mouse position

内容的提问来源于stack exchange,提问作者PintoDoido

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:24:10