首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >捕获显示/监视器图像,在Linux上发送键盘输入

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

Stack Overflow用户
提问于 2011-08-28 22:34:50
回答 3查看 1.3K关注 0票数 2

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

我的目标是处理FPS游戏中的图像,然后根据这些图像在游戏中采取行动(因此需要键盘输入)。使用一些API,而不是试图理解(如果可能的话)如何连接到游戏X或Y,我认为这是连接到任何游戏的最快方法,以某种方式劫持Linux输入和输出。

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

Related Question

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-10-11 20:58:14

我终于有了一个解决方案。我相信UrT会自己加载OpenGL,所以像wallhacks之类的东西是不可能的。那么剩下的最好的选择就是拍摄X截图。即使是在Python这样的脚本语言中,这也是非常快的。下面的代码获取连续的屏幕截图,并通过OpenCV将它们显示为动画。当然,您需要在最小化模式下启动UrT。The rest of the details are in my project

代码语言:javascript
复制
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发送前进漫游密钥。

代码语言:javascript
复制
xdotool search --name ioUrbanTerror  windowactivate keydown W
票数 0
EN

Stack Overflow用户

发布于 2011-08-28 22:40:51

要做到这一点,你不需要做任何像内核或设备驱动程序这样的底层工作。

例如,您可以使用XTest X11 extension以编程方式伪造输入事件(来自this postinganother example for keyboard)。

代码语言:javascript
复制
#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帧的未经测试的大纲:

代码语言:javascript
复制
// 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的调用。

票数 5
EN

Stack Overflow用户

发布于 2011-08-29 03:46:39

感谢@awoodland的回答,我查找了相关资源,并找到了以下内容

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

我将这段代码编译为

代码语言:javascript
复制
gcc -shared -fPIC -o glcapture.so glcapture.c -ldl

并在脚本中为FPS游戏script加载它

代码语言:javascript
复制
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安装了必要的包之后

代码语言:javascript
复制
sudo apt-get install libxtst-dev

然后fakeKey.c编译并正常工作。

注意:I started a project on Github for this,欢迎任何人使用fork,help等。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7221600

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档