使用JNA解决自动化测试无法做密码输入操作的问题
作者:网络转载 发布时间:[ 2013/4/8 10:11:16 ] 推荐标签:
系统API映射好以后,利用这个接口写了如下的工具类,包含点击和输入各种操作。代码如下:
1.import java.util.concurrent.Callable;
2.import java.util.concurrent.ExecutorService;
3.import java.util.concurrent.Executors;
4.import java.util.concurrent.Future;
5.import java.util.concurrent.TimeUnit;
6.
7.import com.sun.jna.Native;
8.import com.sun.jna.Pointer;
9.import com.sun.jna.platform.win32.WinDef.HWND;
10.import com.sun.jna.platform.win32.WinUser.WNDENUMPROC;
11.
12./**
13. * Window组件操作工具类
14. *
15. * @author sunju
16. *
17. */
18.public class Win32Util {
19.
20. private static final int N_MAX_COUNT = 512;
21.
22. private Win32Util() {
23. }
24.
25. /**
26. * 从桌面开始查找指定类名的组件,在超时的时间范围内,如果未找到任何匹配的组件则反复查找
27. * @param className 组件的类名
28. * @param timeout 超时时间
29. * @param unit 超时时间的单位
30. * @return 返回匹配的组件的句柄,如果匹配的组件大于一个,返回第一个查找的到的;如果未找到或超时则返回<code>null</code>
31. */
32. public static HWND findHandleByClassName(String className, long timeout, TimeUnit unit) {
33. return findHandleByClassName(USER32EXT.GetDesktopWindow(), className, timeout, unit);
34. }
35.
36. /**
37. * 从桌面开始查找指定类名的组件
38. * @param className 组件的类名
39. * @return 返回匹配的组件的句柄,如果匹配的组件大于一个,返回第一个查找的到的;如果未找到任何匹配则返回<code>null</code>
40. */
41. public static HWND findHandleByClassName(String className) {
42. return findHandleByClassName(USER32EXT.GetDesktopWindow(), className);
43. }
44.
45. /**
46. * 从指定位置开始查找指定类名的组件
47. * @param root 查找组件的起始位置的组件的句柄,如果为<code>null</code>则从桌面开始查找
48. * @param className 组件的类名
49. * @param timeout 超时时间
50. * @param unit 超时时间的单位
51. * @return 返回匹配的组件的句柄,如果匹配的组件大于一个,返回第一个查找的到的;如果未找到或超时则返回<code>null</code>
52. */
53. public static HWND findHandleByClassName(HWND root, String className, long timeout, TimeUnit unit) {
54. if(null == className || className.length() <= 0) {
55. return null;
56. }
57. long start = System.currentTimeMillis();
58. HWND hwnd = findHandleByClassName(root, className);
59. while(null == hwnd && (System.currentTimeMillis() - start < unit.toMillis(timeout))) {
60. hwnd = findHandleByClassName(root, className);
61. }
62. return hwnd;
63. }
64.
65. /**
66. * 从指定位置开始查找指定类名的组件
67. * @param root 查找组件的起始位置的组件的句柄,如果为<code>null</code>则从桌面开始查找
68. * @param className 组件的类名
69. * @return 返回匹配的组件的句柄,如果匹配的组件大于一个,返回第一个查找的到的;如果未找到任何匹配则返回<code>null</code>
70. */
71. public static HWND findHandleByClassName(HWND root, String className) {
72. if(null == className || className.length() <= 0) {
73. return null;
74. }
75. HWND[] result = new HWND[1];
76. findHandle(result, root, className);
77. return result[0];
78. }
79.
80. private static boolean findHandle(final HWND[] target, HWND root, final String className) {
81. if(null == root) {
82. root = USER32EXT.GetDesktopWindow();
83. }
84. return USER32EXT.EnumChildWindows(root, new WNDENUMPROC() {
85.
86. @Override
87. public boolean callback(HWND hwnd, Pointer pointer) {
88. char[] winClass = new char[N_MAX_COUNT];
89. USER32EXT.GetClassName(hwnd, winClass, N_MAX_COUNT);
90. if(USER32EXT.IsWindowVisible(hwnd) && className.equals(Native.toString(winClass))) {
91. target[0] = hwnd;
92. return false;
93. } else {
94. return target[0] == null || findHandle(target, hwnd, className);
95. }
96. }
97.
98. }, Pointer.NULL);
99. }
100.
101. /**
102. * 模拟键盘按键事件,异步事件。使用win32 keybd_event,每次发送KEYEVENTF_KEYDOWN、KEYEVENTF_KEYUP两个事件。默认10秒超时
103. * @param hwnd 被键盘操作的组件句柄
104. * @param keyCombination 键盘的虚拟按键码(<a href="http://msdn.microsoft.com/ZH-CN/library/windows/desktop/dd375731.aspx">Virtual-Key Code</a>),或者使用{@link java.awt.event.KeyEvent}</br>
105. * 二维数组第一维中的一个元素为一次按键操作,包含组合操作,第二维中的一个元素为一个按键事件,即一个虚拟按键码
106. * @return 键盘按键事件放入windows消息队列成功返回<code>true</code>,键盘按键事件放入windows消息队列失败或超时返回<code>false</code>
107. */
108. public static boolean simulateKeyboardEvent(HWND hwnd, int[][] keyCombination) {
109. if(null == hwnd) {
110. return false;
111. }
112. USER32EXT.SwitchToThisWindow(hwnd, true);
113. USER32EXT.SetFocus(hwnd);
114. for(int[] keys : keyCombination) {
115. for(int i = 0; i < keys.length; i++) {
116. USER32EXT.keybd_event((byte) keys[i], (byte) 0, KEYEVENTF_KEYDOWN, 0); // key down
117. }
118. for(int i = keys.length - 1; i >= 0; i--) {
119. USER32EXT.keybd_event((byte) keys[i], (byte) 0, KEYEVENTF_KEYUP, 0); // key up
120. }
121. }
122. return true;
123. }
124.
125. /**
126. * 模拟字符输入,同步事件。使用win32 SendMessage API发送WM_CHAR事件。默认10秒超时
127. * @param hwnd 被输入字符的组件的句柄
128. * @param content 输入的内容。字符串会被转换成<code>char[]</code>后逐个字符输入
129. * @return 字符输入事件发送成功返回<code>true</code>,字符输入事件发送失败或超时返回<code>false</code>
130. */
131. public static boolean simulateCharInput(final HWND hwnd, final String content) {
132. if(null == hwnd) {
133. return false;
134. }
135. try {
136. return execute(new Callable<Boolean>() {
137.
138. @Override
139. public Boolean call() throws Exception {
140. USER32EXT.SwitchToThisWindow(hwnd, true);
141. USER32EXT.SetFocus(hwnd);
142. for(char c : content.toCharArray()) {
143. Thread.sleep(5);
144. USER32EXT.SendMessage(hwnd, WM_CHAR, (byte) c, 0);
145. }
146. return true;
147. }
148.
149. });
150. } catch(Exception e) {
151. return false;
152. }
153. }
154.
155. public static boolean simulateCharInput(final HWND hwnd, final String content, final long sleepMillisPreCharInput) {
156. if(null == hwnd) {
157. return false;
158. }
159. try {
160. return execute(new Callable<Boolean>() {
161.
162. @Override
163. public Boolean call() throws Exception {
164. USER32EXT.SwitchToThisWindow(hwnd, true);
165. USER32EXT.SetFocus(hwnd);
166. for(char c : content.toCharArray()) {
167. Thread.sleep(sleepMillisPreCharInput);
168. USER32EXT.SendMessage(hwnd, WM_CHAR, (byte) c, 0);
169. }
170. return true;
171. }
172.
173. });
174. } catch(Exception e) {
175. return false;
176. }
177. }
178.
179. /**
180. * 模拟文本输入,同步事件。使用win32 SendMessage API发送WM_SETTEXT事件。默认10秒超时
181. * @param hwnd 被输入文本的组件的句柄
182. * @param content 输入的文本内容
183. * @return 文本输入事件发送成功返回<code>true</code>,文本输入事件发送失败或超时返回<code>false</code>
184. */
185. public static boolean simulateTextInput(final HWND hwnd, final String content) {
186. if(null == hwnd) {
187. return false;
188. }
189. try {
190. return execute(new Callable<Boolean>() {
191.
192. @Override
193. public Boolean call() throws Exception {
194. USER32EXT.SwitchToThisWindow(hwnd, true);
195. USER32EXT.SetFocus(hwnd);
196. USER32EXT.SendMessage(hwnd, WM_SETTEXT, 0, content);
197. return true;
198. }
199.
200. });
201. } catch(Exception e) {
202. return false;
203. }
204. }
205.
206. /**
207. * 模拟鼠标点击,同步事件。使用win32 SendMessage API发送BM_CLICK事件。默认10秒超时
208. * @param hwnd 被点击的组件的句柄
209. * @return 点击事件发送成功返回<code>true</code>,点击事件发送失败或超时返回<code>false</code>
210. */
211. public static boolean simulateClick(final HWND hwnd) {
212. if(null == hwnd) {
213. return false;
214. }
215. try {
216. return execute(new Callable<Boolean>() {
217.
218. @Override
219. public Boolean call() throws Exception {
220. USER32EXT.SwitchToThisWindow(hwnd, true);
221. USER32EXT.SendMessage(hwnd, BM_CLICK, 0, null);
222. return true;
223. }
224.
225. });
226. } catch(Exception e) {
227. return false;
228. }
229. }
230.
231. private static <T> T execute(Callable<T> callable) throws Exception {
232. ExecutorService executor = Executors.newSingleThreadExecutor();
233. try {
234. Future<T> task = executor.submit(callable);
235. return task.get(10, TimeUnit.SECONDS);
236. } finally {
237. executor.shutdown();
238. }
239. }
240.}
相关推荐
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11