我需要处理发送到笔记本电脑video显示器的图像,并且需要使用C ++或shell程序将键盘input发送到我的Linux系统。
我的目标是处理作为FPS游戏一部分的图像,然后根据这些图像在该游戏内部(因此是键盘input)采取行动。 与其试图理解(如果甚至可能的话)如何使用一些API来连接游戏X或Y,我认为这是连接任何游戏的最快方式,以某种方式劫持Linuxinput和输出。
有没有办法做到这一点没有任何内核,或设备驱动程序黑客? 我以前用recordmydesktop把我的桌面录制成video,我想我可以破解它的代码,并尝试从中反向工程。 任何其他的想法? 我在Ubuntu 11上。
相关问题
您不需要像内核或设备驱动程序那样执行任何操作。
例如,您可以使用XTest X11扩展来伪编程输入事件(从本文来看,还有另一个键盘示例 )。
#include <X11/extensions/XTest.h> #include <unistd.h> int main () { display *dpy = NULL; XEvent event; dpy = XOpendisplay (NULL); /* Get the current pointer position */ XQueryPointer (dpy,Rootwindow (dpy,0),&event.xbutton.root,&event.xbutton.window,&event.xbutton.x_root,&event.xbutton.y_root,&event.xbutton.x,&event.xbutton.y,&event.xbutton.state); /* Fake the pointer movement to new relative position */ XTestFakeMotionEvent (dpy,event.xbutton.x + 100,event.xbutton.y + 50,CurrentTime); XSync(dpy,0); XClosedisplay (dpy); return 0; }
要捕捉图像,最简单的方法是使用函数插入 (通过LD_PRELOAD )来截取对glXSwapBuffers调用,每画出一帧,将调用glXSwapBuffers 。 从那里你可以复制framebuffer的内容,使用glreadPixels和做你想要的。
例如截取OpenGL帧的未经测试的轮廓 :
// Function pointer to the *real* glXSwapBuffers static void (*glx_fptr)(display*,GLXDrawable) = NULL; // Make sure init gets called when the shared object is loaded. GCC specific. static void init(void) __attribute__((constructor)); static void init(void) { dlerror(); // find the real glXSwapBuffers glx_fptr = dlsym(RTLD_NEXT,"glXSwapBuffers"); if (NULL == glx_fptr) fprintf(stderr,"[glvidcap] %sn",dlerror()); } void glXSwapBuffers(display *dpy,GLXDrawable drawable) { unsigned int w = 0; unsigned int h = 0; static int x,y; static Window win; static unsigned int border,depth; // Find the window size. (You Could skip this and make it all static if you // Trust the window not to change size XGetGeometry(dpy,drawable,&win,&x,&y,&w,&h,&border,&depth); // Assuming frame is some memory you want the frame dumped to: glreadPixels(0,w,h,GL_BGR,GL_UNSIGNED_BYTE,frame); // Call the real function: assert(glx_fptr); glx_fptr(dpy,drawable); }
然后你想在运行你正在看的任何游戏之前把它编译成共享对象和共享对象的LD_PRELOAD 。
如果碰巧是SDL应用程序,则可以根据需要拦截对SDL_Flip或SDL_UpdateRect的调用。
感谢@ awoodland的回答,我查找了相关资源,并发现了这一点
http://bzr.sesse.net/glcapture/glcapture.c
我编译这个代码为
gcc -shared -fPIC -o glcapture.so glcapture.c -ldl
并将其加载到FPS游戏Urban Terror中作为脚本
LD_PRELOAD=`pwd`/glcapture.so [DIR]/UrbanTerror/IoUrbanTerror.i386
这个脚本运行的那一刻,游戏被加载。 出于某种原因,游戏图形不显示,但我可以稍后改进。 当我退出游戏时,我看到控制台上打印的gettimeofday消息,告诉我钩子已经工作。 我将继续处理此代码,以提供更多详细信息。
发送按键,我跟着链接
http://bharathisubramanian.wordpress.com/2010/03/14/x11-fake-key-event-generation-using-xtest-ext/
在Ubuntu上安装了必要的软件包之后
sudo apt-get install libxtst-dev
然后fakeKey.c编译和工作没有问题。
注意:我在Github上为此启动了一个项目 ,欢迎任何人分叉,协助等等。
我终于有了一个解决方案。 我相信UrT自己加载OpenGL,所以像wallhacks等东西是不可能的。 那么最好的剩余选项是X截图。 这工作得非常快,甚至从像Python这样的脚本语言。 以下代码将连续执行截图,并通过OpenCV将其显示为动画。 你需要以最小化模式启动UrT。 其余的细节在我的项目 。
import gtk.gdk import PIL from opencv.cv import * from opencv.highgui import * from opencv.adaptors import PIL2Ipl w = gtk.gdk.get_default_root_window() sz = w.get_size() print "The size of the window is %dx %d" % sz size_x = 600 size_y = 400 start_x = 0 start_y = 100 end_x = start_x+size_x end_y = start_y+size_y Box = (start_x,start_y,start_x+size_x,start_y+size_y) while True: pb = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB,False,8,sz[0],sz[1]) pb = pb.get_from_drawable(w,w.get_colormap(),sz[1]) width,height = pb.get_width(),pb.get_height() im = PIL.Image.fromstring("RGB",(width,height),pb.get_pixels()) im = im.crop(Box) cv_img = PIL2Ipl(im) cvNamedWindow("fps") cvShowImage("fps",cv_img) cvWaitKey(30)
此外,为了发送密钥到游戏中,上面的方法不起作用,我不得不使用xdotool来向前发送漫游密钥到UrT,
xdotool search --name IoUrbanTerror windowactivate keydown W
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。