当前位置: 代码网 > it编程>编程语言>Asp.net > dotnet X11 窗口之间发送鼠标消息 模拟鼠标输入

dotnet X11 窗口之间发送鼠标消息 模拟鼠标输入

2024年05月16日 Asp.net 我要评论
本文记录我阅读 Avalonia 代码过程中所学习到的在 X11 的窗口之间发送鼠标消息,可以跨进程给其他进程的窗口发送鼠标消息,通过此方式可以实现模拟鼠标输入 ...

本文记录我阅读 avalonia 代码过程中所学习到的在 x11 的窗口之间发送鼠标消息,可以跨进程给其他进程的窗口发送鼠标消息,通过此方式可以实现模拟鼠标输入

直接使用 xsendevent 给指定窗口发送消息即可,如以下示例代码

            var xevent = new xevent
            {
                motionevent =
                {
                    type = xeventname.motionnotify,
                    send_event = true,
                    window = window,
                    display = display,
                    x = x,
                    y = y
                }
            };
            xsendevent(display, window, propagate: false, new intptr((int) (eventmask.buttonmotionmask)), ref xevent);

以上的 window 是自己进程的主窗口,发送的相关定义代码是我从 avalonia 和 cpf 代码仓库里面抄的,所有代码放在 githubgitee 上,可以使用如下命令行拉取代码

先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码

git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin 7636387e97780403ce473f553540a9cc1e0652ef

以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继续输入以下代码,将 gitee 源换成 github 源进行拉取代码

git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
git pull origin 7636387e97780403ce473f553540a9cc1e0652ef

获取代码之后,进入 dikalehebeekajaqunicobo 文件夹,即可获取到源代码

以上代码是对自己进程内的主窗口发送鼠标移动消息的示例,核心代码如下

while (true)
{
    var xnextevent = xnextevent(display, out var @event);
    if (@event.type == xeventname.motionnotify)
    {
        var x = @event.motionevent.x;
        var y = @event.motionevent.y;

        xdrawline(display, window, gc, x, y, x + 100, y);
    }

    var count = xeventsqueued(display, 0 /*queuedalready*/);
    if (count == 0)
    {
        for (int i = 0; i < 100; i++)
        {
            var xevent = new xevent
            {
                motionevent =
                {
                    type = xeventname.motionnotify,
                    send_event = true,
                    window = window,
                    display = display,
                    x = i,
                    y = i
                }
            };
            xsendevent(display, window, propagate: false, new intptr((int) (eventmask.buttonmotionmask)), ref xevent);
        }
    }
}

如上述代码可以看到只需更改 xsendevent 里面的 window 对应的参数,即可决定发送给哪个窗口。比如有两个窗口,可以通过此方式让窗口 2 收到鼠标消息时,自动转发给窗口 1 上,核心代码如下

var handle = xcreatewindow(display, rootwindow, 0, 0, xdisplaywidth, xdisplayheight, 5,
    32,
    (int)createwindowargs.inputoutput,
    visual,
    (nuint)valuemask, ref xsetwindowattributes);


var window1 = new foowindow(handle, display);


var window2 = new foowindow(xcreatewindow(display, rootwindow, 0, 0, xdisplaywidth, xdisplayheight, 5,
    32,
    (int) createwindowargs.inputoutput,
    visual,
    (nuint) valuemask, ref xsetwindowattributes), display);


while (true)
{
    var xnextevent = xnextevent(display, out var @event);
    if (xnextevent != 0)
    {
        break;
    }

    if (@event.type == xeventname.motionnotify)
    {
        var x = @event.motionevent.x;
        var y = @event.motionevent.y;

        if (@event.motionevent.window == window1.window)
        {
            xdrawline(display, window1.window, window1.gc, x, y, x + 100, y);
        }
        else
        {
            var xevent = new xevent
            {
                motionevent =
                {
                    type = xeventname.motionnotify,
                    send_event = true,
                    window = window1.window,
                    display = display,
                    x = x,
                    y = y
                }
            };
            xsendevent(display, window1.window, propagate: false, new intptr((int)(eventmask.buttonmotionmask)),
                ref xevent);
        }
    }
}

class foowindow
{
    public foowindow(nint windowhandle, nint display)
    {
        window = windowhandle;

        xeventmask ignoredmask = xeventmask.substructureredirectmask | xeventmask.resizeredirectmask |
                                 xeventmask.pointermotionhintmask;
        var mask = new intptr(0xffffff ^ (int)ignoredmask);
        xselectinput(display, windowhandle, mask);

        xmapwindow(display, windowhandle);
        xflush(display);

        var screen = xdefaultscreen(display);
        var white = xwhitepixel(display, screen);

        var gc = xcreategc(display, windowhandle, 0, 0);
        xsetforeground(display, gc, white);

        gc = gc;
    }

    public nint window { get; }
    public intptr gc { get; }
}

以上代码放在 githubgitee 上,可以使用如下命令行拉取代码

先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码

git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin c8354f643998d01eed8f56757a558623e4d94a8a

以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继续输入以下代码,将 gitee 源换成 github 源进行拉取代码

git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
git pull origin c8354f643998d01eed8f56757a558623e4d94a8a

获取代码之后,进入 dikalehebeekajaqunicobo 文件夹,即可获取到源代码

以上测试的是相同进程内的,跨进程其实也可以,只需要获取其他进程的窗口对应的指针即可。其实在这里我不确定 x11 的窗口 intptr 是否称为指针是合适的。但行为上看起来和 windows 下的句柄非常类似

如以下的测试代码,启动自身作为新的进程,然后传入当前进程的窗口,让另一个进程获取当前进程的窗口,接着测试在另一个进程将鼠标消息发送到当前进程上

var handle = xcreatewindow(display, rootwindow, 0, 0, xdisplaywidth, xdisplayheight, 5,
    32,
    (int)createwindowargs.inputoutput,
    visual,
    (nuint)valuemask, ref xsetwindowattributes);


var window1 = new foowindow(handle, display);
xsync(display, false);

intptr window2handle = intptr.zero;

if (args.length == 0)
{
    var currentprocess = process.getcurrentprocess();
    var mainmodulefilename = currentprocess.mainmodule!.filename;
    process.start(mainmodulefilename, [window1.window.tostring(), window1.gc.tostring()]);
}
else if (args.length == 2)
{
    if (long.tryparse(args[0], out var otherprocesswindowhandle))
    {
        window2handle = new intptr(otherprocesswindowhandle);
    }
}

while (true)
{
    var xnextevent = xnextevent(display, out var @event);
    if (xnextevent != 0)
    {
        console.writeline($"xnextevent {xnextevent}");
        break;
    }

    if (@event.type == xeventname.expose)
    {
        if (args.length == 0)
        {
            xdrawline(display, window1.window, window1.gc, 0, 0, 100, 100);
        }
    }
    else if (@event.type == xeventname.motionnotify)
    {
        var x = @event.motionevent.x;
        var y = @event.motionevent.y;

        if (window2handle != 0 && window2gchandle != 0)
        {
            // 绘制是无效的
            //xdrawline(display, window2handle, window2gchandle, x, y, x + 100, y);

            var xevent = new xevent
            {
                motionevent =
                {
                    type = xeventname.motionnotify,
                    send_event = true,
                    window = window2handle,
                    display = display,
                    x = x,
                    y = y
                }
            };
            xsendevent(display, window2handle, propagate: false, new intptr((int)(eventmask.buttonmotionmask)),
                ref xevent);
        }
        else
        {
            xdrawline(display, window1.window, window1.gc, x, y, x + 100, y);
        }
    }
}

放在 githubgitee 上,可以使用如下命令行拉取代码

先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码

git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin ec8242cfe08a0eb23ba637c655083fceb0a8edb3

以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继续输入以下代码,将 gitee 源换成 github 源进行拉取代码

git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
git pull origin ec8242cfe08a0eb23ba637c655083fceb0a8edb3

获取代码之后,进入 dikalehebeekajaqunicobo 文件夹,即可获取到源代码

通过以上测试可以发现 x11 的鼠标输入是完全可以进行模拟输入的,只需要拿到窗口指针,使用 xsendevent 进行发送即可

再进一步的实验,也许大家也发现上面代码里面有被我注释的 xdrawline 的调用。在 xdrawline 里面也是传入 gc 和 window 指针即可绘制线段,我就想着如果传入别的进程的窗口是否适合,是否就能在其他进程的窗口上绘制出内容

我尝试从另一个进程将 gc 传回来,如下面代码

intptr window2handle = intptr.zero;
intptr window2gchandle = intptr.zero;

if (args.length == 0)
{
    var currentprocess = process.getcurrentprocess();
    var mainmodulefilename = currentprocess.mainmodule!.filename;
    process.start(mainmodulefilename, [window1.window.tostring(), window1.gc.tostring()]);
}
else if (args.length == 2)
{
    if (long.tryparse(args[0], out var otherprocesswindowhandle))
    {
        window2handle = new intptr(otherprocesswindowhandle);
    }

    if (long.tryparse(args[1], out var otherprocessgchandle))
    {
        window2gchandle = new intptr(otherprocessgchandle);
    }
}

  ... // 忽略其他代码

         xdrawline(display, window2handle, window2gchandle, x, y, x + 100, y);

此时发现运行代码,进入到 xdrawline 报段错误,进程挂掉。原因是 gc 指针看起来是不能跨进程使用的,以上代码放在 githubgitee 上,可以使用如下命令行拉取代码

先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码

git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin c397b872a4d2cba187e1c04f7b015c8b2ca7092c

以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继续输入以下代码,将 gitee 源换成 github 源进行拉取代码

git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
git pull origin c397b872a4d2cba187e1c04f7b015c8b2ca7092c

获取代码之后,进入 dikalehebeekajaqunicobo 文件夹,即可获取到源代码

尝试自己进程创建 gc 指针,如以下核心代码

intptr window2handle = intptr.zero;
intptr window2gchandle = intptr.zero;

if (args.length == 0)
{
    var currentprocess = process.getcurrentprocess();
    var mainmodulefilename = currentprocess.mainmodule!.filename;
    process.start(mainmodulefilename, [window1.window.tostring(), window1.gc.tostring()]);
}
else if (args.length == 2)
{
    if (long.tryparse(args[0], out var otherprocesswindowhandle))
    {
        window2handle = new intptr(otherprocesswindowhandle);
    }

    //if (long.tryparse(args[1], out var otherprocessgchandle))
    //{
    //    window2gchandle = new intptr(otherprocessgchandle);
    //}
    // 不用别人传的,从窗口进行创建
    window2gchandle = xcreategc(display, window2handle, 0, 0);
    console.writeline($"xcreategc window2 {window2gchandle}");
}

如此代码经过实际测试发现没有任何效果,当然了,也不会导致当前进程挂掉。以上代码放在 githubgitee 上,可以使用如下命令行拉取代码

先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码

git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin f0cb9bd3b4e4e9184fed831bdd84ef7e4b103888

以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继续输入以下代码,将 gitee 源换成 github 源进行拉取代码

git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
git pull origin f0cb9bd3b4e4e9184fed831bdd84ef7e4b103888

获取代码之后,进入 dikalehebeekajaqunicobo 文件夹,即可获取到源代码

更多 x11 开发请参阅 博客导航

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com