Jackiesteed

www.github.com/jackiesteed

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

拿这篇文章除除草...

问题:写程序模拟人操作电脑,在桌面新建text文件.

求解过程:

大概思路就是鼠标在桌面进行右键点击,通过弹出的PopupMenu来新建text文件,写入数据并保存.

1,首先,要保证鼠标在桌面上,而不是被其他窗口遮挡,这样邮件点击才会弹出正确的菜单,那么如果我们原意的话可以让程序把其他窗口的进程都kill掉,

但还是不要了,因为这没太大意义,也不能展现什么技术点.由我们来保证现在鼠标已经在桌面上,而且不是在某个图标上.

2,让鼠标进行右键点击,弹出Popup菜单.

对于Windows相关对象的操作,基本可以由pywin32中的库来实现.

调用mouse_event可以在某个点出发鼠标点击,即按下右键,然后弹起

但是必须要正确的设置dwFlags,才能将dx,dy当做cursor的绝对位置来使用.

3,在弹出的菜单中单击[新建(&W)]菜单项,然后会弹出一个二级的PopupMenu,点击[文本文档]菜单项.

菜单窗口的类名是"#32768",其他的用数字标识类名的还有"#32769"(桌面窗口), "#32770"(对话框窗口)等.

调用FindWindow就可以获得当前处于焦点的菜单窗口的句柄,

但是通过窗口句柄是不能操作菜单的,我们需要的是一个菜单的句柄,那么首先被考虑的就是GetMenu,

参考msdn中对GetMenu的Remarks我们就会发现GetMenu对于Popup菜单是不起作用的,

一个有效的方法是发送一个要求获取菜单句柄的消息MN_GETHMENU,

获得hmenu之后, 就可以获得第i个菜单项的坐标,剩下的就是点击了.

如果想让程序兼容性更好一点的话,我们会考虑通过菜单项内容中的文字来找到某个菜单项(比如[文本文档]),而不是通过index,

因为随着某些软件(比如git)的安装,桌面的PopupMenu会被修改(会增加一些新项目),原来确定的index就可能变得无效.调用GetMenuItemInfo可以获得菜单项的全部信息,

然后拿相应菜单的text来比对,就可以确定哪一个是需要点击的菜单项.

但这又会引入另一个问题,GetMenuItemInfo的参数中LPMENUITEMINFO要求一个结构体的指针.

在python目前的库中的GetMenuItemInfo实现的也是,而python内建的机制中不支持指针,所以必须通过C的方法来实现.

可以通过ctypes库中的函数来自行实现这个结构体并生成指针,或者是调用一个现成的库win32gui_struct(helpers for working with various win32gui structures).

4,随着3中第二次鼠标点击,桌面出现一个新建的text文件,可以立即编辑文件的名字,keybd_event可以来发送按键消息,编辑完名字之后,回车,现在我们已经让程序自动新建了一个text文件.

5当然我们还可以编辑一下这个文件,刚刚好,文件目前还处于选中状态,回车一下,text文件就会打开,写入我们想要的内容,然后Save一下,关闭文件,就这么简单.

下面是一段不负责任的代码,不保证兼容性,但相信对你会有帮助:

 

  1 # coding = utf-8
2 import win32gui
3 import win32api
4 import os, win32process
5 import win32com.client
6 import win32con
7 import winnt
8 import time
9 import shutil
10 from time import sleep
11 import os
12 import os.path
13 import random
14 import subprocess
15 import win32clipboard
16 import platform
17 import win32gui_struct
18 import struct
19 import array
20
21 ########################################################################################
22 #函数功能:在x,y(屏幕坐标)处点击鼠标,button控制是左键还是邮件
23 #参数:x,y--屏幕坐标,button--鼠标的左键或右键
24 #备注:其中,cx,cy是我的屏幕的长和宽,按(0-65536)的比例在映射一下x,y的虚拟位置
25 ########################################################################################
26 def MouseClick(x, y, button = "LEFT"):
27 SCREENRANGE = 65536
28 cx = 1366
29 cy = 768
30 x = x * SCREENRANGE / cx
31 y = y * SCREENRANGE / cy
32
33 if "RIGHT" == button:
34 win32api.mouse_event(win32con.MOUSEEVENTF_RIGHTDOWN + win32con.MOUSEEVENTF_ABSOLUTE + win32con.MOUSEEVENTF_MOVE, x, y)
35 win32api.mouse_event(win32con.MOUSEEVENTF_RIGHTUP + win32con.MOUSEEVENTF_ABSOLUTE + win32con.MOUSEEVENTF_MOVE, x, y)
36 else:
37 win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN + win32con.MOUSEEVENTF_ABSOLUTE + win32con.MOUSEEVENTF_MOVE, x, y)
38 win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP + win32con.MOUSEEVENTF_ABSOLUTE + win32con.MOUSEEVENTF_MOVE, x, y)
39
40 ########################################################################################
41 #函数功能:模拟鼠标移动到当前处于焦点的Popup菜单的某一项
42 #参数:idx--菜单项的序号
43 #备注:MN_GETHMENU = 0x01E1 这个消息在win32con中没有,自己定义了一下,见msdn
44 #备注2:菜单中有separator,不要漏数
45 ########################################################################################
46 def MouseHoverMenuItem(idx):
47 hwnd = win32gui.FindWindow("#32768", None)
48 MN_GETHMENU = 0x01E1
49 hmenu = win32gui.SendMessage(hwnd, MN_GETHMENU, 0, 0)
50 icount = win32gui.GetMenuItemCount(hmenu)
51 if idx < 0:
52 idx += icount
53 rect = win32gui.GetMenuItemRect(hwnd, hmenu, idx)[1]
54 x = (rect[2] - rect[0]) / 2 + rect[0]
55 y = (rect[3] - rect[1]) / 2 + rect[1]
56 DesktopCommon.MouseTo(x, y)
57
58 ########################################################################################
59 #函数功能:模拟鼠标点击当前处于焦点的Popup菜单的某一项
60 #参数:idx--菜单项的序号,button -- "LEFT", "RIGHT" 点击鼠标的左键或是右键
61 #备注:MN_GETHMENU = 0x01E1 这个消息在win32con中没有,自己定义了一下,见msdn
62 ########################################################################################
63 def ClickOnMenuItem(idx, button = "LEFT"):
64 hwnd = win32gui.FindWindow("#32768", None)
65 MN_GETHMENU = 0x01E1
66 hmenu = win32gui.SendMessage(hwnd, MN_GETHMENU, 0, 0)
67 icount = win32gui.GetMenuItemCount(hmenu)
68 if idx < 0:
69 idx += icount
70 rect = win32gui.GetMenuItemRect(hwnd, hmenu, idx)[1]
71 x = (rect[2] - rect[0]) / 2 + rect[0]
72 y = (rect[3] - rect[1]) / 2 + rect[1]
73
74 MouseClick(x, y, button)
75 ########################################################################################
76 #函数功能:点击菜单中文字内容为text的菜单项
77 #参数:text--要点击的菜单的内容, button -- 点击左键还是右键
78 #返回值:如果成功点击,则返回True,否则False
79 ########################################################################################
80 def ClickOnMenuItemByText(text, button = "LEFT"):
81 hwnd = win32gui.FindWindow("#32768", None)
82 MN_GETHMENU = 0x01E1
83 hmenu = win32gui.SendMessage(hwnd, MN_GETHMENU, 0, 0)
84 icount = win32gui.GetMenuItemCount(hmenu)
85 for i in xrange(icount):
86 t = GetMenuItemString(i).decode("gbk").encode("UTF-8")
87 # print text, t
88 if text == t:
89 rect = rect = win32gui.GetMenuItemRect(hwnd, hmenu, i)[1]
90 x = (rect[2] - rect[0]) / 2 + rect[0]
91 y = (rect[3] - rect[1]) / 2 + rect[1]
92 MouseClick(x, y, button)
93 return True
94
95 return False
96 ########################################################################################
97 #函数功能:通过下标获得某个菜单项的内容文本
98 #参数:idx要操作的菜单项的index
99 #返回值:获得的菜单项的内容的文本
100 ########################################################################################
101 def GetMenuItemString(idx):
102 hwnd = win32gui.FindWindow("#32768", None)
103 MN_GETHMENU = 0x01E1
104 hmenu = win32gui.SendMessage(hwnd, MN_GETHMENU, 0, 0)
105 mii, extra = win32gui_struct.EmptyMENUITEMINFO()
106 win32gui.GetMenuItemInfo(hmenu, idx, True, mii)
107 fType, fState, wID, hSubMenu, hbmpChecked, hbmpUnchecked,\
108 dwItemData, text, hbmpItem = win32gui_struct.UnpackMENUITEMINFO(mii)
109 print text
110 return text
111
112 ########################################################################################
113 #函数功能:获得菜单中的菜单项的个数
114 #函数返回:菜单项的个数
115 ########################################################################################
116 def GetMenuItemCount():
117 hwnd = win32gui.FindWindow("#32768", None)
118 MN_GETHMENU = 0x01E1
119 hmenu = win32gui.SendMessage(hwnd, MN_GETHMENU, 0, 0)
120 icount = win32gui.GetMenuItemCount(hmenu)
121 return icount
122
123 if __name__ == '__main__':
124 #sleep几秒,可以有反应时间
125 sleep(6)
126 hwnd = win32gui.GetDesktopWindow()
127 rect = win32gui.GetWindowRect(hwnd)
128 x = rect[0] + (rect[2] - rect[0]) * 2 / 3
129 y = rect[1] + (rect[3] - rect[1]) * 2 / 3
130 MouseClick(x, y, "RIGHT")
131 sleep(2)
132 ClickOnMenuItemByText("新建(&W)")
133 sleep(2)
134 ClickOnMenuItemByText("文本文档")
135 sleep(2)
136 keymap = {'j': 0x4A, 'a': 0x41, 'c': 0x43, 'k': 0x4B, 'i': 0x49, 'e': 0x45, '\n': win32con.VK_RETURN}
137 for key in 'jackie\n':
138 win32api.keybd_event(keymap[key], 0, 0, 0)
139 win32api.keybd_event(keymap[key], 0, win32con.KEYEVENTF_KEYUP, 0)
140 sleep(1)
141 #end
posted on 2012-03-17 02:38  Jackiesteed  阅读(2138)  评论(2编辑  收藏  举报