Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

optional blocking begin and end commands #290

Open
ces42 opened this issue Mar 19, 2023 · 7 comments
Open

optional blocking begin and end commands #290

ces42 opened this issue Mar 19, 2023 · 7 comments

Comments

@ces42
Copy link
Contributor

ces42 commented Mar 19, 2023

Is your feature request related to a problem? Please describe.
I've been trying to using the begin and end triggers to focus the window the cursor is over/refocus the previously focused window so that I can use 3-finger swipes to change tabs (by sending ctrl+PgUp/Down with ydotool) in windows that aren't currently focused.
It kind of works, but it seems like sometimes wmctrl command I use to focus the window hasn't finished when ydotool sends the keypress, so the wrong window receives it.

Describe the solution you'd like
My could probably be fixed if there was some way to make commands (at least for begin and end "gesture") be executed synchronously, i.e. no other commands are executed before their process has exited. Probably the easiest way to do this would be for the whole fusuma process to wait until the command exits.

@ces42
Copy link
Contributor Author

ces42 commented Mar 22, 2023

I've been playing around trying to do this and it seems to me that replacing


by

if event.record.index.keys[-1].symbol == :begin
  Process.wait(pid)
else
  Process.detach(pid)
end

would implement this always, for begin commands.

I don't really have any idea how to create an option in config.yml that would allow the user to turn this on/off.

@iberianpig
Copy link
Owner

Could you paste your config.yml?
I would like to know in detail what kind of workflow you are trying to create.

@ces42
Copy link
Contributor Author

ces42 commented Mar 24, 2023

Here's the relevant part of the config

swipe:
    3:
      begin:
        command: |-
            sedGetValue='s/.*=\(.*\)/\1/'
            old_win=$(xdotool getactivewindow)
            id=$(xdotool getmouselocation --shell | grep WINDOW | sed 's/.*=\(.*\)/\1/')
            if [ $old_win != $id ]; then
                # wmctrl -iR "$id"
                xdotool windowfocus "$id"
                echo $old_win > "/var/run/user/$(id -u)/fusuma-old-win"
            else
                echo 'SAME' > "/var/run/user/$(id -u)/fusuma-old-win"
            fi
        interval: 0.1
      end:
        command: |-
            old_win=$(cat /var/run/user/$(id -u)/fusuma-old-win)
            echo $old_win
            if [ "$old_win" != 'SAME' ]; then
                xdotool windowfocus $old_win
            fi
      left:
        update:
          command: |-
              ydotool key --key-delay 0 29:1 109:1 109:0 29:0 # ctrl and PgDown
          threshold: 0.5
          interval: 1.7
      right:
        update:
          command: |-
              ydotool key --key-delay 0 29:1 104:1 104:0 29:0 # ctrl and PgUp
          threshold: 0.5
          interval: 1.7
      up:
          command: |-
              case $(xprop -id $id WM_CLASS | cut -d " -f 4) in
                  firefox|"Firefox Developer Edition"|"Tor Browser"|kitty)
                      ydotool key --key-delay 0 29:1 62:1 62:0 29:0
                      ;;
                  *)
                      ydotool key --key-delay 0 29:1 17:1 17:0 29:0
                      ;;
              esac
          threshold: 0.7
      down:
          command: |-
              case $(xprop -id $id WM_CLASS | cut -d " -f 4) in
                  Tilix|kitty|Guake)
                      ydotool key --key-delay 0 29:1 42:1 20:1 20:0 42:0 29:0
                      echo 'SAME' > "/var/run/user/$(id -u)/fusuma-old-win"
                      ;;
                  *)
                      ydotool key --key-delay 0 29:1 20:1 20:0 29:0
                      echo 'SAME' > "/var/run/user/$(id -u)/fusuma-old-win"
                      ;;
              esac
          threshold: 0.6

(I'm having the different shell commands communicate using "files" is /var/run/.)

The problem I was describing was mostly solved by replacing wmctrl -iR "$id" by xdotool windowfocus "$id", the latter seems to be much faster. But I expect that this will still cause trouble under load.

@ces42
Copy link
Contributor Author

ces42 commented Mar 24, 2023

Although I've been thinking that probably the best solution for my problems is to switch to a client-server model where fusuma just writes someting like 3finger-begin, 3finger-right, etc. to a named pipe and I have a separate process reading from it and executing what I want.

@iberianpig
Copy link
Owner

As you say, it would be nice to implement job-queue in separate processes.

Considering the cost of implementation, it also seems good to use waitpid #290 (comment)

libinput_command_input_plugin may be helpful for how to get values ​​from config.

"enable-dwt": [TrueClass, FalseClass],

enable_dwt = "--enable-dwt" if config_params(:"enable-dwt")

@ces42
Copy link
Contributor Author

ces42 commented Mar 25, 2023

I went ahead and wrote an executor plugin:

# frozen_string_literal: true

module Fusuma
  module Plugin
    module Executors
      # Server executor plugin
      class ServerExecutor < Executor

        # executor properties on config.yml
        # @return [Array<Symbol>]
        def execute_keys
          [:server]
        end

        def config_param_types
          {
            'pipe': [String],
          }
        end

        def initialize
          super()
          @pipe = config_params(:'pipe')
        end

        def execute(event)
          command = search_command(event)

          MultiLogger.info(server: command, args: event.record.args)

          File.write(@pipe, command.to_s + "\n")
        rescue SystemCallError => e
          MultiLogger.error("#{event.record.index.keys}": e.message.to_s)
        end

        def executable?(event)
          event.tag.end_with?("_detector") &&
            event.record.type == :index &&
            search_command(event)
        end

        # @param event [Event]
        # @return [String]
        def search_command(event)
          command_index = Config::Index.new([*event.record.index.keys, :server])
          Config.search(command_index)
        end

      end
    end
  end
end

(This is mostly copy pasted from command_executor, I don't really know any ruby). My config.yaml now is something like

swipe:
    3:
        begin:
          server: three_finger_begin
          interval: 0.1
        end:
          server: three_finger_end
        left:
          update:
            server: three_finger_left
            threshold: 0.5
            interval: 1.7
        right:
          update:
            server: three_finger_right
            threshold: 0.5
            interval: 1.7
        up:
            server: three_finger_up
            threshold: 0.7
        down:
            server: three_finger_down
            threshold: 0.6
plugin:
  executors:
    server_executor:
      pipe: /var/run/user/1000/fusuma_fifo

My "server" is currently just a sh process reading from that pipe after I have it source a file with function definitions.

@iberianpig
Copy link
Owner

Oh, you wrote a fusuma plugin without any knowledge of Ruby? That's amazing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants