为什么每次击键事件后 Atspi.DeviceEvent 数据都相同?

Why is Atspi.DeviceEvent data the same after every keystroke event?

我真的很难 AT-SPI 在 Vala 应用程序中工作。

我可以注意到通过 Atspi.register_keystroke_listener, but can't for the life of me get it to pass anything useful to the callback function. On each key press it returns exactly the same data regardless of the key pressed, and the stroke.event_string 按下了一个键,里面似乎没有任何东西。

以下是显示问题的精简演示应用程序。

public class Demo.Application : Gtk.Application {
    private static Application? _app = null;

    private Atspi.DeviceListenerCB listener_cb;
    private Atspi.DeviceListener listener;

    public Application () {
        Object (
            application_id: "com.bytepixie.snippetpixie",
            flags: ApplicationFlags.HANDLES_COMMAND_LINE
        );
    }

    protected override void activate () {
        message ("Activated");

        Atspi.init();

        listener_cb = (Atspi.DeviceListenerCB) on_key_released_event;
        listener = new Atspi.DeviceListener ((owned) listener_cb);

        try {
            Atspi.register_keystroke_listener (listener, null, 0, Atspi.EventType.KEY_RELEASED_EVENT, Atspi.KeyListenerSyncType.ALL_WINDOWS | Atspi.KeyListenerSyncType.CANCONSUME);
        } catch (Error e) {
            message ("Could not keystroke listener: %s", e.message);
            Atspi.exit ();
            quit ();
        }
    }

    private bool on_key_released_event (Atspi.DeviceEvent stroke) {
        message ("id: %u, hw_code: %d, modifiers: %d, timestamp: %u, event_string: %s, is_text: %s",
            stroke.id,
            stroke.hw_code,
            stroke.modifiers,
            stroke.timestamp,
            stroke.event_string,
            stroke.is_text.to_string ()
        );

        return false;
    }

    public override int command_line (ApplicationCommandLine command_line) {
        hold ();
        activate ();
        return 0;
    }

    public static new Application get_default () {
        if (_app == null) {
            _app = new Application ();
        }
        return _app;
    }

    public static int main (string[] args) {
        var app = get_default ();
        return app.run (args);
    }
}

编译后运行,然后按下键"qwerty",我得到以下内容。

ian@ians-apollo:~/Documents/atspi-test$ valac demo.vala --pkg gtk+-3.0 --pkg atspi-2
ian@ians-apollo:~/Documents/atspi-test$ ./demo 
** Message: 18:35:59.373: demo.vala:15: Activated

(demo:18257): GLib-GObject-CRITICAL **: 18:35:59.456: g_object_unref: assertion 'G_IS_OBJECT (object)' failed
** Message: 18:36:00.716: demo.vala:32: id: 22029, hw_code: 4, modifiers: 0, timestamp: 0, event_string: (null), is_text: true
q** Message: 18:36:01.046: demo.vala:32: id: 22029, hw_code: 4, modifiers: 0, timestamp: 0, event_string: (null), is_text: true
w** Message: 18:36:01.477: demo.vala:32: id: 22029, hw_code: 4, modifiers: 0, timestamp: 0, event_string: (null), is_text: true
e** Message: 18:36:01.837: demo.vala:32: id: 22029, hw_code: 4, modifiers: 0, timestamp: 0, event_string: (null), is_text: true
r** Message: 18:36:02.187: demo.vala:32: id: 22029, hw_code: 4, modifiers: 0, timestamp: 0, event_string: (null), is_text: true
t** Message: 18:36:02.583: demo.vala:32: id: 22029, hw_code: 4, modifiers: 0, timestamp: 0, event_string: (null), is_text: true
y** Message: 18:36:10.587: demo.vala:32: id: 22029, hw_code: 4, modifiers: 0, timestamp: 0, event_string: (null), is_text: true

你可以在控制台看到每行开头的"qwerty",因为我没有消耗击键,但每次输出的数据没有区别。

我错过了什么?是否存在某种需要在每次事件后清除的缓存?

弄清楚这一点花了一段时间,该演示非常有帮助。本质上,回调的 C 函数签名是错误的。

阅读 AtspiDeviceListenerCB 的 C 文档,函数签名应该是:

gboolean
(*AtspiDeviceListenerCB) (const AtspiDeviceEvent *stroke,
                          void *user_data);

user_datastroke之后。

在示例 Vala 程序中,on_key_released_eventDemo.Application 的一个方法。 Vala 会将实例引用作为生成的 C 中方法的第一个参数。使用 --ccode 开关和 valac 在生成的 C 中显示以下内容:

static gboolean demo_application_on_key_released_event (DemoApplication* self,
                                                 AtspiDeviceEvent* stroke);

解决办法是告诉Vala编译器将实例引用放在不同的位置。在示例程序中,这意味着更改:

private bool on_key_released_event (Atspi.DeviceEvent stroke) {

[CCode (instance_pos = -1)]
private bool on_key_released_event (Atspi.DeviceEvent stroke) {

CCode 属性详细信息 instance_pos 可以是另一个值,但 -1 将实例参数作为函数签名中的最后一个参数。我们本可以使用 2 代替。有关更改生成的 C 函数参数位置的更多信息,请参阅 Vala Writing Bindings Manually document.

另一种解决方案是根本不使用实例数据,而是使用 DeviceListener.simple

如果认为 Vala 编译器有足够的可用信息来计算出用作回调的对象方法应该在生成的 C 中的不同位置具有实例参数,那就太好了。我已经虽然没有花时间调查这种可能性。