【问题标题】:Sending events to uinput with python-evdev on keybinding trouble with mask keys使用 python-evdev 向 uinput 发送事件以解决使用掩码键的键绑定问题
【发布时间】:2013-06-05 22:46:37
【问题描述】:

简而言之,我正在尝试向我的程序添加一个键绑定,它将编辑剪贴板,然后将更改粘贴到您处于​​活动状态的任何窗口中。在 Windows 上,我想我可能可以通过消息传递来做到这一点,但 X 不会像那样使用消息传递,所以为了做到这一点,我只是使用 python-evdev 将 ctrl+v 事件发送到 uinput。当您只运行它时,它运行得相当好,但我需要它在键绑定上运行,在这种情况下是 super+v。问题就变成了,当你将 ctrl 和 v 事件发送到 uinput 时,超级掩码仍然处于活动状态,因此它没有将 ctrl+v 发送到窗口,而是发送 ctrl+super+v,这实际上并没有做任何事情。这是解释我在说什么的最少代码:

import evdev,time,keybinder,gtk

def callback():
    with evdev.UInput() as uinput:
        uinput.write(evdev.ecodes.EV_KEY, evdev.ecodes.KEY_LEFTCTRL, 1)
        uinput.write(evdev.ecodes.EV_KEY, evdev.ecodes.KEY_V, 1)
        uinput.write(evdev.ecodes.EV_KEY, evdev.ecodes.KEY_V, 0)
        uinput.write(evdev.ecodes.EV_KEY, evdev.ecodes.KEY_LEFTCTRL, 0)
        uinput.syn()

keybinder.bind("<super>v",callback)
keybinder.bind("Escape",gtk.main_quit)
gtk.main()

如果你发布的速度足够快,你实际上可以让它工作,但它非常快,显然对于实际应用程序来说是不可接受的。我试图发布 super 但这会引发一些问题;它不是很通用,它提出了之后该怎么做的问题(让它释放?再按一次?如果他们在你释放然后再次按下它之间的时间内释放怎么办?),最重要的是,它没有看起来真的很管用。

无论如何,我想问题是,有没有办法解决这个问题?也许一种发送不会与物理键盘结合的按键事件的方法(不太可能)?如果没有,有没有更好的方法让它在 Linux 上通用粘贴?

【问题讨论】:

    标签: python linux input evdev


    【解决方案1】:

    我认为这没有解决方案。正如您已经清楚地理解的那样,Ctrl-V 不是用于启动“粘贴”操作的 IPC 机制,它只是执行此操作的常用键绑定(请注意,如果发生这种情况,您的技巧将不起作用让 emacs 在前台运行,您的小工具只会将窗口向上滚动一页)。而且我认为您是对的,没有标准(例如 freedesktop.org 上的某些内容)要求窗口“立即粘贴”,也不应该有。

    至少正如应用普遍理解和实现的那样,粘贴是用户启动的操作。没有应用程序会期望它由外部工具驱动。您要解决的实际问题是什么?你不能绑定一些东西在你的客户端应用程序中运行,或者挂钩一个可访问性/输入法框架吗?

    也就是说:如果你想让这个特定的 hack 发挥作用,我认为你有正确的方法。在操作开始时查询它们的键盘映射,清除任何修饰键的状态,发送您的事件,然后重置状态。显然,你仍然有一场无法解决的与硬件键盘的比赛,但我怀疑在实践中这不会是一个大问题。

    【讨论】:

    • 不幸的是,“我真正想做的”正是我所说的,我试图非常坦诚。我没有将其用作发送文本或尝试以迂回方式解决问题的聪明方法,我正在获取剪贴板数据并尝试粘贴它。问题是你不一定要每次都使用这个应用程序的粘贴功能,否则我只会填充剪贴板并让用户使用它。至于 emacs 问题,该应用程序是用户可编写脚本的,因此他们可以添加一个键绑定(例如 super+shift+v),以便将其粘贴到通常无法正常工作的地方。谢谢
    • 废话,我一直把最后一条评论读成鸡鸡。我真的想不出更好的表达方式,并且在尝试插入换行符时不小心提交了它,所以我没有时间修复它。只是知道它不是这样的,感谢您的回复。
    【解决方案2】:

    您需要找到一种方法来确定当前是否按下了 &lt;super&gt; 键。
    在 wxpython 中是 Super = wx.GetKeyState(wx.WXK_META),我不知道在 Gtk 中会是什么。
    那么你的代码如下:

    def callback():
       Super = wx.GetKeyState(wx.WXK_META) # Here you require the Gtk equivalent 
       with evdev.UInput() as uinput:
            if Super:
                uinput.write(evdev.ecodes.EV_KEY, evdev.ecodes.KEY_LEFTMETA, 0)
            uinput.write(evdev.ecodes.EV_KEY, evdev.ecodes.KEY_LEFTCTRL, 1)
            uinput.write(evdev.ecodes.EV_KEY, evdev.ecodes.KEY_V, 1)
            uinput.write(evdev.ecodes.EV_KEY, evdev.ecodes.KEY_V, 0)
            uinput.write(evdev.ecodes.EV_KEY, evdev.ecodes.KEY_LEFTCTRL, 0)
            if Super:
                uinput.write(evdev.ecodes.EV_KEY, evdev.ecodes.KEY_LEFTMETA, 1)
            uinput.syn()
    

    如您所见,您几乎可以得到它。
    添加的代码只需在所需的 Ctrl+v 之前关闭 Super 键,然后再重新打开。

    【讨论】:

    • 嗯,这个应用程序到此基本放弃了。我想我试过这个(已经有一段时间了,但问题似乎提到了它)但我遇到了竞争条件的问题。如果用户在粘贴之前持有super,我可以把它放回去,但他们也可以在粘贴之后,但在写完之前释放super。然后你的超级按钮被卡住,直到你再次按下它。如果我不替换它,您不能粘贴多次。我相信我的最终解决方案是让用户从上下文菜单中手动选择填充剪贴板,或者设置一个自动填充的选项。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-29
    • 1970-01-01
    • 1970-01-01
    • 2018-05-04
    • 2018-09-05
    相关资源
    最近更新 更多