0

I am using gtk-rs and want to be able to detect when any key is pressed.

From some searching online, it seems like the way to do that in C is with gtk_widget_add_events and then g_signal_connect. This answer has a good explanation.

In Rust, I can call Widget::add_events. I also found several definitions for g_signal_connect_*. But, these functions are unsafe, undocumented, and seem to take C types as arguments.

My question is:

  1. In order to use gobject_sys::g_signal_connect_closure, how do I create a GObject and GClosure. In Rust? Can rust structs and closures be converted to that?
  2. Is there a better and more idiomatic way to listen for key events? I have trouble believing that doing such a basic thing would require such an esoteric interface. I have seen some support for specific keyboard shortcuts or keyboard acceleration groups but I haven't been able to find any documentation or examples for just listening for key press events.
QuinnFreedman
  • 2,242
  • 2
  • 25
  • 42
  • 1
    Use [`Widget::connect`](https://gtk-rs.org/docs/gtk/struct.Widget.html#method.connect) – Jmb Mar 09 '21 at 07:30
  • **But, these functions are unsafe** I would like to know, what meas `ùnsafe` to you? – Michi Mar 09 '21 at 14:02

1 Answers1

1

I figured it out.

Thansk @Jmb, Widget::connect was the right way to go. But, that function is undocumented and has some very weird types. Here's how I figured out how to use it:

window
    .connect("key_press_event", false, |values| {
        // "values" is a 2-long slice of glib::value::Value, which wrap G-types
        // You can unwrap them if you know what type they are going to be ahead of time
        // values[0] is the window and values[1] is the event
        let raw_event = &values[1].get::<gdk::Event>().unwrap().unwrap();
        // You have to cast to the correct event type to access some of the fields
        match raw_event.downcast_ref::<gdk::EventKey>() {
            Some(event) => {
                println!("key value: {:?}", std::char::from_u32(event.get_keyval()));
                println!("modifiers: {:?}", event.get_state());
            },
            None => {},
        }

        // You need to return Some() of a glib Value wrapping a bool
        let result = glib::value::Value::from_type(glib::types::Type::Bool);
        // I can't figure out how to actually set the value of result
        // Luckally returning false is good enough for now.
        Some(result)
    })
    .unwrap();
QuinnFreedman
  • 2,242
  • 2
  • 25
  • 42
  • 1
    Two notes: in the newer `gtk-rs` bindings, getters don't have `get_` in front of them anymore. So you'd use `keyval()` instead of `get_keyval()`, etc. Also, to construct a glib Value from something, just do `.to_value()` on that thing. So to return true, you'd do `(true).to_value()`. – Alexis Dumas Feb 12 '22 at 20:32