Class: Fusuma::Plugin::Remap::Remapper

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

Instance Method Summary collapse

Constructor Details

#initialize(layer_manager:, keyboard_writer:, source_keyboards:, internal_touchpad:) ⇒ Remapper

Returns a new instance of Remapper.

Parameters:



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

def initialize(layer_manager:, keyboard_writer:, source_keyboards:, internal_touchpad:)
  @layer_manager = layer_manager # request to change layer
  @keyboard_writer = keyboard_writer # write event to original keyboard
  @source_keyboards = source_keyboards # original keyboard
  @internal_touchpad = internal_touchpad # internal touchpad
  @uinput = RuinputDevicePatched.new "/dev/uinput"
  @pressed_virtual_keys = Set.new
end

Instance Method Details

#runObject



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

def run
  create_virtual_keyboard
  set_trap
  grab_keyboards

  old_ie = nil
  next_mapping = nil
  current_mapping = {}

  loop do
    ios = IO.select([*@source_keyboards.map(&:file), @layer_manager.reader])
    io = ios.first.first

    if io == @layer_manager.reader
      begin
        @layer_manager.receive_layer
      rescue EOFError
        @destroy.call
      end

      MultiLogger.debug "Remapper#run: layer changed to #{@layer_manager.current_layer}"
      next_mapping = @layer_manager.find_mapping
      next
    end

    if next_mapping && virtual_keyboard_all_key_released?
      if current_mapping != next_mapping
        current_mapping = next_mapping
      end
      next_mapping = nil
    end

    input_event = @source_keyboards.find { |kbd| kbd.file == io }.read_input_event
    input_key = find_key_from_code(input_event.code)

    if input_event.type == EV_KEY
      # FIXME: exit when RIGHTCTRL-LEFTCTRL is pressed
      if (old_ie&.code == KEY_RIGHTCTRL && old_ie.value != 0) && (input_event.code == KEY_LEFTCTRL && input_event.value != 0)
        @destroy.call
      end

      old_ie = input_event
      if input_event.value != 2 # repeat
        packed = {key: input_key, status: input_event.value}.to_msgpack
        @keyboard_writer.puts(packed)
      end
    end

    remapped = current_mapping.fetch(input_key.to_sym, nil)
    if remapped.nil?
      @uinput.write_input_event(input_event)
      next
    end

    remapped_event = InputEvent.new(nil, input_event.type, find_code_from_key(remapped), input_event.value)

    # Workaround to solve the problem that the remapped key remains pressed
    # when the key pressed before remapping is released after remapping
    unless record_virtual_keyboard_event?(remapped, remapped_event.value)
      # set original key before remapping
      remapped_event.code = input_event.code
    end

    # remap to command will be nil
    # e.g) remap: { X: { command: echo 'foo' } }
    # this is because the command will be executed by fusuma process
    next if remapped_event.code.nil?

    @uinput.write_input_event(remapped_event)
  end
end