SWT Display.post(Event) 可將事件直接發送至 UI 執行緒事件佇列,繞過作業系統輸入子系統,實現程式化模擬使用者輸入。事件屬性決定模擬行為:type(KeyDown/KeyUp/MouseMove/MouseDown/MouseUp)、keyCode、character、x/y、button 等。
public class KeyboardSimulator {
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
Text text = new Text(shell, SWT.BORDER);
text.setSize(text.computeSize(150, SWT.DEFAULT));
shell.pack();
shell.open();
new Thread(() -> {
String input = "Love the method.";
for (int i = 0; i < input.length(); i++) {
char ch = input.charAt(i);
boolean shift = Character.isUpperCase(ch);
ch = Character.toLowerCase(ch);
if (shift) postKey(display, SWT.KeyDown, SWT.SHIFT, 0);
postKey(display, SWT.KeyDown, 0, ch);
sleep(10);
postKey(display, SWT.KeyUp, 0, ch);
sleep(100);
if (shift) postKey(display, SWT.KeyUp, SWT.SHIFT, 0);
}
}).start();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) display.sleep();
}
display.dispose();
}
static void postKey(Display display, int type, int keyCode, char character) {
Event e = new Event();
e.type = type;
e.keyCode = keyCode;
e.character = character;
display.post(e);
}
static void sleep(int ms) { try { Thread.sleep(ms); } catch (InterruptedException ignored) {} }
}
關鍵細節:大寫字元需模擬 Shift 按下 → 字元按下/釋放 → Shift 釋放;字元間加入延遲模擬真人打字節奏。
public class MouseSimulator {
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
Button button = new Button(shell, SWT.NONE);
button.setSize(100, 100);
button.setText("Click");
shell.pack();
shell.open();
button.addListener(SWT.MouseDown, e ->
System.out.printf("Mouse Down: button=%d x=%d y=%d%n", e.button, e.x, e.y));
// 取得 Shell 相對座標 (50,50) 對應的螢幕絕對座標
Point pt = display.map(shell, null, 50, 50);
new Thread(() -> {
sleep(300);
postMouse(display, SWT.MouseMove, pt.x, pt.y, 0);
sleep(300);
postMouse(display, SWT.MouseDown, pt.x, pt.y, 1); // button=1 左鍵
sleep(300);
postMouse(display, SWT.MouseUp, pt.x, pt.y, 1);
}).start();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) display.sleep();
}
display.dispose();
}
static void postMouse(Display display, int type, int x, int y, int button) {
Event e = new Event();
e.type = type;
e.x = x; e.y = y; e.button = button;
display.post(e);
}
static void sleep(int ms) { try { Thread.sleep(ms); } catch (InterruptedException ignored) {} }
}
座標轉換關鍵:display.map(control, null, x, y) 將控件相對座標轉為螢幕絕對座標,確保滑鼠事件在正確位置觸發。
| 場景 | 實現要點 |
|---|---|
| 自動化 UI 測試 | 結合驗證點檢查(文字內容、元件狀態),建構關鍵字驅動測試框架 |
| RPA 機器人流程自動化原型 | 針對無 API 的 Legacy 系統,模擬使用者操作完成資料輸入/查詢/匯出 |
| 示範/教學錄製回放 | 記錄使用者操作序列(事件+時間戳),回放重現操作流程 |
| 無障礙輔助工具 | 語音/眼動追蹤輸入轉換為標準 SWT 事件 |
post() 雖可從背景執行緒呼叫,但事件處理仍在 UI 執行緒SWT.SHIFT 等)、滑鼠按鈕編號在不同 OS 可能不同,需條件編譯或抽象層control.forceFocus())public class InputSimulator {
private final Display display;
public InputSimulator(Display display) { this.display = display; }
public void typeString(Control target, String text, int charDelayMs) {
target.forceFocus();
new Thread(() -> {
for (char ch : text.toCharArray()) {
boolean shift = Character.isUpperCase(ch);
char lower = Character.toLowerCase(ch);
if (shift) keyDown(SWT.SHIFT);
keyPress(lower);
sleep(charDelayMs);
keyRelease(lower);
if (shift) keyUp(SWT.SHIFT);
}
}).start();
}
// keyDown, keyUp, keyPress, mouseMove, mouseClick 等封裝方法...
}