def postClick(hwnd, x, y, flag=MouseFlag.LeftButton, clicktype=MouseClickType.SingleClick): """在目标窗口通过PostMessage的方式产生鼠标点击的动作 :param hwnd: 目标窗口句柄 :type hwnd: 整数 :param x: 屏幕x坐标 :type x: 整数 :param y: 屏幕y坐标 :type y: 整数 :param flag: 鼠标键类型 :type flag: 枚举类型, MouseFlag.LeftButton|MouseFlag.MiddleButton|MouseFlag.RightButton :param clicktype: 鼠标键点击方式 :type clicktype: 枚举类型, MouseClickType.SingleClick | MouseClickType.DoubleClick """ sleep_time = (win32gui.GetDoubleClickTime() / 1000.0 + 0.05) - (time.time() - Mouse._last_click_time) if sleep_time > 0: time.sleep(sleep_time) keystate = 0 if win32api.GetAsyncKeyState(win32con.VK_CONTROL) & 0x8000 != 0: keystate = keystate | win32con.MK_CONTROL if win32api.GetAsyncKeyState(win32con.VK_SHIFT) & 0x8000 != 0: keystate = keystate | win32con.MK_SHIFT win32api.SetCursorPos((x, y)) c_x, c_y = win32gui.ScreenToClient(hwnd, (x, y)) if clicktype == MouseClickType.SingleClick: try: win32gui.PostMessage(hwnd, win32con.WM_NULL, 0, 0) win32gui.PostMessage(hwnd, _mouse_msg_param[flag][0], _mouse_msg_param[flag][2] | keystate, (c_y << 16) | c_x) win32gui.PostMessage(hwnd, _mouse_msg_param[flag][1], 0 | keystate, (c_y << 16) | (c_x)) except win32gui.error as e: if e.winerror == winerror.ERROR_INVALID_WINDOW_HANDLE: #无效窗口句柄,有些窗口post第一个消息后就会消失 pass else: raise e else: win32gui.PostMessage(hwnd, _mouse_msg_param[flag][0], _mouse_msg_param[flag][2] | keystate, (c_y << 16) | c_x) win32gui.PostMessage(hwnd, _mouse_msg_param[flag][1], 0 | keystate, (c_y << 16) | (c_x)) time.sleep(0.1) win32gui.PostMessage(hwnd, _mouse_msg_param[flag][3], _mouse_msg_param[flag][2] | keystate, (c_y << 16) | c_x) win32gui.PostMessage(hwnd, _mouse_msg_param[flag][1], 0 | keystate, (c_y << 16) | (c_x)) Mouse._last_click_time = time.time()
def notify(self, hwnd, msg, wparam, lparam): # Double click is actually 1 single click followed # by a double-click event, no way to differentiate # So we need a timed callback to cancel if lparam == win32con.WM_LBUTTONDBLCLK: self.execute_menu_option(self.default_menu_index + self.FIRST_ID) self.stop_click_timer() elif lparam == win32con.WM_RBUTTONUP: self.show_menu() elif lparam == win32con.WM_LBUTTONDOWN: # Wrapper of win32api, timeout is in ms # We need to wait at least untill what user has defined as double click self.stop_click_timer() self.click_timer = timer.set_timer(win32gui.GetDoubleClickTime() * 2, self.click) return True
def _perform_click_input( button="left", coords=(None, None), double=False, button_down=True, button_up=True, wheel_dist=0, pressed="", key_down=True, key_up=True, ): """Perform a click action using SendInput All the *click_input() and *mouse_input() methods use this function. Thanks to a bug report from Tomas Walch (twalch) on sourceforge and code seen at http://msdn.microsoft.com/en-us/magazine/cc164126.aspx this function now always works the same way whether the mouse buttons are swapped or not. For example if you send a right click to Notepad.Edit - it will always bring up a popup menu rather than 'clicking' it. """ # Handle if the mouse buttons are swapped if win32functions.GetSystemMetrics(win32defines.SM_SWAPBUTTON): if button.lower() == 'left': button = 'right' elif button.lower() == 'right': button = 'left' events = [] if button.lower() == 'left': events.append(win32defines.MOUSEEVENTF_MOVE) if button_down: events.append(win32defines.MOUSEEVENTF_LEFTDOWN) if button_up: events.append(win32defines.MOUSEEVENTF_LEFTUP) elif button.lower() == 'right': if button_down: events.append(win32defines.MOUSEEVENTF_RIGHTDOWN) if button_up: events.append(win32defines.MOUSEEVENTF_RIGHTUP) elif button.lower() == 'middle': if button_down: events.append(win32defines.MOUSEEVENTF_MIDDLEDOWN) if button_up: events.append(win32defines.MOUSEEVENTF_MIDDLEUP) elif button.lower() == 'move': events.append(win32defines.MOUSEEVENTF_MOVE) events.append(win32defines.MOUSEEVENTF_ABSOLUTE) elif button.lower() == 'x': if button_down: events.append(win32defines.MOUSEEVENTF_XDOWN) if button_up: events.append(win32defines.MOUSEEVENTF_XUP) if button.lower() == 'wheel': events.append(win32defines.MOUSEEVENTF_WHEEL) # if we were asked to double click (and we are doing a full click # not just up or down. if double and button_down and button_up: events *= 2 if button_down and (button.lower() not in ['move', 'wheel']): # wait while previous click is not affecting our current click while 0 < win32api.GetTickCount() - win32api.GetLastInputInfo( ) < win32gui.GetDoubleClickTime(): time.sleep(Timings.after_clickinput_wait) # set the cursor position win32api.SetCursorPos((coords[0], coords[1])) time.sleep(Timings.after_setcursorpos_wait) if win32api.GetCursorPos() != (coords[0], coords[1]): win32api.SetCursorPos((coords[0], coords[1])) time.sleep(Timings.after_setcursorpos_wait) keyboard_keys = pressed.lower().split() if ('control' in keyboard_keys) and key_down: SendKeys.VirtualKeyAction(SendKeys.VK_CONTROL, up=False).Run() if ('shift' in keyboard_keys) and key_down: SendKeys.VirtualKeyAction(SendKeys.VK_SHIFT, up=False).Run() if ('alt' in keyboard_keys) and key_down: SendKeys.VirtualKeyAction(SendKeys.VK_MENU, up=False).Run() dw_flags = 0 for event in events: dw_flags |= event dw_data = 0 if button.lower() == 'wheel': wheel_dist = wheel_dist * 120 dw_data = wheel_dist if button.lower() == 'move': x_res = win32functions.GetSystemMetrics(win32defines.SM_CXSCREEN) y_res = win32functions.GetSystemMetrics(win32defines.SM_CYSCREEN) x_coord = int(float(coords[0]) * (65535. / float(x_res - 1))) y_coord = int(float(coords[1]) * (65535. / float(y_res - 1))) win32api.mouse_event(dw_flags, x_coord, y_coord, dw_data) else: for event in events: if event == win32defines.MOUSEEVENTF_MOVE: x_res = win32functions.GetSystemMetrics( win32defines.SM_CXSCREEN) y_res = win32functions.GetSystemMetrics( win32defines.SM_CYSCREEN) x_coord = int( float(coords[0]) * (65535. / float(x_res - 1))) y_coord = int( float(coords[1]) * (65535. / float(y_res - 1))) win32api.mouse_event( win32defines.MOUSEEVENTF_MOVE | win32defines.MOUSEEVENTF_ABSOLUTE, x_coord, y_coord, dw_data) else: win32api.mouse_event( event | win32defines.MOUSEEVENTF_ABSOLUTE, coords[0], coords[1], dw_data) time.sleep(Timings.after_clickinput_wait) if ('control' in keyboard_keys) and key_up: SendKeys.VirtualKeyAction(SendKeys.VK_CONTROL, down=False).Run() if ('shift' in keyboard_keys) and key_up: SendKeys.VirtualKeyAction(SendKeys.VK_SHIFT, down=False).Run() if ('alt' in keyboard_keys) and key_up: SendKeys.VirtualKeyAction(SendKeys.VK_MENU, down=False).Run()
def get_double_click_time(): try: return win32gui.GetDoubleClickTime() except Exception as e: log.warn("failed to get double click time: %s", e) return 0
def mouse_single_click(): """单击鼠标""" win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0) win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, 0, 0, 0, 0) time.sleep(win32gui.GetDoubleClickTime() / 1000 / 4)
0x2e: 'delete', 0x24: 'home', 0x23: 'end', 0x21: 'page_up', 0x22: 'page_down', 0x25: 'left_arrow', 0x27: 'right_arrow', 0x26: 'up_arrow', 0x28: 'down_arrow', } win_button_flags = wc.MK_LBUTTON | wc.MK_MBUTTON | wc.MK_RBUTTON win_prev_key_state = 1 << 30 win_last_mouse_down = None win_dbl_time = gui.GetDoubleClickTime() / 1000.0 # 0.25 win_dbl_xdist = api.GetSystemMetrics(wc.SM_CXDOUBLECLK) win_dbl_ydist = api.GetSystemMetrics(wc.SM_CYDOUBLECLK) def win_message_to_event(message, target=None): hwnd, msg, wParam, lParam, milliseconds, gpos = message kind, button = win_message_map[msg] time = milliseconds / 1000.0 if kind == 'mouse_move' and wParam & win_button_flags <> 0: kind = 'mouse_drag' if target: lpos = target.global_to_local(gpos) else: lpos = gpos event = Event()