为什么awt_为AWT的机器人创建DSL
為什么awt
Java SDK附帶了java.awt.Robot類,該類允許鍵盤和鼠標(biāo)輸入的自動(dòng)化以及屏幕捕獲的創(chuàng)建。 當(dāng)您要編寫(xiě)一個(gè)模擬用戶輸入的小型測(cè)試應(yīng)用程序時(shí),或者只想自動(dòng)化一些重復(fù)文本的輸入時(shí),此功能非常有用。 但是您不想每次都編寫(xiě)一個(gè)完整的Java應(yīng)用程序。
另一方面,ANTLR是解析器生成器,使我們能夠創(chuàng)建“特定于域的語(yǔ)言”(DSL)。 借助ANTLR,我們可以開(kāi)發(fā)一個(gè)簡(jiǎn)單的DSL,它為java.awt.Robot每種方法提供一個(gè)命令。 從那時(shí)起,我們可以輕松地為各種簡(jiǎn)單的自動(dòng)化任務(wù)編寫(xiě)腳本。
第一步是發(fā)明新的“ DSL”的語(yǔ)法:
- 不同的“陳述”應(yīng)以分號(hào)分隔。
- 每個(gè)語(yǔ)句應(yīng)包含一個(gè)“命令”和該命令的幾個(gè)參數(shù)。
- 注釋?xiě)?yīng)該跨越多行(使用類似C的注釋/ *…* /,或者僅直到行尾為止。
一個(gè)簡(jiǎn)單的文件可能如下所示:
/* * 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;有了這些要求,我們就可以開(kāi)始寫(xiě)下語(yǔ)法了:
grammar Robot;instructions:(instruction ';')+EOF;instruction:instructionDelay |instructionMouseMove |instructionCreateScreenCapture |instructionMouseClick |instructionKeyboardInput;我們將語(yǔ)法命名為“機(jī)器人”,并定義第一條規(guī)則instructions ,以便我們擁有一個(gè)或多個(gè)指令,后跟一個(gè)分號(hào)作為指令分隔符,直到到達(dá)文件末尾(EOF)。 我們要支持的指令作為規(guī)則instruction一部分列出。 不同規(guī)則之間的管道表示邏輯或,即這些規(guī)則中只有一個(gè)必須匹配。
最簡(jiǎn)單的規(guī)則是instructionDelay之一:
instructionDelay:'delay' paramMs=INTEGER; ... INTEGER:[0-9]+;該規(guī)則以命令“ delay”開(kāi)頭,后跟唯一一個(gè)以整數(shù)形式指定要Hibernate的毫秒數(shù)的參數(shù)。 令牌INTEGER顯示在規(guī)則下方。 它只是定義了我們希望至少有一個(gè)介于0到9之間的數(shù)字。 為了便于以后處理參數(shù),我們將參數(shù)分配給名為paramMs的單獨(dú)樹(shù)節(jié)點(diǎn)。
進(jìn)行屏幕截圖的規(guī)則如下所示:
instructionCreateScreenCapture:'createScreenCapture' x=INTEGER ',' y=INTEGER ',' w=INTEGER ',' h=INTEGER 'file=' file=FILENAME; ... FILENAME:FileNameChar+; fragment FileNameChar:[a-zA-Z0-9/\\:_-$~.];緊隨其后的是關(guān)鍵字createScreenCapture ,用戶必須在屏幕上應(yīng)捕獲的矩形的左上點(diǎn)提供兩個(gè)坐標(biāo)。 接下來(lái)的兩個(gè)坐標(biāo)表示矩形的寬度和高度。 最后,用戶必須提供捕獲圖像的文件名。
文件名由片段FileNameChar的一個(gè)或多個(gè)字符組成。 該fragment定義了文件名應(yīng)允許的所有字符。
使用maven,我們現(xiàn)在可以將此語(yǔ)法存儲(chǔ)為src/main/antlr4文件夾中的Robot.g4文件,并利用相應(yīng)的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作為參數(shù),然后解析并執(zhí)行它:
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(); }文件的內(nèi)容通過(guò)ANTLRInputStream轉(zhuǎn)發(fā)到由ANTLR生成的RobotLexer 。 在詞法分析器解析文件并生成令牌流之后,可以將該流傳RobotParser實(shí)際的RobotParser 。
為了對(duì)傳入的指令做出React,添加了ParseListener 。 幸運(yùn)的是,ANTLR已經(jīng)創(chuàng)建了一個(gè)基本偵聽(tīng)器,該偵聽(tīng)器使用空的實(shí)現(xiàn)來(lái)實(shí)現(xiàn)所有回調(diào)方法。 因此,我們只需要重寫(xiě)我們要處理的方法。 當(dāng)ANTLR為每個(gè)解析器規(guī)則創(chuàng)建一個(gè)回調(diào)方法時(shí),我們可以覆蓋例如方法exitInstructionDelay() 。 生成的代碼傳遞的參數(shù)的類型為RobotParser.InstructionDelayContex 。 正如我們之前在語(yǔ)法中將參數(shù)分配給單獨(dú)的節(jié)點(diǎn)一樣,此上下文對(duì)象具有字段paramMs 。 它的getText()方法以String返回此參數(shù)的值。 我們只需要將其轉(zhuǎn)換為整數(shù)值,然后將其傳遞給Robot實(shí)例的delay()方法即可。
下面的塊中顯示了規(guī)則instructionCreateScreenCapture的實(shí)現(xiàn):
@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);} }原理與上一條指令所示的相同。 傳入的上下文對(duì)象的每個(gè)參數(shù)都有一個(gè)字段,這些字符串值必須轉(zhuǎn)換為整數(shù)值。 有了這些信息,我們就可以構(gòu)造一個(gè)Rectangle對(duì)象,調(diào)用Robot的createScreenCapture()方法并存儲(chǔ)其BufferedImage 。
結(jié)論
為AWT的機(jī)器人創(chuàng)建專用DSL比預(yù)期容易。 所提供的maven插件從語(yǔ)法文件中創(chuàng)建所有必需的類,并與之平滑地集成到構(gòu)建過(guò)程中。 生成的DSL可用于自動(dòng)化簡(jiǎn)單的鼠標(biāo)和鍵盤任務(wù),包括創(chuàng)建屏幕截圖。
- PS:源代碼可從github獲得 。
翻譯自: https://www.javacodegeeks.com/2015/04/creating-a-dsl-for-awts-robot.html
為什么awt
總結(jié)
以上是生活随笔為你收集整理的为什么awt_为AWT的机器人创建DSL的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: DDoS流量(ddos网络流量图)
- 下一篇: 电脑鼠标经常卡住不动怎么办 更新鼠标驱动