1-- Quite exhaustive tester for the I/O parts of the event management.
2-- (use with -w 640 -h 480)
3
4analogtbl = {};
5digitaltbl = {};
6translatetbl = {};
7statustbl = {};
8touchtbl = {};
9analogdata = {};
10
11function drawline(text, size)
12    return render_text("\\f," .. tostring(size) .. " " .. text);
13end
14
15local function reposition()
16	local w3 = VRESW / 3;
17	local h2 = VRESH / 2;
18	if not valid_vid(analabel) then
19		return
20	end
21	move_image(analabel, 0, 0);
22	move_image(digilabel, w3, 0);
23	move_image(translabel, w3 + w3, 0);
24	move_image(touchlabel, 0, h2);
25	move_image(statuslabel, w3 + w3, h2);
26end
27
28function eventtest()
29	symtable = system_load("builtin/keyboard.lua")();
30
31	analabel = drawline([[\bAnalog]], 12);
32	digilabel = drawline([[\bDigital]], 12);
33	touchlabel = drawline([[\bTouch]], 12);
34	statuslabel = drawline([[\bStatus]], 12);
35	translabel = drawline([[\bTranslated]], 12);
36
37	reposition()
38	inputanalog_toggle(1);
39	tc = null_surface(1, 1);
40
41	show_image({statuslabel, analabel, digilabel, translabel, touchlabel});
42
43-- enumerate the list of found devices
44	restbl = inputanalog_query();
45	print(#restbl, "entries found");
46
47	for k, v in ipairs(restbl) do
48		print("-- new device -- ");
49		for i, j in pairs(v) do
50			print(i, j);
51		end
52	end
53
54-- setup a connection point that allows a single event injector
55	local vid = target_alloc("eventinject",
56	function(source, status)
57		if (status.kind == "input") then
58			eventtest_input(status);
59		else
60			print("non-IO event on eventinject connection point:", status.kind);
61		end
62	end);
63	target_flags(vid, TARGET_ALLOWINPUT);
64
65-- enable analog events
66	inputanalog_toggle(1);
67end
68
69function round(inn, dec)
70	return math.floor( (inn * 10^dec) / 10^dec);
71end
72
73function touch_str(iotbl)
74	table.insert(touchtbl, string.format(
75		"dev(%d:%d) @ %d, %d, press: %.2f, size: %.2f, active: %s",
76		iotbl.devid, iotbl.subid, iotbl.x, iotbl.y, iotbl.pressure, iotbl.size,
77		iotbl.active and "yes" or "no")
78	);
79	if (#touchtbl > 10) then
80		table.remove(touchtbl, 1);
81	end
82	local line = table.concat(touchtbl, "\\r\\n");
83	if (touchimg) then
84		delete_image(touchimg);
85	end
86	touchimg = drawline(line, 10);
87	link_image(touchimg, touchlabel);
88	nudge_image(touchimg, 0, 20);
89	show_image(touchimg);
90end
91
92function digital_str(iotbl)
93 	table.insert(digitaltbl, string.format(
94		"dev(%d:%d) %s", iotbl.devid, iotbl.subid, iotbl.active and "press" or "release"));
95
96	if (#digitaltbl > 10) then
97		table.remove(digitaltbl, 1);
98	end
99
100	local line = table.concat(digitaltbl, "\\r\\n");
101
102	if (digitalimg) then
103		delete_image(digitalimg);
104	end
105
106	digitalimg = drawline(line, 10);
107	link_image(digitalimg, digilabel);
108	nudge_image(digitalimg, 0, 20);
109	show_image(digitalimg);
110end
111
112function translate_str(iotbl)
113	table.insert(translatetbl, string.format("dev(%d:%d)%d[%s] => %s, %s, %s, %s",
114		iotbl.devid, iotbl.subid, iotbl.number,
115		table.concat(decode_modifiers(iotbl.modifiers),","),
116		iotbl.keysym, iotbl.active and "press" or "release",
117		symtable[iotbl.keysym] and symtable[iotbl.keysym] or "_nil",
118		iotbl.utf8)
119	);
120
121	if (#translatetbl > 10) then
122		table.remove(translatetbl, 1);
123	end
124
125	local tbl = {""};
126	for k,v in ipairs(translatetbl) do
127		table.insert(tbl, v);
128		table.insert(tbl, [[\r\n]]);
129	end
130
131	if (translateimg) then
132		delete_image(translateimg);
133	end
134
135	translateimg = render_text(tbl);
136	link_image(translateimg, translabel);
137	nudge_image(translateimg, 0, 20);
138	show_image(translateimg);
139end
140
141function analog_str(intbl)
142	return string.format("%d:%.2f/%.2f avg: %.2f", intbl.count,
143		round(intbl.min, 2), round(intbl.max, 2), round(intbl.avg, 2));
144end
145
146tick_counter = 500;
147function eventtest_clock_pulse(stamp, delta)
148	if (analogimg) then
149		delete_image(analogimg);
150	end
151
152	line = "";
153	for ak, ad in pairs( analogdata ) do
154		workline = [[\n\rDevice(]] .. ak .. [[):\n\r\t]];
155		for id, iv in pairs( ad ) do
156			workline = workline .. " axis: " .. id .. " # " .. analog_str(iv) .. [[\n\r\t]];
157		end
158
159		line = line .. workline .. [[\r\n]];
160	end
161
162	analogimg = drawline(line, 10);
163	link_image(analogimg, analabel);
164	nudge_image(analogimg, 0, 20);
165	show_image(analogimg);
166
167-- need a fallback counter as all our inputs might be busy
168-- should possible have an 'all analog off' switch as well or this
169-- might not trigger on noisy sensors
170	tick_counter = tick_counter - 1;
171	if (tick_counter == 0) then
172		return shutdown("timeout");
173	else
174		delete_image(tc);
175		tc = render_text("Shutdown in " .. tostring(tick_counter));
176		show_image(tc);
177		move_image(tc, 0, VRESH - 20);
178	end
179end
180
181function eventtest_input( iotbl )
182	if (iotbl.digital) then
183		tick_counter = 500;
184		if (iotbl.translated) then
185			translate_str(iotbl);
186		else
187			digital_str(iotbl);
188		end
189
190	elseif (iotbl.touch) then
191		touch_str(iotbl);
192
193	elseif (iotbl.analog) then
194		local anatbl = {};
195
196		if (analogdata[iotbl.devid] == nil) then
197			analogdata[iotbl.devid] = {};
198		end
199
200		if (analogdata[iotbl.devid][iotbl.subid] == nil) then
201			analogdata[iotbl.devid][iotbl.subid] = anatbl;
202			anatbl.count = 0;
203			anatbl.min = 65535;
204			anatbl.max = 0;
205			anatbl.avg = 1;
206			anatbl.samples = {};
207		end
208
209		anatbl = analogdata[iotbl.devid][iotbl.subid];
210		anatbl.count = anatbl.count + 1;
211		table.insert(anatbl.samples, iotbl.samples[1]);
212
213		if (iotbl.samples[1] < anatbl.min) then
214			anatbl.min = iotbl.samples[1];
215		end
216
217		if (iotbl.samples[1] > anatbl.max) then
218			anatbl.max = iotbl.samples[1];
219		end
220
221		anatbl.avg = (anatbl.avg + iotbl.samples[1]) / 2;
222
223		if (#anatbl.samples > 10) then
224			table.remove(anatbl.samples, 1);
225		end
226
227		anatbl.match = tbl;
228	elseif (iotbl.kind == "status") then
229		warning(string.format("status(%d) - %s, %s, %s", iotbl.devid, iotbl.devkind,
230			iotbl.label, iotbl.action));
231	end
232end
233
234function eventtest_display_state(status)
235	resize_video_canvas(VRESW, VRESH)
236	reposition()
237end
238