2

我需要处理发送到笔记本电脑视频显示器的图像,并且需要使用C++或shell程序将键盘输入发送到我的Linux系统。捕获显示/监视器图像,在Linux上发送键盘输入

我的目标是处理作为FPS游戏一部分的图像,然后根据这些图像在该游戏中(因此是键盘输入)采取行动。与其试图理解(如果甚至可能的话)如何使用某些API与游戏X或Y进行交互,我认为这是与任何游戏接口的最快方式,以某种方式劫持Linux输入和输出。

有没有办法做到这一点没有任何内核,或设备驱动程序黑客?我以前使用recordmydesktop将我的桌面录制为视频,我想我可以破解它的代码并尝试从中反向设计一些东西。任何其他想法?我在Ubuntu 11

Related Question

回答

0

我终于有了一个解决方案。我相信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 
+0

如果直接使用'dlopen()'加载OpenGL,您仍然可以用自己的libGL.so替换/ usr/lib中的libGL.so,尽管您的解决方案可能比此更简单。 – Flexo

+0

你可能是对的。我不得不进入更多的C编码,我想我会继续解决我的问题。性能不算太差,令人惊讶。 – user423805

5

你不需要做任何事情为低电平,内核或设备驱动程序来做到这一点。

您可以使用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,并用它做你想要的。

E.g.拦截的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_FlipSDL_UpdateRect的调用。

+2

glReadPixels相对于当前设置视口。您应该先读取最后一组视口尺寸(glGetIntegerv(GL_VIEWPORT)),将视口尺寸设置为窗口尺寸,获取旧读取缓冲区,(glGetIntegerv(GL_READ_BUFFER)),将读取缓冲区设置为GL_BACK,然后调用glReadPixels。之后,将事情恢复到之前的状态。 – datenwolf

+0

@awoodland,使用演示OpenGL代码,我可以使用glcapture捕获和编写图像文件。在UrbanTerror上,只有gettimeofday被调用,glXSwapBuffers不是。你有什么想法,为什么这可能是?我的代码在这里 - http://goo.gl/Gxyha – user423805

+0

@ user423805 - 我猜想这是做一些替代调用,而不是只是swapbuffers。您可能可以弄清楚用什么来嗅探X11呼叫,例如http://xmsgtrace.sourceforge.net/或http://www.x.org/archive/X11R7.5/doc/man/man1/xscope.1.html,但它们可能不适用于OpenGL应用程序。 – Flexo

1

感谢@ awoodland的答案,我找了相关资源,并发现这个

http://bzr.sesse.net/glcapture/glcapture.c

我编译此代码为

gcc -shared -fPIC -o glcapture.so glcapture.c -ldl 

,并在加载它的FPS游戏城市恐怖脚本为

LD_PRELOAD=`pwd`/glcapture.so [DIR]/UrbanTerror/ioUrbanTerror.i386 

此脚本运行的那一刻,游戏被加载。出于某种原因,游戏图形不显示,但我可以在以后改进。当我退出游戏时,我看到控制台上印有gettimeofday消息,这告诉我钩子已经工作。随着我继续使用此代码,我会提供更多详细信息。

要发送的按键,我跟着我安装后必要的包在Ubuntu与

sudo apt-get install libxtst-dev 

然后fakeKey.c编译,没有问题工作的链接

http://bharathisubramanian.wordpress.com/2010/03/14/x11-fake-key-event-generation-using-xtest-ext/

注:我started a project on Github for this,欢迎任何人到餐桌,帮助等