系统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.}