Class: Fusuma::Plugin::Remap::KeyboardRemapper

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

Defined Under Namespace

Classes: KeyboardSelector, TouchpadSelector

Constant Summary collapse

VIRTUAL_KEYBOARD_NAME =
"fusuma_virtual_keyboard"

Instance Method Summary collapse

Constructor Details

#initialize(layer_manager:, fusuma_writer:, config: {}) ⇒ KeyboardRemapper

Returns a new instance of KeyboardRemapper.

Parameters:



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

def initialize(layer_manager:, fusuma_writer:, config: {})
  @layer_manager = layer_manager # request to change layer
  @fusuma_writer = fusuma_writer # write event to original keyboard
  @config = config
end

Instance Method Details

#runObject



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

def run
  create_virtual_keyboard
  @source_keyboards = reload_keyboards

  old_ie = nil
  layer = 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
      layer = @layer_manager.receive_layer # update @current_layer
      if layer.nil?
        next
      end

      next_mapping = @layer_manager.find_mapping(layer)
      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
      @emergency_stop.call(old_ie, input_event)

      old_ie = input_event
      if input_event.value != 2 # repeat
        data = {key: input_key, status: input_event.value, layer: layer}
        @fusuma_writer.write(data.to_msgpack)
      end
    end

    remapped = current_mapping.fetch(input_key.to_sym, nil)
    if remapped.nil?
      uinput_keyboard.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_keyboard.write_input_event(remapped_event)
  rescue Errno::ENODEV => e # device is removed
    MultiLogger.error "Device is removed: #{e.message}"
    @source_keyboards = reload_keyboards
  end
rescue EOFError => e # device is closed
  MultiLogger.error "Device is closed: #{e.message}"
ensure
  @destroy&.call
end