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