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

时间:2018-11-09 19:05:43

标签: vala

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

我可以注意到已经通过Atspi.register_keystroke_listener按下了一个键,但是我一生都无法将其传递给回调函数任何有用的东西。每次按下该键,它都会返回完全相同的数据,而与按下的键无关,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”,因为我不使用任何按键,但是每次输出的数据没有区别。

我想念什么?每个事件发生后是否需要清除某种缓存?

1 个答案:

答案 0 :(得分:4)

花了一段时间才能弄清楚这一点,该演示非常有帮助。本质上,回调的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语言中将实例参数放在不同的位置。我没有采取是时候研究这种可能性了。