これを行うために、カーネルやデバイス ドライバーのような低レベルの操作を行う必要はありません。
たとえば、 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;
}
画像をキャプチャする最も簡単な方法は、( を介して)関数の挿入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
ます。