为AWT的机器人创建DSL
Java SDK附帶了java.awt.Robot類,該類允許鍵盤和鼠標輸入的自動化以及屏幕捕獲的創建。 如果您想編寫一個模擬用戶輸入的小型測試應用程序,或者只想自動化一些重復文本的輸入,則此功能非常有用。 但是您不想每次都編寫一個完整的Java應用程序。
另一方面,ANTLR是解析器生成器,使我們能夠創建“域特定語言”(DSL)。 借助ANTLR,我們可以開發一個簡單的DSL,它為java.awt.Robot每種方法提供一個命令。 從那時起,我們可以輕松地為各種簡單的自動化任務編寫腳本。
第一步是發明新的“ DSL”的語法:
- 不同的“陳述”應以分號分隔。
 - 每個語句應包含一個“命令”和該命令的幾個參數。
 - 注釋應該跨越多行(使用類似C的注釋/ *…* /,或者僅直到行尾為止。
 
一個簡單的文件可能如下所示:
/* * A simple example demonstrating the basic features. */ delay 300; // sleep for 300ms mouseMove 20,30; createScreenCapture 100,100,200,200 file=/home/siom/capture.png; mouseClick button1; keyboardInput "Test"; delay 400;有了這些要求,我們就可以開始寫下語法了:
grammar Robot;instructions:(instruction ';')+EOF;instruction:instructionDelay |instructionMouseMove |instructionCreateScreenCapture |instructionMouseClick |instructionKeyboardInput;我們將語法命名為“機器人”,并定義第一條規則instructions ,以便我們擁有一個或多個指令,后跟一個分號作為指令分隔符,直到到達文件末尾(EOF)。 我們要支持的指令作為規則instruction一部分列出。 不同規則之間的管道表示邏輯或,即僅這些規則之一必須匹配。
最簡單的規則是instructionDelay延遲:
instructionDelay:'delay' paramMs=INTEGER; ... INTEGER:[0-9]+;該規則以命令“ delay”開頭,后跟唯一一個以整數形式指定要休眠的毫秒數的參數。 令牌INTEGER顯示在規則下方。 它只是定義了我們希望至少有一個介于0到9之間的數字。 為了簡化以后對參數的處理,我們將參數分配給名為paramMs的單獨樹節點。
進行屏幕截圖的規則如下所示:
instructionCreateScreenCapture:'createScreenCapture' x=INTEGER ',' y=INTEGER ',' w=INTEGER ',' h=INTEGER 'file=' file=FILENAME; ... FILENAME:FileNameChar+; fragment FileNameChar:[a-zA-Z0-9/\\:_-$~.];緊隨其后的是關鍵字createScreenCapture ,用戶必須在屏幕上應捕獲的矩形的左上點提供兩個坐標。 接下來的兩個坐標表示矩形的寬度和高度。 最后,用戶必須提供捕獲圖像的文件名。
文件名由片段FileNameChar的一個或多個字符組成。 該fragment定義了文件名應允許的所有字符。
使用maven,我們現在可以將此語法存儲為src/main/antlr4文件夾中的Robot.g4文件,并利用相應的maven插件生成Java詞法分析器和解析器:
<build><plugins><plugin><groupId>org.antlr</groupId><artifactId>antlr4-maven-plugin</artifactId><version>${antlr.version}</version><executions><execution><goals><goal>antlr4</goal></goals></execution></executions></plugin>...</plugins> </build><dependencies><dependency><groupId>org.antlr</groupId><artifactId>antlr4-runtime</artifactId><version>${antlr.version}</version></dependency>... </dependencies>要在我們自己的代碼中使用生成的類,必須依賴antlr4-runtime 。
方法execute()將輸入文件的Path作為參數,然后解析并執行它:
public void execute(Path inputPath) throws IOException, AWTException {RobotLexer lexer = new RobotLexer(new ANTLRInputStream(new FileInputStream(inputPath.toFile())));RobotParser parser = new RobotParser(new CommonTokenStream(lexer));final Robot robot = new Robot();parser.addParseListener(new RobotBaseListener() {@Overridepublic void exitInstructionDelay(@NotNull RobotParser.InstructionDelayContext ctx) {int delayParam = Integer.parseInt(ctx.paramMs.getText());LOGGER.info("delay(" + delayParam + ")");robot.delay(delayParam);}...});parser.instructions(); }該文件的內容通過ANTLRInputStream轉發到由ANTLR生成的RobotLexer 。 在詞法分析器解析文件并生成令牌流之后,可以將該流傳RobotParser實際的RobotParser 。
為了對傳入的指令做出反應,添加了ParseListener 。 幸運的是,ANTLR已經創建了一個基本偵聽器,該偵聽器使用空的實現來實現所有回調方法。 因此,我們只需要重寫我們要處理的方法。 當ANTLR為每個解析器規則創建一個回調方法時,我們可以覆蓋例如方法exitInstructionDelay() 。 生成的代碼傳遞的參數的類型為RobotParser.InstructionDelayContex 。 正如我們之前在語法中將參數分配給單獨節點一樣,此上下文對象具有字段paramMs 。 它的getText()方法以String返回此參數的值。 我們只需要將其轉換為整數值,然后將其傳遞給Robot實例的delay()方法即可。
下面的塊中顯示了規則instructionCreateScreenCapture的實現:
@Override public void exitInstructionCreateScreenCapture(@NotNullRobotParser.InstructionCreateScreenCaptureContext ctx) {int x = Integer.parseInt(ctx.x.getText());int y = Integer.parseInt(ctx.y.getText());int w = Integer.parseInt(ctx.w.getText());int h = Integer.parseInt(ctx.h.getText());LOGGER.info("Rectangle rectangle = new Rectangle(" + x + "," + y + "," + w + "," + h + ")");Rectangle rectangle = new Rectangle(x, y, w, h);LOGGER.info("createScreenCapture(rectangle);");BufferedImage bufferedImage = robot.createScreenCapture(rectangle);File output = new File(ctx.file.getText());LOGGER.info("Save file to " + output.getAbsolutePath());try {ImageIO.write(bufferedImage, "png", output);} catch (IOException e) {throw new RuntimeException("Failed to write image file: " + e.getMessage(), e);} }其原理與上一條指令所示的相同。 傳入的上下文對象的每個參數都有一個字段,這些字符串值必須轉換為整數值。 有了這些信息,我們可以構造一個Rectangle對象,調用Robot的createScreenCapture()方法并存儲其BufferedImage 。
結論
為AWT的機器人創建專用DSL比預期容易。 所提供的maven插件從語法文件中創建所有必需的類,并與之平滑地集成到構建過程中。 生成的DSL可用于自動化簡單的鼠標和鍵盤任務,包括創建屏幕截圖。
- PS:源代碼可從github獲得 。
 
翻譯自: https://www.javacodegeeks.com/2015/04/creating-a-dsl-for-awts-robot.html
總結
以上是生活随笔為你收集整理的为AWT的机器人创建DSL的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: 魔术二传手反模式
 - 下一篇: 郭明錤:华为归来对消费者来说是好事,倒逼