模拟按键操作实现微信消息机器人

原创
2021/04/01 20:48
阅读数 1.6K

自从微信网页版不能登录后,网上开源的微信消息库都不能用了。
本文是通过按键模拟的方式来实现微信消息机器人,这方法也适用于模拟其它软件。
1、用到的工具和库
(1)JNA,https://github.com/java-native-access/jna,用于获取微信程序,程序窗口置顶操作。
(2)tesseract OCR,主要用于图片文字识别,用法可以参考之前文章https://my.oschina.net/penngo/blog/4972818
(3)java.awt.Robot,JDK自带的类,可以模拟键盘操作、鼠标操作、以及截图。

2、模拟操作步骤
(1)检查当前处于置顶的活动窗口程序是不是微信,如果不是微信则设置微信为置顶。
(2)按下CTRL+F,把需要对话的用户名或群名,粘贴到搜索框,搜索结果最匹配的用户名显示在第一条
(3)按下回车键,会自动选中搜索结果的第一条,并打开对话框。
(4)把对话文本粘贴到对话框,按下回车键发送。
通过上边4个步骤把消息发送出去。
实现代码:
RobotUtil.java

package com.penngo.weixin;
import com.penngo.weixin.utils.Tess4jUtil;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef;
import java.awt.*;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.event.KeyEvent;

public class RobotUtil {

    private static Robot robot;
    private static Clipboard clip;
    private static Toolkit kit;
    public static void isWeixinOnTop(){
        WinDef.HWND tophwnd = User32.INSTANCE.GetForegroundWindow();
        int textLength = User32.INSTANCE.GetWindowTextLength(tophwnd);
        char[] windowText = new char[textLength];
        User32.INSTANCE.GetWindowText(tophwnd, windowText, textLength + 3);
        String windowTitle = String.valueOf(windowText).trim();
        if("微信".equals(windowTitle) == false){
            WinDef.HWND hwnd = User32.INSTANCE.FindWindow(null, "微信");
            if (hwnd == null) {
                System.out.println("微信未运行");
                System.exit(0);
            } else {
                User32.INSTANCE.ShowWindow(hwnd, 9);
                User32.INSTANCE.SetForegroundWindow(hwnd);
            }
        }
    }

    /**
     * 初始化全局变量
     *
     */
    public static void init() {
        try {
            robot = new Robot();
        } catch (AWTException e) {
            robot = null;
            e.printStackTrace();
        }
        kit = Toolkit.getDefaultToolkit();
        clip = kit.getSystemClipboard();
    }

    public static void findName(String name){
        keyPressRelease(KeyEvent.VK_CONTROL, KeyEvent.VK_F);
        copy(name);
        paste();
        delay(2000);
        enter();
    }

    /**
     * 把内容放到剪贴板
     */
    public static void copy(String str){
        Transferable tText = new StringSelection(str);
        try{
            clip.setContents(tText, null);
        }
        catch(Exception e){
            e.printStackTrace();
            clip = Toolkit.getDefaultToolkit().getSystemClipboard();
            clip.setContents(tText, null);
        }
    }

    /**
     * 把内容放到剪贴板
     */
    public static void copyImg(String imgPath){
        Transferable tImg = new ImageSelection(kit.getImage(imgPath));
        clip.setContents(tImg, null);
    }
    /**
     * 粘贴
     */
    public static void paste(){
        keyPressRelease(KeyEvent.VK_CONTROL, KeyEvent.VK_V);
    }
    /**
     * 按快捷键,按下并释放
     * @param keys
     */
    public static void keyPressRelease(int...keys){
        for(int key:keys){
            robot.keyPress(key);
        }
        delay(50);
        for(int key:keys){
            robot.keyRelease(key);
        }
        delay(50);
    }
   

    public static void delay(int ms){
        robot.delay(ms);
    }

    public static void enter(){
        keyPressRelease(KeyEvent.VK_ENTER);
    }
}

WeiXinMessage.java

package com.penngo.weixin;
import com.penngo.weixin.utils.DateUtil;
import java.util.Date;
import java.util.Random;

public class WeiXinMessage {
    public WeiXinMessage(){
        RobotUtil.init();
        RobotUtil.topWeChat();
        RobotUtil.delay(2000);
    }

    /**
     * 发送文本消息
     * @param nickName 微信群内的用户昵称
     * @param txtMsg  发送的文本消息
     */
    public void sendTxt(String nickName, String txtMsg){
        RobotUtil.isWeixinOnTop();
        RobotUtil.findName(nickName);
        RobotUtil.delay(2000);
        RobotUtil.copy(txtMsg);
        RobotUtil.paste();
        RobotUtil.delay(2000);
        RobotUtil.enter();
    }
    public void sendImg(String nickName, String imgMsg){
        RobotUtil.findName(nickName);
        RobotUtil.delay(2000);
        RobotUtil.copyImg(imgMsg);
        RobotUtil.paste();
        RobotUtil.delay(2000);
        RobotUtil.enter();
    }
    public static void main(String[] args) {
        WeiXinMessage weiXin = new WeiXinMessage();
        weiXin.sendTxt("文件传输助手", "hello,penngo");
//      weiXin.sendImg("文件传输助手", "target\\test.jpg");
    }
}

3、改进优化
(1)在使用的过程中,发现偶尔的情况,会出现消息发错用户的情况(出现机率不算高)。
引入tesseract OCR,识别当前用户是否准确。

实现代码

WinDef.HWND hwnd = User32.INSTANCE.FindWindow("WeChatMainWndForPC", null);
WinDef.RECT rect = new WinDef.RECT();
User32.INSTANCE.GetWindowRect(hwnd,rect);
User32.INSTANCE.GetWindowRect(hwnd, rect);
int qqwin_width = rect.right-rect.left;
int qqwin_height = rect.bottom-rect.top;
User32.INSTANCE.MoveWindow(hwnd, 0, 0, qqwin_width, qqwin_height, true);
Tess4jUtil tess4jUtil = new Tess4jUtil();
// 识别出来的用户名
String name = tess4jUtil.getText(0 + 300, 0, qqwin_width - 300, 60);

(2)使用netty提供http接口,这样第三方程序可以与机器人交互,通过http接口,把消息传给机器人,再由机器人发送给微信用户。

 

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
0 评论
0 收藏
0
分享
返回顶部
顶部