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
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
|
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 := ""
device_id := "default"
screen := vision.root_window
decode_application_name_option
create ivy.make(application_name)
ready := decode_options
if ready then
ivy.start(ivy_bus)
vision.loop_stack.add_job(ivy)
vision.start
end
end
screen: ROOT_WINDOW
decode_application_name_option is
local
i, equal_index: INTEGER
do
from
i := 1
until
i > argument_count
loop
if argument(i).has_prefix(once "-application=") then
application_name.copy(argument(i))
equal_index := application_name.first_index_of('=')
application_name.remove_head(equal_index)
end
i := i + 1
end
end
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
-- already done application_name.copy(value) in
-- specific decoding function
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
when "-crop" then
std_error.put_string("Detection de l'option crop : ")
std_error.put_string(value)
std_error.put_new_line
if tmp_pointer.is_valid_crop(value) then
tmp_pointer.set_crop(value)
else
error := True
std_error.put_character('"')
std_error.put_string(value)
std_error.put_string("%" is not a valid crop definition (-crop=xmin,ymin,xmax,ymax is expected).%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)
wacom_pointer.crop_identifier(device_id)
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).
-crop=xmin,ymin,xmax,ymax: outside this area, move events are not reported
(values are integers in device coordinates). Hires values
are mapped to [0,1] inside this window and over when outside.
-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
Crop configuration can be changed dynamically sending a CHANGE_CROP message:
CHANGE_CROP device_id=radar_wacom crop=52320,14596,86600,38102
]")
--*** 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
|