




已阅读5页,还剩16页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Java语言的Hook实现引言:最近在玩完美时空的诛仙Online(不知道这里有没人有共同爱好的),这个游戏每晚七点会出现一个任务“新科试炼”。这个任务简单地说就是做选择题,范围小到柴米油盐,大到世界大千,所以多玩的YY上出现一个频道叫“诛仙答题频道”,这个频道会即时为玩家提供正确答案,所以当大家都上YY的时候,最终出来的成绩的高低并不取决于你的知识面,而是取决你家的网速及你的反应速度(答题越早,所获得的成绩越高)。我家的网速很好,可惜我的反应速度一般,所以从来没上过一次前十,因为每次听说YY上的答案后还要移动鼠标去点击相应的答案,这个过程平均需要0.5秒,这无疑是我成绩不高的根本所在。所以我想到了通过按下键盘上的某些按键实现将鼠标移动到指定位置并模拟鼠标键按下事件(以下简称模拟)。也许你会问:这还不简单,直接加个KeyListener不就完了?但是你想过没有,在模拟的时候,窗口的焦点是在游戏窗口,而不是Java程序的窗口(甚至连窗口都没有),所以我们需要一个监听所有进程的接口,这就是我接下要说的“Hook(钩子)”(了解外挂制作的人应该知道是什么东西,没看过?百度之)。不废话,进入正题: 首先,编写之前,我们要使用到一个第三方类库,它实现的功能就是让你直接调用API,而将对Window的调用交给它处理,下载地址是:-feeling . sourceforge .net 将包下载完后解压,并创建项目,结构如左图,lib下的三个dll文件要拷到window/system32下,下面就是编码了:首先我们定义一个抽象类来拦截键盘事件,如下:Java代码 import org.sf.feeling.swt.win32.extension.hook.data.HookData; import org.sf.feeling.swt.win32.extension.hook.data.KeyboardHookData; import org.sf.feeling.swt.win32.extension.hook.listener.HookEventListener; public abstract class KeyboardHookEventListener implements HookEventListener public void acceptHookData(HookData arg0) KeyboardHookData khd = (KeyboardHookData) arg0); if(khd.getTransitionState() /处理按下事件 doPress(khd.getWParam(); else doReleased(khd.getWParam(); /处理释放事件 public abstract void doPress(int keyNum); public abstract void doReleased(int keyNum); import org.sf.feeling.swt.win32.extension.hook.data.HookData;import org.sf.feeling.swt.win32.extension.hook.data.KeyboardHookData;import org.sf.feeling.swt.win32.extension.hook.listener.HookEventListener;public abstract class KeyboardHookEventListener implements HookEventListenerpublic void acceptHookData(HookData arg0) KeyboardHookData khd = (KeyboardHookData) arg0);if(khd.getTransitionState()/处理按下事件doPress(khd.getWParam();elsedoReleased(khd.getWParam();/处理释放事件public abstract void doPress(int keyNum);public abstract void doReleased(int keyNum); 接着再定义一个抽象类到拦截鼠标事件,如下:Java代码 import org.sf.feeling.swt.win32.extension.hook.data.HookData; import org.sf.feeling.swt.win32.extension.hook.data.MouseHookData; import org.sf.feeling.swt.win32.extension.hook.listener.HookEventListener; public abstract class MouseHookEventListener implements HookEventListener public void acceptHookData(HookData hookData) int x=(MouseHookData) hookData).getPointX(); int y=(MouseHookData) hookData).getPointY(); switch(hookData.getWParam() case 513: doLeftPressed(x,y); break; case 514: doLeftReleased(x,y); break; case 516: doRightPressed(x,y); break; case 517: doRightReleased(x,y); break; case 519: doMiddlePressed(x,y); break; case 520: doMiddleReleased(x,y); break; default: protected abstract void doLeftPressed(int x,int y); protected abstract void doLeftReleased(int x,int y); protected abstract void doRightPressed(int x,int y); protected abstract void doRightReleased(int x,int y); protected abstract void doMiddlePressed(int x,int y); protected abstract void doMiddleReleased(int x,int y); import org.sf.feeling.swt.win32.extension.hook.data.HookData;import org.sf.feeling.swt.win32.extension.hook.data.MouseHookData;import org.sf.feeling.swt.win32.extension.hook.listener.HookEventListener;public abstract class MouseHookEventListener implements HookEventListenerpublic void acceptHookData(HookData hookData) int x=(MouseHookData) hookData).getPointX();int y=(MouseHookData) hookData).getPointY();switch(hookData.getWParam()case 513:doLeftPressed(x,y);break;case 514:doLeftReleased(x,y);break;case 516:doRightPressed(x,y);break;case 517:doRightReleased(x,y);break;case 519:doMiddlePressed(x,y);break;case 520:doMiddleReleased(x,y);break;default:protected abstract void doLeftPressed(int x,int y);protected abstract void doLeftReleased(int x,int y);protected abstract void doRightPressed(int x,int y);protected abstract void doRightReleased(int x,int y);protected abstract void doMiddlePressed(int x,int y);protected abstract void doMiddleReleased(int x,int y); 至此,我们的项目底层架构已经完成,下面就是业务流程的控制问题了,在贴上我的代码之前,我觉得有必要先做一下诛仙答题跟项目的介绍(又要废话了,顺便帮老池免费作下广告,遇上我是他的福分,-)。答题是这样的:首先,诛仙这个游戏是支持窗口化(且提供几个固定窗口大小供选择),而其中的答题窗口就是窗口中的窗口了(可拖动的)。7点,答题系统开启,每个玩家可选择进入答题窗口,等下一分钟才真正开始,这一分钟中,页面会显示出3个幸运星,但是没有题目.经过一番分析,可以确定用户要输入的有:当前使用的窗口大小及幸运星的位置(幸运星跟选项的位置不固定的,幸运星一确定,选项的位置也就知道了)。以下是关于这个业务的代码:定义一个特定的鼠标事件响应,如下:Java代码 import java.awt.Dimension; import java.util.LinkedList; import java.util.List; public class MyMouseHookEventListener extends MouseHookEventListener private Dimension zeroDimension; private List dimensions=new LinkedList(); private boolean needFetchZeroDimension=false; private String currentOffsetSeries=; public void resetZeroDimension() this.needFetchZeroDimension=true; public void resetDimensions(String dimensionSeries) this.dimensions.clear(); String dimStrs=dimensionSeries.split(,); for(int i=0;dimStrs!=null&i0) dimSeries=dimSeries.substring(1); return dimSeries; Override protected void doLeftPressed(int x, int y) Override protected void doLeftReleased(int x, int y) Override protected void doMiddlePressed(int x, int y) Override protected void doMiddleReleased(int x, int y) Override protected void doRightPressed(int x, int y) if(this.needFetchZeroDimension) this.zeroDimension=new Dimension(x,y); resetDimensions(currentOffsetSeries); this.needFetchZeroDimension=false; System.out.println(幸运星位置已获取,关闭重置模式,rn现在你可以使用小键盘上的12345来实现鼠标事件模拟,如果你需要重新选择请按F11); Override protected void doRightReleased(int x, int y) public void setCurrentOffsetSeries(String currentOffsetSeries) this.currentOffsetSeries = currentOffsetSeries; public List getDimensions() return dimensions; import java.awt.Dimension;import java.util.LinkedList;import java.util.List;public class MyMouseHookEventListener extends MouseHookEventListener private Dimension zeroDimension;private List dimensions=new LinkedList();private boolean needFetchZeroDimension=false;private String currentOffsetSeries=;public void resetZeroDimension()this.needFetchZeroDimension=true;public void resetDimensions(String dimensionSeries)this.dimensions.clear();String dimStrs=dimensionSeries.split(,);for(int i=0;dimStrs!=null&i0)dimSeries=dimSeries.substring(1);return dimSeries;Overrideprotected void doLeftPressed(int x, int y) Overrideprotected void doLeftReleased(int x, int y) Overrideprotected void doMiddlePressed(int x, int y) Overrideprotected void doMiddleReleased(int x, int y) Overrideprotected void doRightPressed(int x, int y) if(this.needFetchZeroDimension)this.zeroDimension=new Dimension(x,y);resetDimensions(currentOffsetSeries);this.needFetchZeroDimension=false;System.out.println(幸运星位置已获取,关闭重置模式,rn现在你可以使用小键盘上的12345来实现鼠标事件模拟,如果你需要重新选择请按F11);Overrideprotected void doRightReleased(int x, int y) public void setCurrentOffsetSeries(String currentOffsetSeries) this.currentOffsetSeries = currentOffsetSeries;public List getDimensions() return dimensions; 再定义一个运行类:Java代码 import java.awt.AWTException; import java.awt.Robot; import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.StringSelection; import java.awt.datatransfer.Transferable; import java.awt.event.InputEvent; import org.sf.feeling.swt.win32.extension.hook.Hook; public class ZhuXianSwifter public static final int NUM_1=97; public static final int NUM_2=98; public static final int NUM_3=99; public static final int NUM_4=100; public static final int NUM_5=101; public static final int F_11=122; public static final int F_12=123; private static final String OFFSET_SERIES_640_480=-125,84,-125,107,-125,130,-125,152,44,0,20,0,0,0; private static final String OFFSET_SERIES_800_600=-156,105,-156,134,-156,163,-156,190,55,0,25,0,0,0; private static final String OFFSET_SERIES_1024_768=-200,138,-200,172,-200,211,-200,248,70,0,32,0,0,0; /* * 使用说明: * 1、启动后先选择所使用的分辨率,目前只支持640*480,800*600,1024*768; * 2、然后使用鼠标右键点击一下试炼答题窗口的第一个幸运星的中心点即可; * 3、使用小键盘的1234选择答案,使用5点星星(第一个使用完会自动用第二个), * 4、只支持命令行模式 * 5、F11为取坐标模式,按F11开始,再次按F11结束,并将零坐标跟之前的偏移坐标复制到系统剪贴板 * 6、按F12退出程序 * throws AWTException */ public static void main(String args) throws AWTException /*注册鼠标Hook*/ final MyMouseHookEventListener mouseListener=new MyMouseHookEventListener(); Hook.MOUSE.addListener(mouseListener); Hook.MOUSE.install(); /*系统剪贴板*/ final Clipboard systemClipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); final Robot robot=new Robot(); /*键盘监听器*/ final KeyboardHookEventListener keyboardListener=new KeyboardHookEventListener() private boolean haveChooseMode=false; private int count=0; Override public void doPress(int keyNum) String mode=; if(keyNum=F_12) if(!mouseListener.getDimensionSeries().equals() System.out.println(内容已经复制到系统剪贴板); Transferable text = new StringSelection(mouseListener.getDimensionSeries(); systemClipboard.setContents(text,null); System.out.println(-程序退出-); System.exit(0); else if(keyNum=F_11) haveChooseMode=false; count=0; System.out.println(启动重置模式); printChooseMode(); else if(haveChooseMode=false) switch(keyNum) case NUM_1: mode=640*480; mouseListener.setCurrentOffsetSeries(OFFSET_SERIES_640_480); break; case NUM_2: mode=800*600; mouseListener.setCurrentOffsetSeries(OFFSET_SERIES_800_600); break; case NUM_3: mode=1024*768; mouseListener.setCurrentOffsetSeries(OFFSET_SERIES_1024_768); break; default: System.out.println(请重新选择:); printChooseMode(); return; System.out.println(您选择了+mode+分辨率模式); haveChooseMode=true; mouseListener.resetZeroDimension(); printFetchZeroCoordinate(); else switch (keyNum) case NUM_1: robot.mouseMove(int)mouseListener.getDimensions().get(0).getWidth(),(int)mouseListener.getDimensions().get(0).getHeight(); robot.mousePress(InputEvent.BUTTON1_MASK); robot.mouseRelease(InputEvent.BUTTON1_MASK); break; case NUM_2: robot.mouseMove(int)mouseListener.getDimensions().get(1).getWidth(),(int)mouseListener.getDimensions().get(1).getHeight(); robot.mousePress(InputEvent.BUTTON1_MASK); robot.mouseRelease(InputEvent.BUTTON1_MASK); break; case NUM_3: robot.mouseMove(int)mouseListener.getDimensions().get(2).getWidth(),(int)mouseListener.getDimensions().get(2).getHeight(); robot.mousePress(InputEvent.BUTTON1_MASK); robot.mouseRelease(InputEvent.BUTTON1_MASK); break; case NUM_4: robot.mouseMove(int)mouseListener.getDimensions().get(3).getWidth(),(int)mouseListener.getDimensions().get(3).getHeight(); robot.mousePress(InputEvent.BUTTON1_MASK); robot.mouseRelease(InputEvent.BUTTON1_MASK); break; case NUM_5: robot.mouseMove(int)mouseListener.getDimensions().get(4+count).getWidth(),(int)mouseListener.getDimensions().get(4+count).getHeight(); robot.mousePress(InputEvent.BUTTON1_MASK); robot.mouseRelease(InputEvent.BUTTON1_MASK); count+; if(count=3) count=0; break; default: break; Override public void doReleased(int keyNum) ; Hook.KEYBOARD.addListener(keyboardListener); Hook.KEYBOARD.install(); / 註冊事件 printChooseMode(); private static void printChooseMode() System.out.println(请选择窗口大小:); System.out.println(NUM1:640*480); System.out.println(NUM2:800*600); System.out.println(NUM3:1024*768); private static void printFetchZeroCoordinate() System.out.println(请在第一个幸运星的中心上点击鼠标右键); import java.awt.AWTException;import java.awt.Robot;import java.awt.Toolkit;import java.awt.datatransfer.Clipboard;import java.awt.datatransfer.StringSelection;import java.awt.datatransfer.Transferable;import java.awt.event.InputEvent;import org.sf.feeling.swt.win32.extension.hook.Hook;public class ZhuXianSwifter public static final int NUM_1=97;public static final int NUM_2=98;public static final int NUM_3=99;public static final int NUM_4=100;public static final int NUM_5=101;public static final int F_11=122;public static final int F_12=123;private static final String OFFSET_SERIES_640_480=-125,84,-125,107,-125,130,-125,152,44,0,20,0,0,0;private static final String OFFSET_SERIES_800_600=-156,105,-156,134,-156,163,-156,190,55,0,25,0,0,0;private static final String OFFSET_SERIES_1024_768=-200,138,-200,172,-200,211,-200,248,70,0,32,0,0,0;/* * 使用说明: * 1、启动后先选择所使用的分辨率,目前只支持640*480,800*600,1024*768; * 2、然后使用鼠标右键点击一下试炼答题窗口的第一个幸运星的中心点即可; * 3、使用小键盘的1234选择答案,使用
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 夜间施工周边居民沟通协调方案
- 锂电池生产流程自动化与物联网整合方案
- 病房改造项目风险评估与应对方案
- 校园消防安全教育-讲话
- 校园安全教育管理讲座
- 消防大队校园安全教育
- 公路项目勘察与设计方案
- 给水工程水库建设与管理方案
- 给水工程供水管网设计方案
- 地热供暖示范项目配套技术方案
- 化学品使用储存培训
- 《古希腊弃婴现象研究》
- 专题26 实验与探究 十年(2015 2024)高考生物真题分类汇编(全国) (解析版)
- 结核性脑病影像诊断
- 国家职业技术技能标准 6-02-06-03 白酒酿造工 人社厅发2019107号
- 制冰机和设备相关项目实施方案
- 竣工结算审计服务投标方案(技术方案)
- 中国抗肿瘤治疗相关恶心呕吐预防和治疗指南(2023版)解读
- 2024至2030年全球及中国湿式电动剃须刀行业深度研究报告
- 《冷战史专题》笔记
- 高中化学必修一2.2离子反应第二课时课件
评论
0/150
提交评论