我需要处理发送到笔记本电脑的视频显示器上的图像,并且需要使用C++或shell程序将键盘输入发送到我的Linux系统。
我的目标是处理FPS游戏中的图像,然后根据这些图像在游戏中采取行动(因此需要键盘输入)。使用一些API,而不是试图理解(如果可能的话)如何连接到游戏X或Y,我认为这是连接到任何游戏的最快方法,以某种方式劫持Linux输入和输出。
有没有办法做到这一点,而没有任何内核,或设备驱动程序黑客?我之前使用recordmydesktop将我的桌面录制为视频,我想我可以破解它的代码,并尝试从中逆向工程一些东西。还有其他想法吗?我在Ubuntu 11上。
发布于 2011-10-11 20:58:14
我终于有了一个解决方案。我相信UrT会自己加载OpenGL,所以像wallhacks之类的东西是不可能的。那么剩下的最好的选择就是拍摄X截图。即使是在Python这样的脚本语言中,这也是非常快的。下面的代码获取连续的屏幕截图,并通过OpenCV将它们显示为动画。当然,您需要在最小化模式下启动UrT。The rest of the details are in my project。
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 %d x %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(),0,0,0,0,sz[0],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发布于 2011-08-28 22:40:51
要做到这一点,你不需要做任何像内核或设备驱动程序这样的底层工作。
例如,您可以使用XTest X11 extension以编程方式伪造输入事件(来自this posting的another example for keyboard)。
#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, 0, event.xbutton.x + 100,
event.xbutton.y + 50, CurrentTime);
XSync(dpy, 0);
XCloseDisplay (dpy);
return 0;
} 要捕获图像,最简单的方法是使用function interposition (通过LD_PRELOAD)“拦截”对glXSwapBuffers的调用,该调用将在每一帧绘制完成后被调用。在那里,您可以使用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] %s\n", 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,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的调用。
发布于 2011-08-29 03:46:39
感谢@awoodland的回答,我查找了相关资源,并找到了以下内容
http://bzr.sesse.net/glcapture/glcapture.c
我将这段代码编译为
gcc -shared -fPIC -o glcapture.so glcapture.c -ldl并在脚本中为FPS游戏script加载它
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编译并正常工作。
注意:I started a project on Github for this,欢迎任何人使用fork,help等。
https://stackoverflow.com/questions/7221600
复制相似问题