捕获显示/监视图像,在Linux上发送键盘输入

BBD*_*Sys 2 linux x11 linux-device-driver linux-kernel function-interposition

我需要处理发送到笔记本电脑视频显示器的图像,我需要使用C++或shell程序将键盘输入发送到我的Linux系统.

我的目标是处理属于FPS游戏的图像,然后根据这些图像在游戏中进行操作(因此键盘输入).我没有尝试理解(如果它甚至可能)如何使用某些API与游戏X或Y进行交互,我认为这是与任何游戏进行交互的最快捷方式,劫持Linux输入和输出.

没有任何内核或设备驱动程序黑客攻击,有没有办法做到这一点?之前我使用recordmydesktop将我的桌面记录为视频,我想我可以破解其代码并尝试从中进行逆向工程.还有其他想法吗?我在Ubuntu 11上.

相关问题

Fle*_*exo 5

您不需要像内核或设备驱动程序那样执行任何操作.

例如,您可以使用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, 0, event.xbutton.x + 100,  
        event.xbutton.y + 50, CurrentTime);  
  XSync(dpy, 0);  
  XCloseDisplay (dpy);  
  return 0;  
}   
Run Code Online (Sandbox Code Playgroud)

要捕获图像,最简单的方法是使用函数插入(via 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);
}
Run Code Online (Sandbox Code Playgroud)

然后你想LD_PRELOAD在运行你正在查看的任何游戏之前将其编译为共享对象和该共享对象.

如果恰好是SDL应用程序,您可以截取SDL_FlipSDL_UpdateRect适当的调用.

  • glReadPixels相对于当前设置的视口.您应首先读取最后设置的视口尺寸(glGetIntegerv(GL_VIEWPORT)),将视口大小设置为窗口尺寸,获取旧读缓冲区(glGetIntegerv(GL_READ_BUFFER)),将读缓冲区设置为GL_BACK,然后调用glReadPixels.之后,将事情恢复到以前的状态. (2认同)