diff options
-rw-r--r-- | play.cpp | 10 | ||||
-rw-r--r-- | rec.cpp | 177 | ||||
-rw-r--r-- | rec.h | 27 | ||||
-rw-r--r-- | record.cpp | 22 |
4 files changed, 164 insertions, 72 deletions
@@ -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)); @@ -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"); } - @@ -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); }; @@ -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); |