【问题标题】:Simulate mouse-clicking a widget in Python Gtk3+在 Python Gtk3+ 中模拟鼠标单击小部件
【发布时间】:2017-02-22 17:48:34
【问题描述】:

借助Keybinder 库,Python 3 和 Gtk 3.22.5 应用程序响应全局键绑定。目前它调用一个简单的回调:

def keybinder_callback(self, keystr, user_data):
    print("Handling", keystr, user_data)

应用程序的其他地方是一个Gtk.Window,其中包含一个Gtk.MenuBarkeybinder_callback 需要像用户点击鼠标一样激活菜单栏。

(这是一个非常基本的停靠式应用程序,而不是具有典型应用程序窗口的应用程序)

我已尝试向菜单项发送信号:

self.menubar.get_children()[0].emit("activate-item")

没有任何喜悦。我也试过假装按下按钮

from Xlib.ext.xtest import fake_input
fake_input(display,X.ButtonPress,1)

这也没有效果,但无论如何感觉都是错误的方法。我认为发送信号会更合适。

能否像用户点击鼠标一样以编程方式激活小部件?

(它不必是模拟的鼠标点击 - 它只需要以与鼠标点击相同的方式激活和聚焦小部件)


我写了一个example,其中有一个keybinder_callback,如下所示:

def keybinder_callback(self, keystr, user_data):
  print("Handling", keystr, user_data)
  print("Event time:", Keybinder.get_current_event_time())
  activate_the_menu()

我需要向该函数添加一些命令,该命令将 activate_the_menu

我尝试了很多方法,包括捕获真实事件(通过使用xev 进行监控)并模拟它们(ENTER_NOTIFYFOCUS_CHANGE),将它们注入Gdk.main_do_event

我试过打电话给menu.popupmenu.popup_at_widgetmenubar.select_item 和其他很多东西。一切都无济于事。

没有什么想法了,我什至把我的旧 Xlib 书掸掉了……

顺便说一句,虽然这不是一个合适的解决方案,但它可以在 shell 中工作:

$ xdotool mousemove 1605 10 click 1 mousemove restore

但不可靠来自keybinder_callback

run("xdotool mousemove %d 10 click 1 mousemove restore" %
            (self.get_position().root_x+5) , shell=True)

【问题讨论】:

  • 看看GtkMenu.popup_at_widget,但要小心,我在玩的时候差点把我的电脑冻住了。不太清楚发生了什么,但弹出菜单后我无法再关闭程序。
  • 好吧,我尝试了self.menu.popup_at_widget(self,Gdk.Gravity.STATIC,Gdk.Gravity.STATIC,None),但得到了Warning: g_object_set_data: assertion 'G_IS_OBJECT (object)' failed

标签: python gtk3


【解决方案1】:

尝试了很多东西后,我发现这行得通。

import Xlib
from Xlib import X
from Xlib.display import Display
from Xlib.ext.xtest import fake_input
import time

def keybinder_callback(self, keystr, user_data):
    time.sleep(0.2)
    x = self.get_position().root_x+5
    display = Display()
    mpos = display.screen().root.query_pointer()._data
    display.screen().root.warp_pointer(x,5)
    display.sync()
    fake_input(display,X.ButtonPress,1, X.CurrentTime, X.NONE, x, 5)
    display.sync()
    fake_input(display,X.ButtonRelease,1)
    display.screen().root.warp_pointer(mpos['root_x'],
                                       mpos['root_y'])
    display.sync()

我发现时间延迟对于避免这个错误是必要的:

Gdk-CRITICAL **: Window 0x1e7c660 has not been made visible in GdkSeatGrabPrepareFunc

【讨论】:

    猜你喜欢
    • 2011-04-02
    • 2010-12-16
    • 2014-01-03
    • 2011-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多