49 virtual ~Display() { |
49 virtual ~Display() { |
50 if (display) XCloseDisplay(display); |
50 if (display) XCloseDisplay(display); |
51 } |
51 } |
52 }; |
52 }; |
53 |
53 |
|
54 class Event { |
|
55 public: |
|
56 |
|
57 enum class Type { |
|
58 KEY, |
|
59 BUTTON, |
|
60 MOTION, |
|
61 UNKNOWN |
|
62 }; |
|
63 |
|
64 enum class State { |
|
65 PRESSED, |
|
66 RELEASED, |
|
67 UNKNOWN |
|
68 }; |
|
69 |
|
70 Type type = Type::UNKNOWN; |
|
71 State state = State::UNKNOWN; |
|
72 int key = -1; |
|
73 int button = -1; |
|
74 unsigned long screen = 0; |
|
75 unsigned long delay = 1; |
|
76 int x = -1; |
|
77 int y = -1; |
|
78 } currentEvent; |
|
79 |
54 Display display; |
80 Display display; |
55 std::ostream& output; // TODO: remove |
|
56 Configuration& configuration; |
81 Configuration& configuration; |
57 const char QUOTE = '"'; // TODO: remove |
|
58 std::wstring_convert<std::codecvt_utf8<wchar_t>> convertor; // TODO: probably not needed |
82 std::wstring_convert<std::codecvt_utf8<wchar_t>> convertor; // TODO: probably not needed |
59 std::vector<relpipe::reader::handlers::AttributeMetadata> firstAttributes; |
83 std::vector<relpipe::reader::handlers::AttributeMetadata> attributes; |
60 relpipe::common::type::Integer valueCount = 0; |
84 relpipe::common::type::Integer attributeIndex = 0; |
61 public: |
85 public: |
62 |
86 |
63 X11Handler(std::ostream& output, Configuration& configuration) : output(output), configuration(configuration) { |
87 X11Handler(Configuration& configuration) : configuration(configuration) { |
64 display.display = XOpenDisplay(nullptr); |
88 display.display = XOpenDisplay(nullptr); |
65 } |
89 } |
66 |
90 |
67 void startRelation(relpipe::common::type::StringX name, std::vector<relpipe::reader::handlers::AttributeMetadata> attributes) override { |
91 void startRelation(relpipe::common::type::StringX name, std::vector<relpipe::reader::handlers::AttributeMetadata> attributes) override { |
68 if (display.display) { |
92 if (display.display) { |
69 if (firstAttributes.empty()) { |
93 if (this->attributes.empty()) { |
70 firstAttributes = attributes; |
94 this->attributes = attributes; |
71 if (configuration.writeHeader) for (auto attr : attributes) attribute(attr.getAttributeName()); |
|
72 } else { |
95 } else { |
73 throw std::logic_error("Only a single relation can be converted to the X11 format."); |
96 throw std::logic_error("Only a single relation can be converted to the X11 format."); |
74 } |
97 } |
75 } else { |
98 } else { |
76 throw std::invalid_argument("Unable to open display. Please check the $DISPLAY variable."); |
99 throw std::invalid_argument("Unable to open display. Please check the $DISPLAY variable."); |
77 } |
100 } |
78 |
101 |
79 } |
102 } |
80 |
103 |
81 void attribute(const relpipe::common::type::StringX& value) override { |
104 void attribute(const relpipe::common::type::StringX& value) override { |
82 valueCount++; |
105 if (attributes[attributeIndex].getAttributeName() == L"device") { |
83 |
106 // TODO: maybe add some filtering based on device ID |
84 if (value.size() > 0) { |
107 } else if (attributes[attributeIndex].getAttributeName() == L"type") { |
85 output << QUOTE; |
108 if (value == L"key") currentEvent.type = Event::Type::KEY; |
86 for (auto ch : convertor.to_bytes(value)) { |
109 else if (value == L"button") currentEvent.type = Event::Type::BUTTON; |
87 if (ch == QUOTE) output << QUOTE << QUOTE; |
110 else if (value == L"motion") currentEvent.type = Event::Type::MOTION; |
88 else output << ch; |
111 else currentEvent.type == Event::Type::UNKNOWN; // TODO: throw exception or print warning? |
89 } |
112 } else if (attributes[attributeIndex].getAttributeName() == L"state") { |
90 output << QUOTE; |
113 if (value == L"pressed") currentEvent.state = Event::State::PRESSED; |
|
114 else if (value == L"released") currentEvent.state = Event::State::RELEASED; |
|
115 else currentEvent.state == Event::State::UNKNOWN; // TODO: throw exception or print warning? |
|
116 } else if (attributes[attributeIndex].getAttributeName() == L"button") { |
|
117 currentEvent.button = stol(value); |
|
118 } else if (attributes[attributeIndex].getAttributeName() == L"key") { |
|
119 currentEvent.key = stol(value); |
|
120 } else if (attributes[attributeIndex].getAttributeName() == L"delay") { |
|
121 currentEvent.delay = stoul(value); |
|
122 } else if (attributes[attributeIndex].getAttributeName() == L"screen") { |
|
123 currentEvent.screen = stol(value); |
|
124 } else if (attributes[attributeIndex].getAttributeName() == L"x") { |
|
125 currentEvent.x = stol(value); |
|
126 } else if (attributes[attributeIndex].getAttributeName() == L"y") { |
|
127 currentEvent.y = stol(value); |
|
128 } else { |
|
129 // ignore other attributes |
91 } |
130 } |
92 |
131 |
93 if (valueCount % firstAttributes.size()) { |
132 attributeIndex++; |
94 output << ","; |
133 |
95 } else { |
134 if (attributeIndex % attributes.size() == 0) { |
96 output << "\r\n"; |
135 if (currentEvent.type == Event::Type::KEY) { |
97 valueCount = 0; |
136 XTestFakeKeyEvent(display.display, currentEvent.key, currentEvent.state == Event::State::PRESSED, 1); |
98 // XTestFakeKeyEvent(display.display, 38, true, 0); |
137 } else if (currentEvent.type == Event::Type::BUTTON) { |
99 // XTestFakeKeyEvent(display.display, 38, false, 0); |
138 XTestFakeButtonEvent(display.display, currentEvent.button, currentEvent.state == Event::State::PRESSED, currentEvent.delay); |
|
139 } else if (currentEvent.type == Event::Type::MOTION) { |
|
140 XTestFakeMotionEvent(display.display, currentEvent.screen, currentEvent.x, currentEvent.y, currentEvent.delay); |
|
141 } else { |
|
142 std::wcerr << L"Unsupported event" << std::endl; |
|
143 } |
|
144 |
|
145 attributeIndex = 0; |
|
146 currentEvent = Event(); |
100 } |
147 } |
101 } |
148 } |
102 |
149 |
103 void endOfPipe() { |
150 void endOfPipe() { |
104 output.flush(); |
151 // XTestDiscard(display.display); // TODO: wait before discard? |
105 } |
152 } |
106 |
153 |
107 }; |
154 }; |
108 |
155 |
109 } |
156 } |