Como posso determinar o tempo de apresentação ociosa de Python no Windows, Linux e MacOS?
Pergunta
Gostaria de saber quanto tempo passou desde o último usuário pressionar uma tecla ou mover o mouse - e não apenas na minha candidatura, mas em toda a "computador" (ie visor), a fim de adivinhar se eles são ainda no computador e capaz de observar notificações que aparecem na tela.
Eu gostaria de fazer isso puramente de (Py) GTK +, mas eu sou passível de chamar funções específicas de plataforma. Idealmente, eu gostaria de chamar funções que já foram embrulhadas de Python, mas se isso não for possível, não estou acima de um pouco de código C ou ctypes
, enquanto eu sei o que estou realmente procurando.
No Windows eu acho que a função que eu quero é GetLastInputInfo
, mas que não parece ser envolvido por pywin32; Espero que eu estou faltando alguma coisa.
Solução
Gajim faz isso dessa maneira no Windows, OS X e GNU / Linux (e outros nixes *) :
- Python invólucro módulo (também inclui código de detecção do Windows tempo ocioso, usando
GetTickCount
comctypes
); - módulo para obter X11 tempo ocioso Ctypes baseada (usando
XScreenSaverQueryInfo
, foi um módulo C em versões antigas Gajim); - C módulo para obter OS X ocioso tempo (usando propriedade do sistema
HIDIdleTime
).
Esses links são bastante datada 0,12 versão, então você pode querer verificar fonte de corrente para possíveis novas melhorias e mudanças.
Outras dicas
Se você usar PyGTK e X11 no Linux, você pode fazer algo como este, que é baseado no que Pidgin faz:
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
O exemplo acima usa GDK via ctypes para ser capaz de acessar o específica X11. Xscreensaver APIs também precisam ser acessado através ctypes.
Deve ser muito fácil para a porta-lo para usar pygi e introspecção.
Eu tenho uma resposta sobre cliques do mouse sugerindo usar pyHook :
Detectando mouse clica em janelas usando python
Eis algum outro código que eu fiz para detectar mouse posição através ctypes: http://monkut.webfactional.com/ blogue / Arquivo / 2008/10/2 / python-win-rato-position
A mais-redonda sobre método para alcançar este objetivo seria através de captura de tela e comparando qualquer mudança em imagens usando PIL.
http: / /www.wellho.net/forum/Programming-in-Python-and-Ruby/Python-Imaging-Library-PIL.html