IT评测·应用市场-qidao123.com技术社区
标题:
dotnet X11 窗口之间发送鼠标消息 模仿鼠标输入
[打印本页]
作者:
科技颠覆者
时间:
2024-5-20 05:25
标题:
dotnet 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 代码仓库里面抄的,所有代码放在
github
和
gitee
上,可以使用如下下令行拉代替码
先创建一个空文件夹,接着使用下令行 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; }
}
复制代码
以上代码放在
github
和
gitee
上,可以使用如下下令行拉代替码
先创建一个空文件夹,接着使用下令行 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);
}
}
}
复制代码
放在
github
和
gitee
上,可以使用如下下令行拉代替码
先创建一个空文件夹,接着使用下令行 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 指针看起来是不能跨历程使用的,以上代码放在
github
和
gitee
上,可以使用如下下令行拉代替码
先创建一个空文件夹,接着使用下令行 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}");
}
复制代码
云云代码颠末实际测试发现没有任何效果,固然了,也不会导致当前历程挂掉。以上代码放在
github
和
gitee
上,可以使用如下下令行拉代替码
先创建一个空文件夹,接着使用下令行 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 开发请参阅
博客导航
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
欢迎光临 IT评测·应用市场-qidao123.com技术社区 (https://dis.qidao123.com/)
Powered by Discuz! X3.4