summaryrefslogtreecommitdiff
path: root/play.cpp
blob: b1157e01e778434166bfb8b3ddd7094aab5017e1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <X11/Xlib.h>
#include <X11/extensions/XInput.h>
#ifdef HAVE_XI2
#include <X11/extensions/XInput2.h>
#endif
#include <X11/XKBlib.h>

#define class _class
extern "C" {
#include <xdo.h>
};
#undef class

#include "global.h"
#include "rec.h"

Rect get_win_pos(Window win)
{
	Rect r;
	Window child;
	XWindowAttributes attr;
	XGetWindowAttributes(dpy, win, &attr);

	if (!XTranslateCoordinates(dpy, win, attr.root, 0, 0, &r.x, &r.y, &child)) {
		fprintf(stderr, "Error XTranslateCoordinates\n");
		exit(EXIT_FAILURE);
	}

	r.width = attr.width;
	r.height = attr.height;
	return r;
}

void play(const char *fn, Window win)
{
	Window target_win = 0;

	if (win == 0) {
		fprintf (stderr, "play mode require a window to be specified\n");
		exit(EXIT_FAILURE);
	}

	xdo_t *xdo = xdo_new_with_opened_display(dpy, NULL, False);

	Rect rc = get_win_pos(win);

	ReadRecordsFile file(fn);

	unsigned prev_time = 0;
	while (!file.at_eof()) {
		const Record rec = file.get();

		unsigned tm = rec.get_time();
		if (prev_time) {
			unsigned diff = tm - prev_time;
			struct timespec ts = { diff / 1000u, diff % 1000u * 1000000u };
			nanosleep(&ts, NULL);
		}
		prev_time = tm;

		XEvent ev;
		memset(&ev, 0, sizeof(ev));
		ev.xkey.display = dpy;
		ev.xkey.window = win;
		ev.xkey.time = CurrentTime;
		ev.xkey.root = DefaultRootWindow(dpy);

		switch (rec.get_type()) {
		case Record::KeyDown:
			ev.type = KeyPress;
			goto keyboard;
		case Record::KeyUp:
			ev.type = KeyRelease;
		keyboard:
			if (rec.get_field(Record::Window, 0) != target_win)
				break;
			ev.xkey.x = rec.get_field(Record::X);
			ev.xkey.y = rec.get_field(Record::Y);
			ev.xkey.x_root = ev.xkey.x + rc.x;
			ev.xkey.y_root = ev.xkey.y + rc.y;
			ev.xkey.state = rec.get_field(Record::State);
			ev.xkey.keycode = rec.get_field(Record::Detail);
			ev.xkey.same_screen = True;
//			XSendEvent(dpy, win, True, KeyPressMask, &ev);
			XSendEvent(dpy, win, False, 0, &ev);
			XFlush(dpy);
			break;
		case Record::ButtonDown:
			if (rec.get_field(Record::Window, 0) != target_win)
				break;
			xdo_mousedown(xdo, 0, rec.get_field(Record::Detail));
			break;

		case Record::ButtonUp:
			if (rec.get_field(Record::Window, 0) != target_win)
				break;
			xdo_mouseup(xdo, 0, rec.get_field(Record::Detail));
			break;

		case Record::MouseMotion:
			if (rec.get_field(Record::Window, 0) != target_win)
				break;
			xdo_mousemove_relative_to_window(xdo, win, rec.get_field(Record::X), rec.get_field(Record::Y));
			break;

		case Record::TargetWindow:
			target_win = rec.get_field(Record::Window);
			break;

		case Record::WindowMove:
			xdo_window_move(xdo, win, rec.get_field(Record::X), rec.get_field(Record::Y));
			break;
		default:
			fprintf (stderr, "unknown type %u\n", rec.get_type());
			exit(EXIT_FAILURE);
		}
		XFlush(dpy);
	}

	xdo_free(xdo);
}