summaryrefslogtreecommitdiff
path: root/xinput_ivy.e
blob: 15d0a54adf6b166dc4ad9c2d73dc755a3b3b8f00 (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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
class XINPUT_IVY

inherit
	GRAPHIC

insert
	ARGUMENTS
	
creation {ANY}
	make

feature {}
	
	ivy_bus: STRING
	
	application_name: STRING

	device_id: STRING
	
	make is
		local
			ready: BOOLEAN
		do
			application_name := "wacom"
			ivy_bus := ":3110"
			device_id := "default"
			screen := vision.root_window
			ready := decode_options
			if ready then
				create ivy.make(application_name)
				ivy.start(ivy_bus)
				vision.loop_stack.add_job(ivy)
				vision.start
			end
		end
	
	screen: ROOT_WINDOW

	decode_options: BOOLEAN is
		local
			i: INTEGER
			option, value: STRING
			equal_index: INTEGER
			error: BOOLEAN
			tmp_pointer: WACOM_POINTER
		do
			from
				i := 1
				option := ""
				value := ""
				create tmp_pointer.make(Current)
			until
				i > argument_count or error
			loop
				option.copy(argument(i))
				equal_index := option.first_index_of('=')
				if equal_index = 0 then
					value.clear_count
				else
					value.copy(option)
					value.remove_head(equal_index)
					option.remove_tail(option.count - equal_index + 1)
				end
				inspect option
				when "-help" then
					print_help
				when "-list_devices" then
					list_devices
				when "-pad" then
					if init_pad(value) then
						Result := True
					else
						error := True
						std_error.put_character('"')
						std_error.put_string(value)
						std_error.put_string("%" is not a valid pad name.%N")
					end
				when "-wacom_pointer" then
					if init_wacom_pointer(tmp_pointer, value) then
						Result := True
					else
						error := True
						std_error.put_character('"')
						std_error.put_string(value)
						std_error.put_string("%" is not a valid pointer name.%N")
					end
				when "-bus" then
					ivy_bus.copy(value)
				when "-b" then
					if i < argument_count then
						i := i + 1
						ivy_bus.copy(argument(i))
					else
						error := True
						std_error.put_string("Missing bus identifier after %
                                       %-b option.%N")
					end
				when "-application" then
					application_name.copy(value)
				when "-identifier" then
					device_id.copy(value)
				when "-x_offset" then
					if value.is_integer then
						tmp_pointer.set_x_offset(value.to_integer)
					else
						error := True
						std_error.put_character('"')
						std_error.put_string(value)
						std_error.put_string("%" is not a valid x_offset (an integer is needed).%N")
					end
				when "-y_offset" then
					if value.is_integer then
						tmp_pointer.set_y_offset(value.to_integer)
					else
						error := True
						std_error.put_character('"')
						std_error.put_string(value)
						std_error.put_string("%" is not a valid y_offset (an integer is needed).%N")
					end
				when "-prediction" then
					if value.is_real then
						tmp_pointer.set_prediction(value.to_real)
					else
						error := True
						std_error.put_character('"')
						std_error.put_string(value)
						std_error.put_string("%" is not a valid time (a real number is needed).%N")
					end
				when "-ignore" then
					if value.is_integer then
						tmp_pointer.set_ignore_rate(value.to_integer)
					else
						error := True
						std_error.put_character('"')
						std_error.put_string(value)
						std_error.put_string("%" is not a valid ignore rate (an integer is needed).%N")
					end
				else
					error := True
					std_error.put_string("Unknown option ")
					std_error.put_string(argument(i))
					std_error.put_new_line
					print_help
				end
				i := i + 1
			end
			if error then
				Result := False
			end
			if argument_count =0 then
				print_help
			end
		end

	init_pad(pad_name: STRING): BOOLEAN is
		local
			pad: X_INPUT_DEVICE
			message_header: STRING
		do
			pad := subscribe_input(pad_name)
			if pad /= Void then
				Result := True
				message_header := "slider_event device_id="
				message_header.append(device_id)
				message_header.append(once " value=")
				pad.when_moved(screen, agent slider_event(message_header, ?))
				pad.when_proximity_out(screen, agent left_slider_out(message_header, ?))
				
				message_header := "pad_event device_id="
				message_header.append(device_id)
				message_header.append(once " button=")
				pad.when_button_pressed(screen, agent pad_button_pressed(message_header, ?))
				pad.when_button_released(screen, agent pad_button_released(message_header, ?))
			end
		end
	
	init_wacom_pointer(wacom_pointer_model: WACOM_POINTER; pointer_name: STRING): BOOLEAN is
		local
			pointer: X_INPUT_DEVICE
			message_header: STRING
			wacom_pointer: WACOM_POINTER
		do
			pointer := subscribe_input(pointer_name)
			if pointer /= Void then
				Result := True
				wacom_pointer := wacom_pointer_model.twin
				message_header := "_event device_id="
				message_header.append(device_id)
				wacom_pointer.set_message_header(message_header)
				pointer.when_moved(screen, agent wacom_pointer.move)
				pointer.when_button_pressed(screen, agent wacom_pointer.button(True, ?))
				pointer.when_button_released(screen, agent wacom_pointer.button(False, ?))
				pointer.when_proximity_in(screen, agent wacom_pointer.proximity(True, ?))
				pointer.when_proximity_out(screen, agent wacom_pointer.proximity(False, ?))
			end
		end

	print_help is
		do
			io.put_string("[
								This tool get data from wacom pen screen and is
		                  able to send them to applications using ivy bus.

								Options:
								   -help:               print this help.

								   -list_devices:       all available devices are listed.

								   -pad=name:           report pad data from the pad device with this name.

								   -wacom_pointer=name: report pointer data from the pointer device with
								                        this name. Ex: stylus.

								   -bus=[address]:port: specify the ivy bus (default is :3110).

								   -b [address]:port:   specify the ivy bus (default is :3110) (added for
								                        compatibility with other ivy tools).

								   -application=name:   specify the application name on the ivy bus
								                        (default is wacom).

								   -identifier=id:      this identifier will be used in ivy messages
								                        device_id value (default is "default").

								   -x_offset=n:         specify the x-offset for the wacom device
								                        for the display configuration (default is 0).

								   -y_offset=n:         specify the y-offset for the wacom device
								                        for the display configuration (default is 0).

								   -prediction=t:       change the prediction time for the physical position.
								                        (default is 25ms).

								   -ignore=n:           number of messages to ignore before sending a new
								                        position message (this reduces message frequency).
								                        (default is 0 => ~120message/s).
									
								Options are considered in the order they appear in the command line. A new
								value overrides the previous one. "wacom_pointer" and "pad" are created where they
								appear, with known information.
								
								Messages:
								   slider_event device_id=radar_wacom value=4 side=left time=4523271
								                        device_id: identifier (see options).
								                        value: new slider value (0 when the
																		finger leaves the slider).
								                        side: left or right.
								                        time: event time (ms), X server reference.

								   pad_event device_id=radar_wacom button=12 status=left time=4523271
								                        device_id: identifier (see options).
								                        button: button identifier.
								                        status: up or down.
								                        time: event time (ms), X server reference.

								   button_event device_id=radar_wacom button=2 status=up x=1290 y=325
								      presure=307 tilt_x=-20 tilt_y=15 wheel=0 predicted_x=1272 predicted_y=322
								      type=123 serial_number=429389 time=4523271 hires_x=0.827 hires_y=0.231
								      proximity=unchanged
								   pointer_event device_id=radar_wacom x=1290 y=325
								      presure=307 tilt_x=-20 tilt_y=15 wheel=0 predicted_x=1272 predicted_y=322
								      type=123 serial_number=429389 time=4523271 hires_x=0.827 hires_y=0.231
								      proximity=unchanged
								                        device_id: identifier (see options).
								                        button: button identifier.
								                        status: up or down.
								                        x: pointer position (display coordinates).
								                        y: pointer position (display coordinates).
								                        presure: presure value ([0, 1023] for intuos 3).
								                        tilt_x: device tilt in degrees.
								                        tilt_y: device tilt in degrees.
								                        wheel: rotation value (device type dependent value).
								                        predicted_x: predicted position. It is expected to be
								                             the current position of the real device.
								                        predicted_y: predicted position. It is expected to be
								                             the current position of the real device.
								                        type: the type of the device (pen, eraser, mouse,
								                             cursor, airbrush...).
								                        serial_number: the serial number of the device.
								                        time: event time (ms), X server reference.
								                        hires_x: pointer position (device coordinates, in range [0,1]).
								                        hires_y: pointer position (device coordinates, in range [0,1]).
								                        proximity: unchanged, in, out

								]")
			--*** calibration?
			--*** filtrage?
			--*** bouton du stylo?
			--*** distance du stylo?
			--*** message pour demander la configuration?
			--*** suppression du curseur souris
			--*** display
			--***
			--*** Ajouter le message pour modifier la prédiction
		end
		  
	x11: X11

	subscribe_input(name: STRING): X_INPUT_DEVICE is
		local
			i: INTEGER
			devices: FAST_ARRAY[X_INPUT_DEVICE]
		do
			if not x11.has_x_input_extension then
				std_error.put_line("XInputExtension is not available.")
			else
				from
					devices := x11.x_input_extension.devices
					i := devices.lower
				until
					i > devices.upper or else Result /= Void
				loop
					if devices.item(i).name.is_equal(name) then
						Result := devices.item(i)
						if Result.is_available_extension then
							Result.connect
						else
							Result := Void
						end
					end
					i := i + 1
				end
			end
		end

	left_pad_position: INTEGER
	right_pad_position: INTEGER
	
	slider_event(message_header: STRING; pad: X_INPUT_DEVICE) is
		local
			new_pad_position: INTEGER
			message: STRING
		do
			message := once ""
			new_pad_position := pad.motion_axis_data(4)
			if new_pad_position /= left_pad_position then
				message.copy(message_header)
				new_pad_position.append_in(message)
				message.append(once " side=left time=")
				pad.event_time.append_in(message)
				ivy.send_message(message)
				left_pad_position := new_pad_position
			end
				
			new_pad_position := pad.motion_axis_data(5)
			if new_pad_position /= right_pad_position then
				message.copy(message_header)
				new_pad_position.append_in(message)
				message.append(once " side=right time=")
				pad.event_time.append_in(message)
				ivy.send_message(message)
				right_pad_position := new_pad_position
			end
		end

	left_slider_out(message_header: STRING; pad: X_INPUT_DEVICE) is
		local
			message: STRING
		do
			message := once ""
			message.copy(message_header)
			message.extend('0')
			message.append(once " side=left time=")
			pad.event_time.append_in(message)
			ivy.send_message(message)
			left_pad_position := 0
		end

	pad_button_pressed(message_header: STRING; pad: X_INPUT_DEVICE) is
		local
			message: STRING
		do
			message := once ""
			message.copy(message_header)
			pad.button_number.append_in(message)
			message.append(once " status=down time=")
			pad.event_time.append_in(message)
			ivy.send_message(message)
		end
	
	pad_button_released(message_header: STRING; pad: X_INPUT_DEVICE) is
		local
			message: STRING
		do
			message := once ""
			message.copy(message_header)
			pad.button_number.append_in(message)
			message.append(once " status=up time=")
			pad.event_time.append_in(message)
			ivy.send_message(message)
		end

	list_devices is
		local
			i: INTEGER
			devices: FAST_ARRAY[X_INPUT_DEVICE]
			device: X_INPUT_DEVICE
		do
			if not x11.has_x_input_extension then
				std_error.put_line("XInputExtension is not available.")
			else
				from
					devices := x11.x_input_extension.devices
					i := devices.lower
				until
					i > devices.upper
				loop
					device := devices.item(i)
					std_output.put_string(device.name)
					std_output.put_string(once " (Type: ")
					if device.type = Void then
						std_output.put_character('?')
					else
						std_output.put_string(device.type)
					end
					std_output.put_string(once " Status: ")
					if device.is_available_extension then
						std_output.put_line(once " available)")
					else
						std_output.put_line(once " unavailable)")
					end
					i := i + 1
				end
			end
		end

feature {WACOM_POINTER}
	ivy: IVY
	

end