Skip to content

Instantly share code, notes, and snippets.

@richard-to
Created April 7, 2014 10:30
Show Gist options
  • Save richard-to/10017943 to your computer and use it in GitHub Desktop.
Save richard-to/10017943 to your computer and use it in GitHub Desktop.
X11 Example code for grabbing screenshots of window and sending key events
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
using namespace cv;
using namespace std;
#define ACTIVE_WINDOWS "_NET_CLIENT_LIST"
#define WINDOW_TITLE "Wolf3d Screenshot"
#define WINDOW_DOXBOX "DOSBox"
// Find the DOSBox Window so we can do cool stuff with it!
bool findDOSBoxWindow(Display *display, Window &window)
{
bool found = false;
Window rootWindow = RootWindow(display, DefaultScreen(display));
Atom atom = XInternAtom(display, ACTIVE_WINDOWS, true);
Atom actualType;
int format;
unsigned long numItems;
unsigned long bytesAfter;
unsigned char *data = '\0';
Window *list;
char *windowName;
int status = XGetWindowProperty(display, rootWindow, atom, 0L, (~0L), false,
AnyPropertyType, &actualType, &format, &numItems, &bytesAfter, &data);
list = (Window *)data;
if (status >= Success && numItems) {
for (int i = 0; i < numItems; ++i) {
status = XFetchName(display, list[i], &windowName);
if (status >= Success) {
string windowNameStr(windowName);
if (windowNameStr.find(WINDOW_DOXBOX) == 0) {
window = list[i];
found = true;
break;
}
}
}
}
XFree(windowName);
XFree(data);
return found;
}
int main(int argc, char *argv[])
{
Display *display = XOpenDisplay(NULL);
Window rootWindow = RootWindow(display, DefaultScreen(display));
Window DOSBoxWindow;
XWindowAttributes DOSBoxWindowAttributes;
if (findDOSBoxWindow(display, DOSBoxWindow) == false) {
printf("Error: Cannot find DOSBox window. Exiting program.");
return 0;
}
XGetWindowAttributes(display, DOSBoxWindow, &DOSBoxWindowAttributes);
int width = DOSBoxWindowAttributes.width;
int height = DOSBoxWindowAttributes.height;
namedWindow(WINDOW_TITLE, WINDOW_AUTOSIZE);
Mat frame = Mat::zeros(height, width, CV_8UC3);
Vec3b frameRGB;
XColor colors;
XImage *image;
unsigned long red_mask;
unsigned long green_mask;
unsigned long blue_mask;
while (true) {
image = XGetImage(
display, DOSBoxWindow, 0, 0, width, height, AllPlanes, ZPixmap);
red_mask = image->red_mask;
green_mask = image->green_mask;
blue_mask = image->blue_mask;
for (int i = 0; i < height; ++i) {
for (int j = 0; j < width; ++j) {
colors.pixel = XGetPixel(image, j, i);
// TODO(richard-to): Figure out why red and blue are swapped
frameRGB = frame.at<Vec3b>(i, j);
frameRGB.val[0] = colors.pixel & blue_mask;
frameRGB.val[1] = (colors.pixel & green_mask) >> 8;
frameRGB.val[2] = (colors.pixel & red_mask) >> 16;
frame.at<Vec3b>(i, j) = frameRGB;
}
}
XFree(image);
imshow(WINDOW_TITLE, frame);
if (waitKey(10) >= 0) {
break;
}
}
}
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
using namespace cv;
using namespace std;
#define ACTIVE_WINDOWS "_NET_CLIENT_LIST"
#define WINDOW_TITLE "Wolf3d Screenshot"
#define WINDOW_DOXBOX "DOSBox"
// Find the DOSBox Window so we can do cool stuff with it!
bool findDOSBoxWindow(Display *display, Window &window)
{
bool found = false;
Window rootWindow = RootWindow(display, DefaultScreen(display));
Atom atom = XInternAtom(display, ACTIVE_WINDOWS, true);
Atom actualType;
int format;
unsigned long numItems;
unsigned long bytesAfter;
unsigned char *data = '\0';
Window *list;
char *windowName;
int status = XGetWindowProperty(display, rootWindow, atom, 0L, (~0L), false,
AnyPropertyType, &actualType, &format, &numItems, &bytesAfter, &data);
list = (Window *)data;
if (status >= Success && numItems) {
for (int i = 0; i < numItems; ++i) {
status = XFetchName(display, list[i], &windowName);
if (status >= Success) {
string windowNameStr(windowName);
if (windowNameStr.find(WINDOW_DOXBOX) == 0) {
window = list[i];
found = true;
break;
}
}
}
}
XFree(windowName);
XFree(data);
return found;
}
void millisleep(int ms)
{
usleep(ms * 1000);
}
int main(int argc, char *argv[])
{
Display *display = XOpenDisplay(NULL);
Window rootWindow = RootWindow(display, DefaultScreen(display));
Window DOSBoxWindow;
XWindowAttributes DOSBoxWindowAttributes;
if (findDOSBoxWindow(display, DOSBoxWindow) == false) {
printf("Error: Cannot find DOSBox window. Exiting program.");
return 0;
}
XKeyEvent event;
event.type = KeyPress;
event.display = display;
event.send_event = False;
event.window = DOSBoxWindow;
event.root = rootWindow;
event.time = CurrentTime;
event.same_screen = True;
event.keycode = XKeysymToKeycode(display, XK_Up);
XSendEvent(display, DOSBoxWindow, True, KeyPressMask, (XEvent *)&event);
XFlush(display);
millisleep(100);
event.type = KeyRelease;
XSendEvent(display, DOSBoxWindow, True, KeyReleaseMask, (XEvent *)&event);
XFlush(display);
}
@shaggyrogers
Copy link

Thanks! You need to use XDestroyImage(image), not XFree(image), since the latter doesn't free the image data.

Also, instead of finding the window by name, it's easier to use xwininfo to get the ID and pass it as an argument, which you can then just cast to Window:

./screenshot_window $(xwininfo -int -name "Window Name" | grep -oP "(?<=Window id: )\d+")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment