summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--play.cpp10
-rw-r--r--rec.cpp177
-rw-r--r--rec.h27
-rw-r--r--record.cpp22
4 files changed, 164 insertions, 72 deletions
diff --git a/play.cpp b/play.cpp
index 8ee5b02..b1157e0 100644
--- a/play.cpp
+++ b/play.cpp
@@ -72,10 +72,10 @@ void play(const char *fn, Window win)
ev.xkey.root = DefaultRootWindow(dpy);
switch (rec.get_type()) {
- case XI_KeyPress:
+ case Record::KeyDown:
ev.type = KeyPress;
goto keyboard;
- case XI_KeyRelease:
+ case Record::KeyUp:
ev.type = KeyRelease;
keyboard:
if (rec.get_field(Record::Window, 0) != target_win)
@@ -91,19 +91,19 @@ void play(const char *fn, Window win)
XSendEvent(dpy, win, False, 0, &ev);
XFlush(dpy);
break;
- case XI_ButtonPress:
+ case Record::ButtonDown:
if (rec.get_field(Record::Window, 0) != target_win)
break;
xdo_mousedown(xdo, 0, rec.get_field(Record::Detail));
break;
- case XI_ButtonRelease:
+ case Record::ButtonUp:
if (rec.get_field(Record::Window, 0) != target_win)
break;
xdo_mouseup(xdo, 0, rec.get_field(Record::Detail));
break;
- case XI_Motion:
+ 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));
diff --git a/rec.cpp b/rec.cpp
index 70c37cf..7f4fd83 100644
--- a/rec.cpp
+++ b/rec.cpp
@@ -1,9 +1,67 @@
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include "rec.h"
+#define FIELD_TYPES \
+ FIELD(X, "x") \
+ FIELD(Y, "y") \
+ FIELD(State, "state") \
+ FIELD(Detail, "detail") \
+ FIELD(Window, "win") \
+ FIELD(Width, "w") \
+ FIELD(Height, "h") \
+ FIELD(Keysym, "keysym")
+
+const char *Record::get_field_name(FieldsType type)
+{
+#define FIELD(t,n) case t: return n;
+ switch (type) {
+ FIELD_TYPES
+ }
+#undef FIELD
+ return "";
+}
+
+Record::FieldsType Record::get_field_type(const char *name)
+{
+#define FIELD(t,n) if (strcmp(name, n) == 0) return t;
+ FIELD_TYPES
+#undef FIELD
+ fprintf(stderr, "Invalid field type %s\n", name);
+ exit(EXIT_FAILURE);
+}
+
+#define RECORD_TYPES \
+ RECORD(KeyDown, "key_down") \
+ RECORD(KeyUp, "key_up") \
+ RECORD(ButtonDown, "button_down") \
+ RECORD(ButtonUp, "button_up") \
+ RECORD(MouseMotion, "mouse_move") \
+ RECORD(WindowMove, "window_move") \
+ RECORD(TargetWindow, "target_window")
+
+const char *Record::get_record_name(RecordType type)
+{
+#define RECORD(t,n) case t: return n;
+ switch (type) {
+ RECORD_TYPES
+ }
+#undef RECORD
+ return "";
+}
+
+Record::RecordType Record::get_record_type(const char *name)
+{
+#define RECORD(t,n) if (strcmp(name, n) == 0) return t;
+ RECORD_TYPES
+#undef RECORD
+ fprintf(stderr, "Invalid record type\n");
+ exit(EXIT_FAILURE);
+}
+
RecordsFile::RecordsFile(FILE *_f):
f(_f)
{
@@ -14,91 +72,100 @@ RecordsFile::RecordsFile(FILE *_f):
}
ReadRecordsFile::ReadRecordsFile(const char *fn):
- RecordsFile(fopen(fn, "rb")),
- eof(false), next(0)
+ RecordsFile(fopen(fn, "r")),
+ eof(false)
{
- get_number();
+ get_line();
}
-Record ReadRecordsFile::get()
-{
- get_number(START_RECORD);
- unsigned type = get_number();
- unsigned time = get_number();
-
- Record rec(type, time);
- for (;;) {
- type = get_number();
- if (type == END_RECORD)
- return rec;
- if (type != FIELD) {
- fprintf(stderr, "expected a field!\n");
- exit(EXIT_FAILURE);
- }
- type = get_number();
- if (type >= Record::MAX_FIELD) {
- fprintf(stderr, "invalid field type!\n");
- exit(EXIT_FAILURE);
- }
- rec.set_field((Record::FieldsType) type, get_number());
- }
-}
+#define SPACES " \t\v\r\n"
-unsigned
-ReadRecordsFile::get_number()
+void ReadRecordsFile::get_line()
{
if (eof) {
fprintf(stderr, "trying to read past EOF\n");
exit(EXIT_FAILURE);
}
- unsigned res = next;
- if (fread(&next, sizeof(next), 1, f) != 1) {
- if (!feof(f)) {
- fprintf (stderr, "end of file\n");
- exit(EXIT_FAILURE);
- }
- eof = true;
+ while (fgets(next_line, sizeof(next_line), f)) {
+ const char *p = next_line;
+
+ // skip initial spaces
+ p += strspn(p, SPACES);
+
+ // detect comments
+ if (!*p || *p == '#')
+ continue;
+
+ // got line
+ return;
}
- return res;
+
+ if (!feof(f)) {
+ fprintf (stderr, "error reading input file\n");
+ exit(EXIT_FAILURE);
+ }
+ eof = true;
}
-void
-ReadRecordsFile::get_number(unsigned n)
+Record ReadRecordsFile::get()
{
- if (get_number() != n) {
- fprintf (stderr, "expected %u in file position %lx\n", n, (unsigned long) ftell(f));
+ char *line = next_line;
+
+ // skip initial spaces
+ line += strspn(line, SPACES);
+
+ // read time and command
+ int got = 0;
+ unsigned time;
+ char cmd[64];
+ if (sscanf(line, "@%u %60[^" SPACES "]%n", &time, cmd, &got) < 2) {
+ fprintf (stderr, "error reading time: %s\n", next_line);
exit(EXIT_FAILURE);
}
-}
+ Record::RecordType type = Record::get_record_type(cmd);
+ Record rec(type, time);
+
+ char *p = line + got;
+ for (;;) {
+ char field[64];
+ unsigned value;
+
+ p += strspn(p, SPACES);
+ if (!*p)
+ break;
+ got = 0;
+ if (sscanf(p, "%60[^:]:%u%n", field, &value, &got) < 2 || got == 0) {
+ fprintf(stderr, "expected a field: %s\n", next_line);
+ exit(EXIT_FAILURE);
+ }
+ p += got;
+
+ Record::FieldsType type = Record::get_field_type(field);
+ rec.set_field(type, value);
+ }
+ get_line();
+ return rec;
+}
+
WriteRecordsFile::WriteRecordsFile(const char *fn):
- RecordsFile(fopen(fn, "wb"))
+ RecordsFile(fopen(fn, "w"))
{
}
void WriteRecordsFile::put(const Record &rec)
{
- add_number(START_RECORD);
- add_number(rec.get_type());
- add_number(rec.get_time());
+ fprintf(f, "@%u %s", rec.get_time(), rec.get_record_name(rec.get_type()));
for (unsigned n = 0; n < Record::MAX_FIELD; ++n) {
Record::FieldsType type = (Record::FieldsType) n;
if (!rec.has_field(type))
continue;
- add_number(FIELD);
- add_number(type);
- add_number(rec.get_field(type));
+ fprintf(f, " %s:%u", rec.get_field_name(type), rec.get_field(type));
}
- add_number(END_RECORD);
-}
-
-void WriteRecordsFile::add_number(unsigned num)
-{
- fwrite(&num, sizeof(num), 1, f);
+ fprintf(f, "\n");
}
-
diff --git a/rec.h b/rec.h
index 3406f02..ae63b79 100644
--- a/rec.h
+++ b/rec.h
@@ -5,13 +5,23 @@ class Record
{
public:
enum FieldsType { Nothing, X, Y, State, Detail, Window, Width, Height, Keysym, MAX_FIELD };
- enum RecordType { WindowMove = 256, TargetWindow };
- Record(unsigned _type, unsigned _time):
+ static const char *get_field_name(FieldsType type);
+ static FieldsType get_field_type(const char *name);
+
+ enum RecordType {
+ KeyDown, KeyUp,
+ ButtonDown, ButtonUp, MouseMotion,
+ WindowMove = 256, TargetWindow
+ };
+ static const char *get_record_name(RecordType type);
+ static RecordType get_record_type(const char *name);
+
+ Record(RecordType _type, unsigned _time):
fields_present(0), type(_type), time(_time)
{
}
~Record() { }
- unsigned get_type() const { return type; }
+ RecordType get_type() const { return type; }
unsigned get_time() const { return time; }
bool has_field(FieldsType type) const { return ((fields_present >> type) & 1) != 0; }
unsigned get_field(FieldsType type) const {
@@ -31,7 +41,8 @@ public:
fields[type] = value;
}
private:
- unsigned type, time;
+ RecordType type;
+ unsigned time;
unsigned fields_present;
unsigned fields[MAX_FIELD];
};
@@ -42,7 +53,6 @@ protected:
RecordsFile(FILE *_f);
~RecordsFile() { fclose(f); }
- enum { START_RECORD = 1, END_RECORD = 2, FIELD = 3 };
FILE *f;
};
@@ -53,11 +63,10 @@ public:
bool at_eof() const { return eof; }
Record get();
private:
- unsigned get_number();
- void get_number(unsigned num);
+ void get_line();
bool eof;
- unsigned next;
+ char next_line[1024];
};
class WriteRecordsFile: public RecordsFile
@@ -65,7 +74,5 @@ class WriteRecordsFile: public RecordsFile
public:
WriteRecordsFile(const char *fn);
void put(const Record &rec);
-private:
- void add_number(unsigned num);
};
diff --git a/record.cpp b/record.cpp
index 92da9e6..80c3846 100644
--- a/record.cpp
+++ b/record.cpp
@@ -107,6 +107,24 @@ DoRecord::record_move()
file.put(r);
}
+static Record::RecordType get_record_type(int evtype)
+{
+ switch (evtype) {
+ case XI_KeyPress:
+ return Record::KeyDown;
+ case XI_KeyRelease:
+ return Record::KeyUp;
+ case XI_ButtonPress:
+ return Record::ButtonDown;
+ case XI_ButtonRelease:
+ return Record::ButtonUp;
+ case XI_Motion:
+ return Record::MouseMotion;
+ }
+ fprintf (stderr, "unhandled event\n");
+ exit(EXIT_FAILURE);
+}
+
void
DoRecord::handle_xi_mouse(XIDeviceEvent* ev)
{
@@ -121,7 +139,7 @@ DoRecord::handle_xi_mouse(XIDeviceEvent* ev)
if (!inside)
return;
- Record r(ev->evtype, get_record_time());
+ Record r(get_record_type(ev->evtype), get_record_time());
r.set_field(Record::X, mouse_x - rc.x);
r.set_field(Record::Y, mouse_y - rc.y);
r.set_field(Record::State, ev->mods.effective);
@@ -136,7 +154,7 @@ DoRecord::handle_xi_mouse(XIDeviceEvent* ev)
void
DoRecord::handle_xi_keys(XIDeviceEvent* ev)
{
- Record r(ev->evtype, get_record_time());
+ Record r(get_record_type(ev->evtype), get_record_time());
r.set_field(Record::X, ev->root_x - rc.x);
r.set_field(Record::Y, ev->root_y - rc.y);
r.set_field(Record::State, ev->mods.effective);