falldog 发表于 2015-4-20 12:18:02

Python and Menu[编程点滴1]

  拿这篇文章除除草...
  问题:写程序模拟人操作电脑,在桌面新建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)
54   x = (rect - rect) / 2 + rect
55   y = (rect - rect) / 2 + rect
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)
71   x = (rect - rect) / 2 + rect
72   y = (rect - rect) / 2 + rect
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)
90             x = (rect - rect) / 2 + rect
91             y = (rect - rect) / 2 + rect
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 + (rect - rect) * 2 / 3
129   y = rect + (rect - rect) * 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, 0, 0, 0)
139         win32api.keybd_event(keymap, 0, win32con.KEYEVENTF_KEYUP, 0)
140         sleep(1)
141         #end
页: [1]
查看完整版本: Python and Menu[编程点滴1]