├── README.md
├── pom.xml
└── src
└── main
└── java
└── org
└── tbworks
└── auto_alipay
├── AlipayEditInputTyper.java
├── MESSAGE.java
├── TestTyper.java
└── User324J.java
/README.md:
--------------------------------------------------------------------------------
1 | # alipay_edit_typer
2 | Just a DEMO to demonstrate how to use JNA to type chars into alipay's password edit control automatically.
3 |
4 | For Chinese document [Click Here](http://blog.csdn.net/tbwood/article/details/44649109)
5 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 | org.tbworks
6 | auto_alipay
7 | 0.0.1-SNAPSHOT
8 | jar
9 |
10 | auto_alipay
11 | http://maven.apache.org
12 |
13 |
14 | UTF-8
15 |
16 |
17 |
18 |
19 | junit
20 | junit
21 | 3.8.1
22 | test
23 |
24 |
25 | net.java.dev.jna
26 | jna
27 | 4.1.0
28 |
29 |
30 | org.seleniumhq.selenium
31 | selenium-java
32 | 2.45.0
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/src/main/java/org/tbworks/auto_alipay/AlipayEditInputTyper.java:
--------------------------------------------------------------------------------
1 | package org.tbworks.auto_alipay;
2 |
3 | import java.util.ArrayList;
4 | import java.util.HashMap;
5 | import java.util.Iterator;
6 | import java.util.List;
7 | import java.util.Map;
8 | import java.util.concurrent.TimeUnit;
9 |
10 | import com.sun.jna.Native;
11 | import com.sun.jna.Pointer;
12 | import com.sun.jna.platform.win32.User32;
13 | import com.sun.jna.platform.win32.WinDef.HWND;
14 | import com.sun.jna.platform.win32.WinUser.WNDENUMPROC;
15 | import com.sun.jna.win32.W32APIOptions;
16 |
17 | /**
18 | * @author tangb Note: className means the class name of window (frame), you can
19 | * get it by spy++
20 | */
21 | public class AlipayEditInputTyper {
22 |
23 | // load the user32.dll
24 | final protected static User324J user32 = (User324J) Native.loadLibrary(
25 | "user32", User324J.class, W32APIOptions.DEFAULT_OPTIONS);
26 |
27 |
28 | /**
29 | * @author tangb
30 | * You can not modify a final variable in the anonymous class, but you can modify its member if the member was not final.
31 | */
32 | private static final class finalHandleContainer
33 | {
34 | private HWND handle;
35 | }
36 |
37 | // -----------------------privates-------------------------------
38 |
39 | /**
40 | * get browser frame's window handle by class name and window title
41 | *
42 | * @param browserClassName
43 | * : browser window's class name, you can get it by spy++
44 | * @param browserTitle
45 | * @return
46 | */
47 | private static HWND getAlipayWindowHandle(String browserClassName,
48 | String browserTitle) {
49 |
50 | HWND deskTopHandle = user32.GetDesktopWindow();
51 |
52 | char[] winClass = new char[100];
53 | user32.GetClassName(deskTopHandle, winClass, 100);
54 |
55 | System.out.println(winClass);
56 |
57 | if( deskTopHandle == null )
58 | throw new RuntimeException("Can not find the desktop's window handle!");
59 |
60 |
61 | return getSpecifiedWindowHandle(deskTopHandle,browserClassName,browserTitle);
62 | }
63 |
64 |
65 | /** search the children windows of the father window specified by father-handle and find the child window with specified className and substring of title
66 | * @param fatherHandle handle of the father window
67 | * @param className className of the child window
68 | * @param title title of the child window
69 | * @return
70 | */
71 | private static HWND getSpecifiedWindowHandle(HWND fatherHandle, final String className,final String title)
72 | {
73 | final finalHandleContainer alipayWindowHandleContainer = new finalHandleContainer();
74 |
75 | boolean result = user32.EnumChildWindows(fatherHandle, new WNDENUMPROC() {
76 | @Override
77 | public boolean callback(HWND hWnd, Pointer data) {
78 | // TODO Auto-generated method stub
79 |
80 | char[] winClass = new char[100];
81 | char[] winText = new char[200];
82 | user32.GetClassName(hWnd, winClass, 100);
83 | user32.GetWindowText(hWnd, winText, 200);
84 |
85 | System.out.println("Class Name:"+Native.toString(winClass)+" Title:"+Native.toString(winText));
86 |
87 | if(user32.IsWindowVisible(hWnd) && Native.toString(winClass).equals(className) && Native.toString(winText).contains(title))
88 | {
89 | alipayWindowHandleContainer.handle = hWnd;
90 | return false;//false means stop
91 | }
92 | return true;
93 | }
94 | }, Pointer.NULL);
95 |
96 | return alipayWindowHandleContainer.handle;
97 | }
98 |
99 |
100 | /** get all children's class-names and handles under specified father windows, and store them in a map.
101 | * @param fatherHandle the handle of father window
102 | * @return a map stores every class name and its window handles, e.g., key="CLASSONE", value="12312"
103 | */
104 | private static Map> getChildWindowClassHandleMap(HWND fatherHandle)
105 | {
106 | final finalHandleContainer alipayWindowHandleContainer = new finalHandleContainer();
107 |
108 | final Map> resultMap = new HashMap>();
109 |
110 | boolean result = user32.EnumChildWindows(fatherHandle, new WNDENUMPROC() {
111 | @Override
112 | public boolean callback(HWND hWnd, Pointer data) {
113 | // TODO Auto-generated method stub
114 |
115 | char[] winClass = new char[100];
116 | user32.GetClassName(hWnd, winClass, 100);
117 | if(user32.IsWindowVisible(hWnd))
118 | {
119 | String tempClassName = Native.toString(winClass);
120 | if(resultMap.containsKey(tempClassName))
121 | {
122 | resultMap.get(tempClassName).add(hWnd);
123 | }
124 | else
125 | {
126 | List tempHWNDList = new ArrayList();
127 | tempHWNDList.add(hWnd);
128 | resultMap.put(tempClassName, tempHWNDList);
129 | }
130 | }
131 | return true;
132 | }
133 | }, Pointer.NULL);
134 |
135 | return resultMap;
136 | }
137 |
138 |
139 | /** In term of alipay password edit control, its class name changes very time. And I come up with one solution: the window class name with only one instance may be the alipay edit, others are not definitely. But times always change, so maybe this is not a permanently valid way! Cautions!
140 | * Get several potential alipay edit window. As sending messages to all the sub windows are not efficient, so it is necessary to shrink the range.
141 | * @param browserWindowHandle
142 | * @return
143 | */
144 | private static List getPotentialAlipayEditHandle(HWND browserWindowHandle) {
145 |
146 | Map> candidates = getChildWindowClassHandleMap(browserWindowHandle);
147 | List resultList = new ArrayList();
148 |
149 | for(Iterator it =candidates.entrySet().iterator();it.hasNext();)
150 | {
151 | Map.Entry> next = (Map.Entry>) it.next();
152 | List tempList = next.getValue();
153 | if(tempList.size()==1)
154 | {
155 | resultList.add(tempList.get(0));
156 | }
157 | }
158 |
159 | return resultList;
160 | }
161 |
162 |
163 | // -----------------------publics--------------------------------
164 | /**
165 | * Set password to all potential alipay password edit controls embedded in the browser page
166 | *
167 | * @param browserClassName
168 | * : browser's class name. e.g., MozillaWindowClass for firefox
169 | * @param browserTitleOrSubTitle
170 | * : browser frame's title, or you can just specified a sub-title
171 | * which can mark the alipay window uniquely. E.g., frame's title
172 | * is "123456-scs**0s90", you can just utilize "234" if it is ok.
173 | * @param className
174 | * : alipay edit frame's class name.
175 | * @param title
176 | * : alipay edit frame's title.
177 | * @param password
178 | * : the password.
179 | * @return
180 | * @throws InterruptedException
181 | */
182 | public static boolean setPassword(String browserClassName,
183 | String browserTitleOrSubTitle,String password) throws InterruptedException {
184 | HWND browserWindowHandle = getAlipayWindowHandle(browserClassName,
185 | browserTitleOrSubTitle);
186 |
187 | System.out.println("------------------------------------------------------------------------------------------------------");
188 |
189 | List list = getPotentialAlipayEditHandle(browserWindowHandle);
190 |
191 |
192 | for (char c : password.toCharArray()) {
193 | TimeUnit.MILLISECONDS.sleep(500);
194 | for(HWND handle:list)
195 | user32.SendMessage(handle, MESSAGE.WM_CHAR.toInt(), (byte) c, 0);
196 | }
197 |
198 |
199 | return true;
200 | }
201 | }
202 |
--------------------------------------------------------------------------------
/src/main/java/org/tbworks/auto_alipay/MESSAGE.java:
--------------------------------------------------------------------------------
1 | package org.tbworks.auto_alipay;
2 |
3 | public enum MESSAGE {
4 |
5 | WM_SETTEXT(0x000C),//输入文本
6 | WM_CHAR(0x0102), //输入字符
7 | BM_CLICK(0xF5),//点击事件,即按下和抬起两个动作
8 | KEYEVENTF_KEYUP(0x0002),//键盘按键抬起
9 | KEYEVENTF_KEYDOWN(0x0); //键盘按键按下
10 |
11 | private MESSAGE(int value)
12 | {
13 | this.value = value;
14 | }
15 |
16 | private int value;
17 |
18 | public String toString()
19 | {
20 | return String.valueOf(value);
21 | }
22 |
23 | public int toInt()
24 | {
25 | return value;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/org/tbworks/auto_alipay/TestTyper.java:
--------------------------------------------------------------------------------
1 | package org.tbworks.auto_alipay;
2 |
3 | public class TestTyper {
4 |
5 |
6 | public static void main(String[] args) throws InterruptedException {
7 |
8 | // firefox
9 | AlipayEditInputTyper.setPassword("MozillaWindowClass", "支付宝", "mypassword");
10 | // chrome
11 | AlipayEditInputTyper.setPassword("Chrome_WidgetWin_1", "支付宝", "mypassword");
12 |
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/org/tbworks/auto_alipay/User324J.java:
--------------------------------------------------------------------------------
1 | package org.tbworks.auto_alipay;
2 |
3 | import com.sun.jna.Pointer;
4 | import com.sun.jna.platform.win32.User32;
5 | import com.sun.jna.platform.win32.WinUser;
6 | import com.sun.jna.platform.win32.WinDef.HWND;
7 | import com.sun.jna.platform.win32.WinUser.WNDENUMPROC;
8 | import com.sun.jna.win32.StdCallLibrary;
9 |
10 | /**Define the exported functions provided by user32.dll
11 | * @author tangb
12 | */
13 | public interface User324J extends StdCallLibrary, WinUser {
14 |
15 | /**
16 | * Retrieves a handle to a window whose class name and window name match the
17 | * specified strings. The function searches child windows, beginning with
18 | * the one following the specified child window. This function does not
19 | * perform a case-sensitive search.
20 | *
21 | * @param lpParent
22 | * : its parent's handle
23 | * @param lpChild
24 | * : handle of the window before it
25 | * @param lpClassName
26 | * : class name
27 | * @param lpWindowName
28 | * : windows name
29 | * @return return the window handle if success, or return null
30 | */
31 | HWND FindWindowEx(HWND lpParent, HWND lpChild, String lpClassName,
32 | String lpWindowName);
33 |
34 | /**
35 | * Retrieves a handle to the desktop window. The desktop window covers the
36 | * entire screen. The desktop window is the area on top of which other
37 | * windows are painted.
38 | *
39 | * @return is a handle to the desktop window.
40 | */
41 | HWND GetDesktopWindow();
42 |
43 | /**
44 | * Use to send text to a edit window
45 | *
46 | * @param hWnd
47 | * : the handle of the destination's window
48 | * @param Msg
49 | * : the message to be sent. more can be found in :
50 | * https://msdn.microsoft
51 | * .com/en-us/library/ms644927(v=vs.85).aspx#quequed_messages
52 | * @param wParam
53 | * : Additional message-specific information. In this context,
54 | * it's the char needed to be sent to the alipay edit.
55 | * @param lParam
56 | * : Additional message-specific information.
57 | * @return The return value specifies the result of the message processing;
58 | * it depends on the message sent.
59 | */
60 | int SendMessage(HWND hWnd, int Msg, int wParam, int lParam);
61 |
62 | /**
63 | * Switches focus to the specified window and brings it to the foreground.
64 | *
65 | * @param hWnd
66 | * : A handle to the window.
67 | * @param fAltTab
68 | * : A TRUE for this parameter indicates that the window is being
69 | * switched to using the Alt/Ctl+Tab key sequence. This parameter
70 | * should be FALSE otherwise.
71 | */
72 | void SwitchToThisWindow(HWND hWnd, boolean fAltTab);
73 |
74 | /**
75 | * The EnumChildWindows function enumerates the child windows that belong to
76 | * the specified parent window by passing the handle to each child window,
77 | * in turn, to an application-defined callback function. EnumChildWindows
78 | * continues until the last child window is enumerated or the callback
79 | * function returns FALSE.
80 | *
81 | * @param hWnd
82 | * Handle to the parent window whose child windows are to be
83 | * enumerated. If this parameter is NULL, this function is
84 | * equivalent to EnumWindows.
85 | * @param lpEnumFunc
86 | * Pointer to an application-defined callback function.
87 | * @param data
88 | * Specifies an application-defined value to be passed to the
89 | * callback function.
90 | * @return If the function succeeds, the return value is nonzero. If the
91 | * function fails, the return value is zero. To get extended error
92 | * information, call GetLastError. If EnumChildProc returns zero,
93 | * the return value is also zero. In this case, the callback
94 | * function should call SetLastError to obtain a meaningful error
95 | * code to be returned to the caller of EnumChildWindows.
96 | */
97 | boolean EnumChildWindows(HWND hWnd, WNDENUMPROC lpEnumFunc, Pointer data);
98 |
99 | /**
100 | * This function retrieves the name of the class to which the specified
101 | * window belongs.
102 | *
103 | * @param hWnd
104 | * Handle to the window and, indirectly, the class to which the
105 | * window belongs.
106 | * @param lpClassName
107 | * Long pointer to the buffer that is to receive the class name
108 | * string.
109 | * @param nMaxCount
110 | * Specifies the length, in characters, of the buffer pointed to
111 | * by the lpClassName parameter. The class name string is
112 | * truncated if it is longer than the buffer.
113 | * @return The number of characters copied to the specified buffer indicates
114 | * success. Zero indicates failure. To get extended error
115 | * information, call GetLastError.
116 | */
117 | int GetClassName(HWND hWnd, char[] lpClassName, int nMaxCount);
118 |
119 | /**
120 | * Determines the visibility state of the specified window.
121 | *
122 | * @param hWnd
123 | * A handle to the window to be tested.
124 | *
125 | * @return If the specified window, its parent window, its parent's parent
126 | * window, and so forth, have the WS_VISIBLE style, the return value
127 | * is nonzero. Otherwise, the return value is zero.
128 | *
129 | * Because the return value specifies whether the window has the
130 | * WS_VISIBLE style, it may be nonzero even if the window is totally
131 | * obscured by other windows.
132 | */
133 | boolean IsWindowVisible(HWND hWnd);
134 |
135 |
136 | /**
137 | * This function copies the text of the specified window's title bar - if it has one - into a buffer. If
138 | * the specified window is a control, the text of the control is copied.
139 | * @param hWnd
140 | * Handle to the window or control containing the text.
141 | * @param lpString
142 | * Long pointer to the buffer that will receive the text.
143 | * @param nMaxCount
144 | * Specifies the maximum number of characters to copy to the buffer, including the NULL character.
145 | * If the text exceeds this limit, it is truncated.
146 | * @return
147 | * The length, in characters, of the copied string, not including the terminating null character,
148 | * indicates success. Zero indicates that the window has no title bar or text, if the title bar is
149 | * empty, or if the window or control handle is invalid. To get extended error information, call
150 | * GetLastError. This function cannot retrieve the text of an edit control in another application.
151 | */
152 | int GetWindowText(HWND hWnd, char[] lpString, int nMaxCount);
153 |
154 |
155 |
156 | }
157 |
--------------------------------------------------------------------------------