Class: Fusuma::Plugin::Remap::TouchpadRemapper

Inherits:
Object
  • Object
show all
Includes:
Revdev
Defined in:
lib/fusuma/plugin/remap/touchpad_remapper.rb

Defined Under Namespace

Classes: PalmDetection

Constant Summary collapse

VIRTUAL_TOUCHPAD_NAME =
"fusuma_virtual_touchpad"

Instance Method Summary collapse

Constructor Details

#initialize(fusuma_writer:, source_touchpad:) ⇒ TouchpadRemapper

Returns a new instance of TouchpadRemapper.

Parameters:

  • fusuma_writer (IO)
  • source_touchpad (Revdev::Device)


17
18
19
20
21
22
23
# File 'lib/fusuma/plugin/remap/touchpad_remapper.rb', line 17

def initialize(fusuma_writer:, source_touchpad:)
  @source_touchpad = source_touchpad # original touchpad
  @fusuma_writer = fusuma_writer # write event to fusuma_input
  @palm_detector ||= PalmDetection.new(source_touchpad)

  set_trap
end

Instance Method Details

#runObject

TODO: grab touchpad events and remap them

send remapped events to virtual touchpad or virtual mouse


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
# File 'lib/fusuma/plugin/remap/touchpad_remapper.rb', line 27

def run
  create_virtual_touchpad

  touch_state = {}
  mt_slot = 0
  finger_state = nil
  loop do
    IO.select([@source_touchpad.file]) # , @layer_manager.reader])

    ## example of input_event
    # Event: time 1698456258.380027, type 3 (EV_ABS), code 57 (ABS_MT_TRACKING_ID), value 43679
    # Event: time 1698456258.380027, type 3 (EV_ABS), code 53 (ABS_MT_POSITION_X), value 648
    # Event: time 1698456258.380027, type 3 (EV_ABS), code 54 (ABS_MT_POSITION_Y), value 209
    # Event: time 1698456258.380027, type 1 (EV_KEY), code 330 (BTN_TOUCH), value 1
    # Event: time 1698456258.380027, type 1 (EV_KEY), code 325 (BTN_TOOL_FINGER), value 1
    # Event: time 1698456258.380027, type 3 (EV_ABS), code 0 (ABS_X), value 648
    # Event: time 1698456258.380027, type 3 (EV_ABS), code 1 (ABS_Y), value 209
    # Event: time 1698456258.380027, type 4 (EV_MSC), code 5 (MSC_TIMESTAMP), value 0
    # Event: time 1698456258.380027, -------------- SYN_REPORT ------------
    # Event: time 1698456258.382693, type 3 (EV_ABS), code 47 (ABS_MT_SLOT), value 1
    # Event: time 1698456258.382693, type 3 (EV_ABS), code 57 (ABS_MT_TRACKING_ID), value 43680
    # Event: time 1698456258.382693, type 3 (EV_ABS), code 53 (ABS_MT_POSITION_X), value 400
    # Event: time 1698456258.382693, type 3 (EV_ABS), code 54 (ABS_MT_POSITION_Y), value 252
    # Event: time 1698456258.382693, type 1 (EV_KEY), code 325 (BTN_TOOL_FINGER), value 0
    # Event: time 1698456258.382693, type 1 (EV_KEY), code 333 (BTN_TOOL_DOUBLETAP), value 1
    # Event: time 1698456258.382693, type 4 (EV_MSC), code 5 (MSC_TIMESTAMP), value 7100
    # Event: time 1698456258.382693, -------------- SYN_REPORT ------------
    input_event = @source_touchpad.read_input_event

    touch_state[mt_slot] ||= {MT_TRACKING_ID: nil, X: nil, Y: nil, valid_touch_point: false}
    syn_report = nil

    case input_event.type
    when Revdev::EV_ABS
      case input_event.code
      when Revdev::ABS_MT_SLOT
        mt_slot = input_event.value
        touch_state[mt_slot] ||= {}
      when Revdev::ABS_MT_TRACKING_ID
        touch_state[mt_slot][:MT_TRACKING_ID] = input_event.value
        if input_event.value == -1
          touch_state[mt_slot] = {}
        end
      when Revdev::ABS_MT_POSITION_X
        touch_state[mt_slot][:X] = input_event.value
      when Revdev::ABS_MT_POSITION_Y
        touch_state[mt_slot][:Y] = input_event.value
      when Revdev::ABS_X, Revdev::ABS_Y
        # ignore
      when Revdev::ABS_MT_PRESSURE
        # ignore
      when Revdev::ABS_MT_TOOL_TYPE
        # ignore
      else
        raise "unhandled event"
      end
    when Revdev::EV_KEY
      case input_event.code
      when Revdev::BTN_TOUCH
        # ignore
      when Revdev::BTN_TOOL_FINGER
        finger_state = (input_event.value == 1) ? 1 : 0
      when Revdev::BTN_TOOL_DOUBLETAP
        finger_state = (input_event.value == 1) ? 2 : 1
      when Revdev::BTN_TOOL_TRIPLETAP
        finger_state = (input_event.value == 1) ? 3 : 2
      when Revdev::BTN_TOOL_QUADTAP
        finger_state = (input_event.value == 1) ? 4 : 3
      when 0x148 # define BTN_TOOL_QUINTTAP	0x148	/* Five fingers on trackpad */
        finger_state = (input_event.value == 1) ? 5 : 4
      end
    when Revdev::EV_MSC
      case input_event.code
      when 0x05 # define MSC_TIMESTAMP		0x05
        # ignore
        # current_timestamp = input_event.value
      end
    when Revdev::EV_SYN
      case input_event.code
      when Revdev::SYN_REPORT
        syn_report = input_event.value
      when Revdev::SYN_DROPPED
        MultiLogger.error "Dropped: #{input_event.value}"
      else
        raise "unhandled event", "#{input_event.hr_type}, #{input_event.hr_code}, #{input_event.value}"
      end
    else
      raise "unhandled event", "#{input_event.hr_type}, #{input_event.hr_code}, #{input_event.value}"
    end

    # TODO:
    # Remember the most recent valid touch position and exclude it if it is close to that position
    # For example, when dragging, it is possible to touch around the edge of the touchpad again after reaching the edge of the touchpad, so in that case, you do not want to execute palm detection
    if touch_state[mt_slot][:valid_touch_point] != true
      touch_state[mt_slot][:valid_touch_point] = @palm_detector.palm?(touch_state[mt_slot])
    end

    if syn_report
      # TODO: define format as fusuma_input
      data = {finger: finger_state, touch_state: touch_state}
      @fusuma_writer.write(data.to_msgpack)
    end
  end
rescue => e
  MultiLogger.error "An error occurred: #{e.message}"
ensure
  @destroy&.call
end