如何在 Python 中等待鼠标移动?

159 阅读2分钟

我正在开发一个屏幕录制工具,这个工具旨在帮助软件开发者了解用户是如何最终导致应用程序崩溃的。这个想法是当鼠标开始移动时开始屏幕录制,并在鼠标不动 5 分钟后停止录制。屏幕录制通过 ffmpeg 命令行工具正常工作,唯一剩下的问题(除了应用程序崩溃)是开始和停止屏幕录制。我想知道如何才能做到这一点?理想情况下,它可以使用条件变量,但即使是一个在过去一秒内测试鼠标是否移动的循环也可以。Python 是否支持类似 OnMouseMove() 的方法?

huake_00198_.jpg

2、解决方案

第一种解决方案:

可以使用一个循环和 pywin32 模块来实现。下面是一个示例代码:

import win32api
from time import sleep

count = 0
savedpos = win32api.GetCursorPos()
while(True):
    if count>20*5: # break after 5sec
        break

    curpos = win32api.GetCursorPos()
    if savedpos != curpos:
        savedpos = curpos
        print "moved to " + str(savedpos)

    sleep(0.05)
    count +=1

第二种解决方案:

可以使用 wxPython 模块来实现。wxPython 提供了一组完整的 OnMouse 事件,您可以绑定这些事件。

第三种解决方案:

经过考虑,我认为这种方法更适合处理我的问题。请注意,我已经更新了代码以支持远程桌面断开连接,通过检查 GetCursorPos() 是否引发异常来实现。同样请注意,在关闭远程桌面时,ffmpeg 会输出 [dshow @ ] real-time buffer full! frame dropped! 但对我来说输出文件看起来很好。此脚本已在 Windows server 2012 上进行了测试。

import time, win32api, threading, subprocess, datetime, string, winerror

StopRecordingTimeout = 10

def captureFunction():
    pos = None
    proc = None
    counter = 0
    while True:
        time.sleep(1)
        exceptFlag = False
        try:
            newPos = win32api.GetCursorPos()
            if pos == None:
                pos = newPos
        except Exception as e:
            if e[0] == winerror.ERROR_ACCESS_DENIED:
                exceptFlag = True
        if newPos != pos and proc != None:
            # mouse moved and we are recording already so just make sure the time out counter is zero
            counter = 0
        elif newPos != pos and proc == None:
            # mouse moved and recording didn't start already
            fileName = filter(lambda x : x in string.digits, str(datetime.datetime.now()))
            fileName = 'output' + fileName + '.flv'
            print 'start recording to ' + fileName
            proc = subprocess.Popen('ffmpeg -f dshow -i video=UScreenCapture ' + fileName)
        elif proc != None and (newPos == pos or exceptFlag):
            # mouse didn't moved and recording already started
            if counter < StopRecordingTimeout and not exceptFlag:
                counter = counter + 1
                print 'stop recording in ' + str(StopRecordingTimeout - counter) + ' seconds'
            elif exceptFlag or counter >= StopRecordingTimeout:
                print 'stop recording'
                proc.terminate()
                proc = None
                counter = 0
        pos = newPos

print 'start'
captureThread = threading.Thread(target = captureFunction)
captureThread.start()
captureThread.join()
print 'end'