你不需要做任何像内核或设备驱动程序那样低级的事情来做到这一点。
例如,您可以使用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;
}
要捕获图像,最简单的方法是使用函数 interposition (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);
}
然后,您想LD_PRELOAD
在运行您正在查看的任何游戏之前将其编译为共享对象和共享对象。
如果它碰巧是一个 SDL 应用程序,您可以拦截对SDL_Flip
或SDL_UpdateRect
酌情的调用。