Захват изображения дисплея / монитора, отправка ввода с клавиатуры на Linux - PullRequest
2 голосов
/ 28 августа 2011

Мне нужно обработать изображения, отправленные на видеодисплей моего ноутбука, и мне нужно отправить ввод с клавиатуры в мою систему Linux, используя C ++ или программу оболочки.

Моя цель - обработать изображения, являющиеся частью игры FPS, а затем выполнить действия внутри этой игры (отсюда и ввод с клавиатуры) на основе этих изображений. Вместо того, чтобы пытаться понять (если это вообще возможно), как взаимодействовать с игрой X или Y, используя какой-то API, я решил, что это самый быстрый способ взаимодействия с любой игрой, каким-то образом угоняющий ввод и вывод Linux.

Есть ли способ сделать это без какого-либо ядра или взлома драйвера устройства? Раньше я использовал recordmydesktop для записи своего рабочего стола как видео, думаю, я мог бы взломать его код и попытаться что-то из этого перепроектировать. Есть еще идеи? Я на Ubuntu 11.

Смежный вопрос

Ответы [ 3 ]

5 голосов
/ 28 августа 2011

Вам не нужно делать ничего более низкого уровня, чем ядро ​​или драйверы устройств, чтобы сделать это.

Вы можете использовать расширение 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, в зависимости от ситуации.

1 голос
/ 28 августа 2011

Благодаря ответу @ awoodland я искал соответствующие ресурсы и нашел это

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

Я скомпилировал этот код как

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

и загрузил егодля FPS игра Urban Terror в скрипте как

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 с помощью

sudo apt-get install libxtst-dev

Затем fakeKey.c скомпилировал и работал без проблем.

Примечание: я запустил проект на Github для этого , любой желающий может получить ответвление, помочь и т. Д.

0 голосов
/ 11 октября 2011

У меня наконец есть решение.Я считаю, что UrT загружает OpenGL самостоятельно, поэтому такие вещи, как взломы и т. Д. Невозможны.Тогда лучший оставшийся вариант - сделать X скриншотов.Это работало довольно быстро, даже с использованием скриптового языка, такого как Python.Следующий код делает последовательные снимки экрана и отображает их в виде анимации через OpenCV.Вы должны запустить UrT в свернутом режиме, конечно. Остальные детали находятся в моем проекте .

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
...