Мне нужно обрабатывать изображения, отправленные на видеодисплей моего ноутбука, и мне нужно отправить ввод с клавиатуры в мою систему Linux, используя C ++ или программу оболочки.
Моя цель - обрабатывать изображения, которые являются частью игры FPS, а затем выполнять действия внутри этой игры (следовательно, ввод с клавиатуры) на основе этих изображений. Вместо того, чтобы пытаться понять (если это вообще возможно), как взаимодействовать с игрой X или Y, используя некоторый API, я решил, что это самый быстрый способ взаимодействия с любой игрой, каким-то образом перехватывая ввод и вывод Linux.
Есть ли способ сделать это без взлома ядра или драйверов устройств? Раньше я использовал recordmydesktop для записи своего рабочего стола в виде видео, думаю, я мог бы взломать его код и попытаться что-то из него перепроектировать. Есть другие идеи? Я использую Ubuntu 11.
3 ответа
Наконец-то у меня есть решение. Я считаю, что UrT сам по себе загружает OpenGL, поэтому такие вещи, как wallhacks и т. Д., Невозможны. Тогда лучший оставшийся вариант - это сделать X-скриншоты. Это работало довольно быстро, даже с таким языком сценариев, как Python. Следующий код делает последовательные снимки экрана и отображает их в виде анимации через OpenCV. УрТ, конечно, нужно запускать в свернутом режиме. Остальные детали в моем проекте.
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 чтобы отправить ключ прямого перехода в УрТ,
xdotool search --name ioUrbanTerror windowactivate keydown W
Для этого вам не нужно делать ничего более низкого уровня, чем ядро или драйверы устройств.
Вы можете использовать расширение XTest X11, чтобы программно имитировать события ввода, например (из это сообщение, есть < a href = "http://bharathisubramanian.wordpress.com/2010/03/14/x11-fake-key-event-generation-using-xtest-ext" rel = "nofollow"> другой пример клавиатуры ).
#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
в зависимости от ситуации.
Благодаря ответу @ 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 для этого, любой желающий может разветвляться, помогать и т. Д.
Похожие вопросы
Связанные вопросы
Новые вопросы
linux
ВОПРОСЫ LINUX ДОЛЖНЫ БЫТЬ ПРОГРАММИРОВАНЫ. Используйте этот тег только в том случае, если ваш вопрос касается программирования с использованием API-интерфейсов Linux или специфичного для Linux поведения, а не только потому, что вы случайно запускаете свой код в Linux. Если вам нужна поддержка Linux, вы можете попробовать https://unix.stackexchange.com или сайт Stack Exchange конкретного дистрибутива Linux, например https://askubuntu.com или https://elementaryos.stackexchange.com/.