【问题标题】:Using python with windows 10 to enable mouse wraparound在 Windows 10 中使用 python 来启用鼠标环绕
【发布时间】:2020-03-11 17:08:31
【问题描述】:

我正在尝试结合使用自动光标定位和 pyWinhook 在多屏桌面设置上实现光标环绕。最终,当我点击屏幕的最右侧或最左侧边缘时,我希望将代码的功能扩展到不同的系统,但是现在我通过尝试使其在单个上起作用而省略了网络位系统。

最初我将这个简单的脚本放在一起,使用 pyautogui 进行包装:

import pyautogui

MAX_X, MAX_Y = pyautogui.size()
MAX_X -= 1
MAX_Y -= 1

def detect_wrap():
        x, y = pyautogui.position()
        if x >= MAX_X:
                pyautogui.moveTo(0,y)
        elif x <= 0:
                pyautogui.moveTo(MAX_X,y)
        elif y >= MAX_Y:
                pyautogui.moveTo(x, 0)
        elif y <= 0:
                pyautogui.moveTo(x, MAX_Y) 
        return

print(pyautogui.size())
while True:
        detect_wrap()

这很好用,但最后会出现烦人的无限循环,所以我尝试寻找一种更干净的方法来处理它,偶然发现了 pyWinhook 和 pythoncom 并编写了一个类似的脚本来尝试实现相同的目标。但是,当我这样做时,不是从最底部跳到顶部,从最右边跳到左边等等。脚本卡在边缘并停留在那里。虽然我不确定为什么。我放入了一些打印语句以试图揭示一些信息,并看到鼠标确实移动到了对面的边界,但有些东西一直让它回到原点。我深入研究 pyautogui 并弄清楚它是如何移动光标的(使用 ctypes.windll.user32.SetCursorPos(xpos, ypos)),所以我将 pyautogui 排除在外。我剩下的看起来像这样(请注意,这是一项正在进行的工作):

import win32api
import pyWinhook as pyHook
import pythoncom
import ctypes
import win32api, win32con
import win32.win32gui as win32gui
import os, sys, time

SCREEN_WIDTH = 0        # This will actually be set later, when we know the size of the attached screen(s)
SCREEN_HEIGHT = 0       # This will actually be set later, when we know the size of the attached screen(s)
XMAX = 0                # This will actually be set later, when we know the size of the attached screen(s)
YMAX = 0                # This will actually be set later, when we know the size of the attached screen(s)
XMIN = 1
YMIN = 1

def setWrapPos(xpos, ypos, border):
        win32gui.ReleaseCapture()
        if border == 'left':
                xpos = SCREEN_WIDTH - 1
        elif border == 'top':
                ypos = SCREEN_HEIGHT - 1
        elif border == 'right':
                xpos = XMIN
        elif border == 'bottom':
                ypos = YMIN
        else:
                print('ERROR: Illegal border passed to setWrapPos()')

        ctypes.windll.user32.SetCursorPos(xpos, ypos)
        time.sleep(0.01)
        return

def onclick(event):
        print('Detected mouseclick at (%d,%d)' % event.Position)
        return True

def trackMouse(event):
        hm.UnhookMouse()
        flags, hcursor, coords = win32gui.GetCursorInfo()
        xpos, ypos = coords
        print("Mouse at (%d, %d)" % (xpos, ypos))
        if (xpos <= XMIN):
                setWrapPos(xpos, ypos, 'left')
        elif (ypos <= YMIN):
                setWrapPos(xpos, ypos, 'top')
        elif (xpos >= XMAX):
                setWrapPos(xpos, ypos, 'right')
        elif (ypos >= YMAX):
                setWrapPos(xpos, ypos, 'bottom')
        flags, hcursor, coords = win32gui.GetCursorInfo()
        xpos, ypos = coords
        print("Mouse moved to (%d, %d)" % (xpos, ypos))
        hm.HookMouse()
        return True

def onWinCombo(event):
        if event.Key == 'X':
                print('Lcontrol-X was detected.  Exiting.')
                hm.UnhookMouse()
                hm.UnhookKeyboard()
                os._exit(0)
        else:
                hm.KeyDown = onKeyboardEvent
        return False

def noMoreCombo(event):
        hm.KeyDown = onKeyboardEvent
        hm.KeyUp = None
        return False

def onKeyboardEvent(event):
        print('Keyboard action detected, ' + str(event.Key) + ' was pressed.')
        if str(event.Key) == 'Lcontrol':
                print('Lcontrol detected.')
                hm.KeyDown = onWinCombo
                hm.KeyUp = noMoreCombo
        return True

curr_right = 0
mons = win32api.EnumDisplayMonitors()
i = 0
while i < win32api.GetSystemMetrics(win32con.SM_CMONITORS):
        minfo = win32api.GetMonitorInfo(mons[i][0])
        if minfo['Monitor'][2] > SCREEN_HEIGHT:
                SCREEN_HEIGHT = minfo['Monitor'][3]
        print("Monitor #" + str(i+1) + ": " + str(minfo['Monitor'][2] - curr_right) + "x" + str(minfo['Monitor'][3]))
        i += 1
        curr_right += minfo['Monitor'][2]
minfo = win32api.GetMonitorInfo(mons[i-1][0])
SCREEN_WIDTH = minfo['Monitor'][2]
XMAX = SCREEN_WIDTH - 1
YMAX = SCREEN_HEIGHT - 1

hm = pyHook.HookManager()
hm.SubscribeMouseAllButtonsDown(onclick)
hm.SubscribeMouseMove(trackMouse)
hm.KeyDown = onKeyboardEvent
hm.HookMouse()
hm.HookKeyboard()
pythoncom.PumpMessages()

代码有效,但无论我尝试了什么,我似乎都无法避免光标弹回边框而不是跳到另一边。我的想法已经用完了,所以想也许这里有人会想到发生了什么。

提前感谢您的任何见解。

【问题讨论】:

    标签: python windows console-application hook mouse


    【解决方案1】:

    更新:我创建了一个名为 wrap.py 的工作鼠标环绕 python 脚本,并将结果放在 GitHub 上的https://github.com/XyzzyBob/wrap。我也是在Win10下用pyinstaller编译的,但是不能上传文件,因为我不能从代码所在的地方传输文件。

    python 脚本需要一堆库,如 github 页面上所述,并且高度仅适用于 Windows。如果我发现需要,我可能会在某个时候为 Linux 和 Mac 重做它,但现在我正在使用它。

    仍在开发用于多系统控制的网络版本,但这是一个更大的程序。这方面的进展可能会显示为 github 页面上的一个分支。

    ========================= xxxxxxxxxxxxxxxxxx ===================== =====

    找到了一种方法来使用不同的库来实现我想要做的事情。鼠标库显然处理低级挂钩,并具有获取和设置鼠标状态项(如位置)的例程。解决方案基本上是这样的:

    import mouse
    ...
    def mouseEvent(event):
            if isinstance(event, mouse._mouse_event.MoveEvent):
                    trackMouse(event)
            elif isinstance(event, mouse._mouse_event.ButtonEvent):
                    onclick(event)
            else:
                    print(event)
            return True
    ...
    def trackMouse(event):
            xpos = event.x
            ypos = event.y
            print("Mouse at (%d, %d)" % (xpos, ypos))
            if (xpos <= XMIN):
                    setWrapPos(xpos, ypos, 'left')
            elif (ypos <= YMIN):
                    setWrapPos(xpos, ypos, 'top')
            elif (xpos >= XMAX):
                    setWrapPos(xpos, ypos, 'right')
            elif (ypos >= YMAX):
                    setWrapPos(xpos, ypos, 'bottom')
            return True
    ...
    def onclick(event):
            print(event.event_type + ' for ' + event.button + ' button at ' + str(mouse.get_position()))
            return True
    
    ### Main ###
    hm = mouse.hook(mouseEvent)
    pythoncom.PumpMessages()
    

    现在只需添加键盘挂钩和其余部分即可使其成为一个连贯的包。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-03-27
      • 1970-01-01
      • 1970-01-01
      • 2020-07-09
      • 1970-01-01
      • 2019-04-08
      • 2021-04-05
      相关资源
      最近更新 更多