summaryrefslogtreecommitdiff
path: root/wacom_pointer.e
diff options
context:
space:
mode:
Diffstat (limited to 'wacom_pointer.e')
-rw-r--r--wacom_pointer.e426
1 files changed, 426 insertions, 0 deletions
diff --git a/wacom_pointer.e b/wacom_pointer.e
new file mode 100644
index 0000000..1325625
--- /dev/null
+++ b/wacom_pointer.e
@@ -0,0 +1,426 @@
+class WACOM_POINTER
+
+create {XINPUT_IVY}
+ make, make_self_test
+
+feature {}
+ make(a_xinput_ivy: XINPUT_IVY) is
+ require
+ a_xinput_ivy /= Void
+ do
+ xinput_ivy := a_xinput_ivy
+ prediction_time := 25
+ end
+
+ make_self_test is
+ local
+ angle: REAL
+ x, y: REAL
+ mc: MATH_CONSTANTS
+ i: INTEGER
+ do
+ from
+ angle := 80
+ prediction_time := 10
+ until
+ i > 36
+ loop
+ x := (angle * mc.Pi / 180).cos * 1000
+ y := (angle * mc.Pi / 180).sin * 1000
+ if i > 2 then
+ --io.put_string(once "Real position: x=")
+ io.put_real(x)
+ --io.put_string(once ", y=")
+ io.put_character(' ')
+ io.put_real(y)
+ io.put_new_line
+ end
+ update_predicted_position(x, y, angle)
+ if i >= 2 then
+ --io.put_string(once "Predicted position: x=")
+ io.put_real(predicted_x)
+ --io.put_string(once ", y=")
+ io.put_character(' ')
+ io.put_real(predicted_y)
+ io.put_character(' ')
+ --io.put_new_line
+ end
+ angle := angle + prediction_time
+ i := i + 1
+ end
+ end
+
+ xinput_ivy: XINPUT_IVY
+
+ x_offset, y_offset: INTEGER
+
+ prediction_time: REAL
+
+ ignore_rate, ignored_counter: INTEGER
+
+ pointer_message_header, button_message_header: STRING
+
+ old_presure: INTEGER
+
+ type_to_name(type_id: INTEGER): STRING is
+ do
+ inspect type_id
+ when 2066 then Result := once "pen_2066" -- 0x812
+ when 2049 then Result := once "pen_2049" -- 0x801
+ -- 0x012
+ when 2082 then Result := once "pen_2082" -- 0x822
+ -- 0x842
+ -- 0x852
+ when 2083 then Result := once "grip_pen_2083" -- 0x823
+ when 2067 then Result := once "classic_pen_2067" -- 0x813
+ when 2181 then Result := once "marker_pen_2181" -- 0x885
+ -- 0x022
+ when 2098 then Result := once "stroke_pen_2098" -- 0x832
+ -- 0x032
+ when 3346 then Result := once "airbrush_3346" -- 0xd12
+ -- 0x912
+ -- 0x112
+ when 2323 then Result := once "airbrush_2323" -- 0x913
+ when 2090 then Result := once "eraser_2090" -- 0x82a
+ -- 0x85a
+ -- 0x91a
+ -- 0xd1a
+ -- 0x0fa
+ when 2091 then Result := once "grip_pen_eraser_2091" -- 0x82b
+ when 2075 then Result := once "classic_pen_eraser_2075" -- 0x81b
+ when 2331 then Result := once "airbrush_eraser_2331" -- 0x91b
+ else
+ Result := once ""
+ Result.clear_count
+ type_id.append_in(Result)
+ end
+ end
+
+feature {XINPUT_IVY}
+ set_x_offset(offset: INTEGER) is
+ do
+ x_offset := offset
+ end
+
+ set_y_offset(offset: INTEGER) is
+ do
+ y_offset := offset
+ end
+
+ set_prediction(milliseconds: REAL) is
+ do
+ prediction_time := milliseconds
+ end
+
+ set_ignore_rate(n: INTEGER) is
+ do
+ ignore_rate := n
+ end
+
+ set_message_header(header: STRING) is
+ local
+ history_size: INTEGER
+ do
+ pointer_message_header := "pointer"
+ pointer_message_header.append(header)
+ button_message_header := "button"
+ button_message_header.append(header)
+ history_size := 1
+ create x_history.make(0, history_size)
+ create y_history.make(0, history_size)
+ create time_history.make(0, history_size)
+ end
+
+ device_to_screen_x(x: INTEGER): INTEGER is
+ do
+ Result := (x / 86400 * 1600 + x_offset).force_to_integer_32 -- **** geometrie paramétrable
+ end
+
+ device_to_screen_y(y: INTEGER): INTEGER is
+ do
+ Result := (y / 65000 * 1200 + y_offset).force_to_integer_32 -- **** geometrie paramétrable
+ end
+
+ x_history, y_history, time_history: RING_ARRAY[INTEGER]
+
+ mean(history: RING_ARRAY[INTEGER]): REAL is
+ require
+ history.count > 0
+ local
+ sum: INTEGER_64
+ i: INTEGER
+ do
+ from
+ i := history.lower
+ until
+ i > history.upper
+ loop
+ sum := sum + history.item(i)
+ i := i + 1
+ end
+ Result := sum / history.count
+ end
+
+ move(pointer: X_INPUT_DEVICE) is
+ local
+ x, y, presure: INTEGER
+ t3: REAL_64
+ message: STRING
+ do
+ x := pointer.motion_axis_data(1)
+ y := pointer.motion_axis_data(2)
+ --update_predicted_position(x, y, pointer.event_time)
+ x_history.remove_first
+ x_history.add_last(x)
+ y_history.remove_first
+ y_history.add_last(y)
+ time_history.remove_first
+ time_history.add_last(pointer.event_time)
+ t3 := mean(time_history)
+ if t3 /= t2 then
+ update_predicted_position(mean(x_history), mean(y_history), t3)
+ end
+ presure := pointer.motion_axis_data(3)
+ if ignored_counter < ignore_rate and then ((old_presure = 0) = (presure = 0)) then
+ ignored_counter := ignored_counter + 1
+ else
+ ignored_counter := 0
+ message := once ""
+ message.copy(pointer_message_header)
+ print_data_in(message, x, y, presure, pointer.motion_axis_data(4),
+ pointer.motion_axis_data(5),
+ pointer.motion_axis_data(6), pointer.event_time,
+ once "unchanged")
+ xinput_ivy.ivy.send_message(message)
+ end
+ old_presure := presure
+ end
+
+
+ print_data_in(message: STRING; x, y, presure, v4, v5, v6, time: INTEGER; proximity_description: STRING) is
+ do
+ message.append(once " x=")
+ device_to_screen_x(x).append_in(message)
+ message.append(once " y=")
+ device_to_screen_y(y).append_in(message)
+ message.append(once " presure=")
+ presure.append_in(message)
+ message.append(once " tilt_x=")
+ v4.low_16.append_in(message)
+ message.append(once " tilt_y=")
+ v5.low_16.append_in(message)
+ message.append(once " wheel=")
+ v6.low_16.append_in(message)
+ message.append(once " predicted_x=")
+ device_to_screen_x(predicted_x).append_in(message)
+ message.append(once " predicted_y=")
+ device_to_screen_y(predicted_y).append_in(message)
+ message.append(once " type=")
+ message.append(type_to_name(v4.high_16))
+ message.append(once " serial_number=")
+ (v5.high_16.to_integer_32 |<< 16).bit_or(v6.high_16).append_in(message)
+ message.append(once " time=")
+ time.append_in(message)
+ message.append(once " hires_x=")
+ (x/86400).append_in(message) -- **** geometrie paramétrable
+ message.append(once " hires_y=")
+ (y/65000).append_in(message) -- **** geometrie paramétrable
+ message.append(once " proximity=")
+ message.append(proximity_description)
+ end
+
+ button(pressed: BOOLEAN; pointer: X_INPUT_DEVICE) is
+ local
+ x, y, presure: INTEGER
+ t3: REAL_64
+ message: STRING
+ do
+ x := pointer.motion_axis_data(1)
+ y := pointer.motion_axis_data(2)
+ --update_predicted_position(x, y, pointer.event_time)
+ x_history.remove_first
+ x_history.add_last(x)
+ y_history.remove_first
+ y_history.add_last(y)
+ time_history.remove_first
+ time_history.add_last(pointer.event_time)
+ t3 := mean(time_history)
+ if t3 /= t2 then
+ update_predicted_position(mean(x_history), mean(y_history), t3)
+ end
+ message := once ""
+ message.copy(button_message_header)
+ message.append(once " button=")
+ pointer.button_number.append_in(message)
+ message.append(once " status=")
+ if pressed then
+ message.append(once "down")
+ else
+ message.append(once "up")
+ end
+ presure := pointer.motion_axis_data(3)
+ print_data_in(message, x, y, presure, pointer.motion_axis_data(4),
+ pointer.motion_axis_data(5),
+ pointer.motion_axis_data(6), pointer.event_time,
+ once "unchanged")
+ xinput_ivy.ivy.send_message(message)
+ end
+
+ proximity(in: BOOLEAN; pointer: X_INPUT_DEVICE) is
+ local
+ x, y: INTEGER
+ t3: REAL_64
+ message, proximity_status: STRING
+ do
+ x := pointer.proximity_axis_data(1)
+ y := pointer.proximity_axis_data(2)
+ --update_predicted_position(x, y, pointer.event_time)
+ --*** exploiter le cas proximity in=True pour vider l'historique
+ x_history.remove_first
+ x_history.add_last(x)
+ y_history.remove_first
+ y_history.add_last(y)
+ time_history.remove_first
+ time_history.add_last(pointer.event_time)
+ t3 := mean(time_history)
+ if t3 /= t2 then
+ update_predicted_position(mean(x_history), mean(y_history), t3)
+ end
+ if in then
+ proximity_status := once "In"
+ else
+ proximity_status := once "Out"
+ end
+ message := once ""
+ message.copy(pointer_message_header)
+ print_data_in(message, x, y, pointer.proximity_axis_data(3),
+ pointer.proximity_axis_data(4),
+ pointer.proximity_axis_data(5),
+ pointer.proximity_axis_data(6),
+ pointer.event_time, proximity_status)
+ xinput_ivy.ivy.send_message(message)
+ end
+
+ predicted_x, predicted_y: INTEGER
+
+ int_update_predicted_position(x3, y3, t3: INTEGER) is
+ local
+ dt: REAL -- delta time, temporary value
+ s3x, s3y, s3: REAL -- speed beetween P2 and P3
+ s3xn, s3yn: REAL -- normalized speed between point P2 and P3
+ a3x, a3y: REAL -- acceleration at point P2 (needs P3!)
+ a3xm, a3ym: REAL -- a3 value in mobile coordinates (s2 vector)
+ a4x, a4y: REAL -- a3 value rotated by (s2 vector, s3 vector) angle
+ do
+ dt := t3 - t2
+ --s3x := (x3 - x2).to_real_64 / dt
+ --s3y := (y3 - y2).to_real_64 / dt
+ s3 := (s3x * s3x + s3y * s3y).sqrt
+ s3xn := s3x / s3
+ s3yn := s3y / s3
+
+ dt := (t3 - t1) / 2
+ a3x := (s3x - s2x) / dt
+ a3y := (s3y - s2y) / dt
+ a3xm := a3x * s2xn + a3y * s2yn
+ a3ym := -a3x * s2yn + a3y * s2xn
+ a4x := s3xn * a3xm - s3yn * a3ym
+ a4y := s3yn * a3xm + s3xn * a3ym
+
+ dt := (t3 - t2 + prediction_time) / 2
+ predicted_x := x3 + (prediction_time * (s3x + a4x * dt)).force_to_integer_32
+ predicted_y := y3 + (prediction_time * (s3y + a4y * dt)).force_to_integer_32
+
+ if (prediction_time * (s3y + a4y * dt)).abs > 5300 then
+ io.put_string(once "x2=" + x2.to_string + once " y2=" + y2.to_string)
+ io.put_string(once " x3=" + x3.to_string + once " y3=" + y3.to_string)
+ io.put_string(once " s3x=" + s3x.to_string + once " s3y=" + s3y.to_string)
+ io.put_string(once " a3x=" + a3x.to_string + once " a3y=" + a3y.to_string)
+ io.put_string(once " a3xm=" + a3xm.to_string + once " a3ym=" + a3ym.to_string)
+ io.put_string(once " a4x=" + a4x.to_string + once " a4y=" + a4y.to_string)
+ io.put_string(once " dt=" + dt.to_string)
+ io.put_string(once " ****")
+ io.put_new_line
+ end
+ -- Shift values
+ x2 := x3; y2 := y3
+ s2x := s3x; s2y := s3y
+ s2xn := s3xn; s2yn := s3yn
+ t1 := t2; t2 := t3
+ end
+
+ update_predicted_position(x3, y3, t3: REAL) is
+ require
+ t2 /= t3
+ local
+ dt: REAL -- delta time, temporary value
+ s3x, s3y, s3: REAL -- speed beetween P2 and P3
+ s3xn, s3yn: REAL -- normalized speed between point P2 and P3
+ a3x, a3y: REAL -- acceleration at point P2 (needs P3!)
+ a3xm, a3ym: REAL -- a3 value in mobile coordinates (s2 vector)
+ a4x, a4y: REAL -- a3 value rotated by (s2 vector, s3 vector) angle
+ do
+ dt := t3 - t2
+ s3x := (x3 - x2) / dt
+ s3y := (y3 - y2) / dt
+ s3 := (s3x * s3x + s3y * s3y).sqrt
+ if s3 /= 0 then
+ s3xn := s3x / s3
+ s3yn := s3y / s3
+ end
+
+ dt := (t3 - t1) / 2
+ a3x := (s3x - s2x) / dt
+ a3y := (s3y - s2y) / dt
+ a3xm := a3x * s2xn + a3y * s2yn
+ a3ym := -a3x * s2yn + a3y * s2xn
+ a4x := s3xn * a3xm - s3yn * a3ym
+ a4y := s3yn * a3xm + s3xn * a3ym
+
+ --dt := (t3 - t2 + prediction_time) / 2
+ -- acceleration is constant
+ -- predicted_x := (x3 + prediction_time * (s3x + a3x * dt)).force_to_integer_32
+ -- predicted_y := (y3 + prediction_time * (s3y + a3y * dt)).force_to_integer_32
+
+ -- acceleration is constant in mobile coordinates
+ -- predicted_x := (x3 + prediction_time * (s3x + a4x * dt)).force_to_integer_32
+ -- predicted_y := (y3 + prediction_time * (s3y + a4y * dt)).force_to_integer_32
+
+ -- acceleration variation is constant
+ -- a4x := a3x + (a3x - a2x) * (prediction_time + t2 - t1) / (t3 + t1 - t2 - t0)
+ -- a4y := a3y + (a3y - a2y) * (prediction_time + t2 - t1) / (t3 + t1 - t2 - t0)
+ -- predicted_x := (x3 + prediction_time * (s3x + a4x * dt)).force_to_integer_32
+ -- predicted_y := (y3 + prediction_time * (s3y + a4y * dt)).force_to_integer_32
+
+ -- half constant in mobile coordinates, half constant variation
+ dt := (prediction_time + t2 - t1) / (t3 + t1 - t2 - t0)
+ a4x := (a4x + a3x + (a3x - a2x) * dt) / 2
+ a4y := (a4y + a3y + (a3y - a2y) * dt) / 2
+
+ dt := (t3 - t2 + prediction_time) / 2
+ predicted_x := (x3 + prediction_time * (s3x + a4x * dt)).force_to_integer_32
+ predicted_y := (y3 + prediction_time * (s3y + a4y * dt)).force_to_integer_32
+
+ -- Shift values
+ x2 := x3; y2 := y3
+ s2x := s3x; s2y := s3y
+ s2xn := s3xn; s2yn := s3yn
+ a2x := a3x; a2y := a3y
+ t0 := t1; t1 := t2; t2 := t3
+ end
+
+ a2x, a2y: REAL
+
+ t0: REAL
+
+ --x2, y2: INTEGER -- point P2 coordinates
+ x2, y2: REAL -- point P2 coordinates
+
+ s2x, s2y: REAL -- speed beetween P1 and P2
+
+ s2xn, s2yn: REAL -- normalized speed between P1 and P2
+
+ --t1, t2: INTEGER -- timestamp for points P1 and P2
+ t1, t2: REAL -- timestamp for points P1 and P2
+
+end