如何在Windows、Linux和MacOS中从Python获取显示空闲时间?

18 投票
3 回答
5925 浏览
提问于 2025-04-11 09:27

我想知道用户上次按键或移动鼠标已经过去多久了——不仅仅是在我的应用程序里,而是整个“电脑”(也就是显示器)上。这是为了判断他们是否还在电脑前,能看到屏幕上弹出的通知。

我希望能纯粹通过(PY)GTK+来实现这个功能,但如果需要调用特定平台的函数,我也可以接受。理想情况下,我希望能调用那些已经用Python封装好的函数,但如果找不到,我也不介意写一点C语言或ctypes的代码,只要我知道自己在找什么就行。

在Windows上,我觉得我想要的函数是GetLastInputInfo,但好像pywin32并没有封装这个函数;我希望我只是遗漏了什么。

3 个回答

2

我在关于鼠标点击的回答中看到建议使用 pyHook

在Windows中使用Python检测鼠标点击

这里还有一些我用ctypes检测鼠标位置的代码:http://monkut.webfactional.com/blog/archive/2008/10/2/python-win-mouse-position

还有一种更复杂的方法可以实现这个功能,就是通过屏幕截图,然后使用PIL比较图像的变化。

http://www.wellho.net/forum/Programming-in-Python-and-Ruby/Python-Imaging-Library-PIL.html

7

如果你在Linux上使用PyGTK和X11,你可以像下面这样做,这个方法是基于Pidgin的做法:

import ctypes
import ctypes.util
import platform

class XScreenSaverInfo(ctypes.Structure):
    _fields_ = [('window', ctypes.c_long),
                ('state', ctypes.c_int),
                ('kind', ctypes.c_int),
                ('til_or_since', ctypes.c_ulong),
                ('idle', ctypes.c_ulong),
                ('eventMask', ctypes.c_ulong)]

class IdleXScreenSaver(object):
    def __init__(self):
        self.xss = self._get_library('Xss')
        self.gdk = self._get_library('gdk-x11-2.0')

        self.gdk.gdk_display_get_default.restype = ctypes.c_void_p
        # GDK_DISPLAY_XDISPLAY expands to gdk_x11_display_get_xdisplay
        self.gdk.gdk_x11_display_get_xdisplay.restype = ctypes.c_void_p
        self.gdk.gdk_x11_display_get_xdisplay.argtypes = [ctypes.c_void_p]
        # GDK_ROOT_WINDOW expands to gdk_x11_get_default_root_xwindow
        self.gdk.gdk_x11_get_default_root_xwindow.restype = ctypes.c_void_p

        self.xss.XScreenSaverAllocInfo.restype = ctypes.POINTER(XScreenSaverInfo)
        self.xss.XScreenSaverQueryExtension.restype = ctypes.c_int
        self.xss.XScreenSaverQueryExtension.argtypes = [ctypes.c_void_p,
                                                        ctypes.POINTER(ctypes.c_int),
                                                        ctypes.POINTER(ctypes.c_int)]
        self.xss.XScreenSaverQueryInfo.restype = ctypes.c_int
        self.xss.XScreenSaverQueryInfo.argtypes = [ctypes.c_void_p,
                                                   ctypes.c_void_p,
                                                   ctypes.POINTER(XScreenSaverInfo)]

        # gtk_init() must have been called for this to work
        import gtk
        gtk  # pyflakes

        # has_extension = XScreenSaverQueryExtension(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()),
        #                                            &event_base, &error_base);
        event_base = ctypes.c_int()
        error_base = ctypes.c_int()
        gtk_display = self.gdk.gdk_display_get_default()
        self.dpy = self.gdk.gdk_x11_display_get_xdisplay(gtk_display)
        available = self.xss.XScreenSaverQueryExtension(self.dpy,
                                                        ctypes.byref(event_base),
                                                        ctypes.byref(error_base))
        if available == 1:
            self.xss_info = self.xss.XScreenSaverAllocInfo()
        else:
            self.xss_info = None

    def _get_library(self, libname):
        path = ctypes.util.find_library(libname)
        if not path:
            raise ImportError('Could not find library "%s"' % (libname, ))
        lib = ctypes.cdll.LoadLibrary(path)
        assert lib
        return lib

    def get_idle(self):
        if not self.xss_info:
            return 0

        # XScreenSaverQueryInfo(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()),
        #                       GDK_ROOT_WINDOW(), mit_info);
        drawable = self.gdk.gdk_x11_get_default_root_xwindow()
        self.xss.XScreenSaverQueryInfo(self.dpy, drawable, self.xss_info)
        # return (mit_info->idle) / 1000;
        return self.xss_info.contents.idle / 1000

上面的例子通过ctypes使用gdk,这样就能访问X11特有的功能。Xscreensaver的API也需要通过ctypes来访问。

把它转换成使用PyGI和自省(introspection)应该是比较简单的。

12

Gajim 在 Windows、OS X 和 GNU/Linux(以及其他类 Unix 系统)上是这样做的:

  1. 一个 Python 包装模块(里面还有 Windows 空闲时间检测的代码,使用了 GetTickCountctypes);
  2. 一个基于 Ctypes 的模块,用来获取 X11 的空闲时间(使用了 XScreenSaverQueryInfo,在旧版 Gajim 中是 C 模块);
  3. 一个 C 模块,用来获取 OS X 的空闲时间(使用了 HIDIdleTime 系统属性)。

这些链接指向的是比较旧的 0.12 版本,所以你可能想查看一下当前的源代码,以了解可能的进一步改进和变化。

撰写回答