AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / unix / Perguntas / 793407
Accepted
Gridzbi Spudvetch
Gridzbi Spudvetch
Asked: 2025-04-07 07:03:20 +0800 CST2025-04-07 07:03:20 +0800 CST 2025-04-07 07:03:20 +0800 CST

Executando um script baseado em eventos brutos de um HID específico?

  • 772

Um problema um pouco estranho para você. Eu tenho um antigo tablet 2 em 1 que funciona bem, exceto que o driver da tela sensível ao toque trava ocasionalmente, deixando-o inutilizável. Tenho um script simples para reiniciá-lo, mas quando ele não está conectado ao teclado, isso pode ser um problema. Minha solução proposta é executar o script quando eu pressionar as duas teclas de volume físicas simultaneamente (sendo esses botões o único outro dispositivo de entrada que terei conectado de forma confiável). Estou usando o Fedora Wayland. Isso parece viável e, em caso afirmativo, como poderia ser feito?

scripting
  • 3 3 respostas
  • 284 Views

3 respostas

  • Voted
  1. grawity
    2025-04-07T15:59:03+08:002025-04-07T15:59:03+08:00

    Isso parece viável?

    Sim, você pode ler a entrada bruta da interface "evdev" em /dev/input/event*, usando libevdev ou diretamente dos nós do dispositivo, ou usando a biblioteca libinput de nível superior (que é mais útil para o pré-processamento de mouse/touchpad, mas não muito útil para botões).

    O programa pode ser escrito usando python-evdev (ou python-libevdev, ligeiramente diferente):

    #!/usr/bin/env python3
    import argparse
    import evdev
    import os
    
    def find_device(wanted_name):
        # libudev/GUDev would be a better way to do it but this is fine
        for path in evdev.list_devices():
            dev = evdev.InputDevice(path)
            if dev.name == wanted_name:
                return dev
            dev.close()
    
    dev = find_device("AT Translated Set 2 keyboard")
    btn1 = (evdev.ecodes.EV_KEY, evdev.ecodes.KEY_KPPLUS)
    btn2 = (evdev.ecodes.EV_KEY, evdev.ecodes.KEY_KPMINUS)
    cmd = "echo Yay"
    
    btn1_down = False
    btn2_down = False
    cmd_run = False
    for event in dev.read_loop():
        #print(evdev.categorize(event))
        if (event.type, event.code) == btn1:
            btn1_down = (event.value > 0)
            print(f"button 1 is now {btn1_down=}")
        elif (event.type, event.code) == btn2:
            btn2_down = (event.value > 0)
            print(f"button 2 is now {btn2_down=}")
    
        if btn1_down and btn2_down and (not cmd_run):
            print("buttons pressed")
            os.system(cmd)
            cmd_run = True
        elif (not btn1_down) and (not btn2_down) and cmd_run:
            print("buttons released")
            cmd_run = False
    

    As ferramentas CLI para determinar qual evento você precisa são evtestou evemu-record(ou libinput debug-eventscomo mencionado na outra resposta).

    Você também pode tentar um dos programas existentes de "remapeamento de teclas" baseados em evdev, caso alguns deles consigam mapear o pressionamento de tecla para a execução de um comando:

    • https://github.com/KarsMulder/evsieve (opção exec-shell)
    • https://wiki.archlinux.org/title/Input_remap_utilities

    Teclas de volume também podem aparecer como eventos ACPI, que podem ser manipulados usando acpid(uma lógica semelhante pode ser escrita como parte de /etc/acpi/handler.sh). Verifique se acpi_listenos relata.

    • 6
  2. nbanba
    2025-04-07T15:38:18+08:002025-04-07T15:38:18+08:00

    Dê uma olhada no libinput (você deve instalar o libinput-tools

    Com libinputvocê você pode detectar um evento e executar uma ação quando esse evento for detectado

    Por exemplo, aqui está a saída quando toco no meu touchpad:

    stdbuf -oL -eL libinput debug-events --device /dev/input/event6
    -event6   DEVICE_ADDED            SYNA2393:00 06CB:7A13 Touchpad    seat0 default group1  cap:pg  size 102x77mm tap(dl off) left scroll-nat scroll-2fg-edge click-buttonareas-clickfinger dwt-on dwtp-on
     event6   POINTER_MOTION          +0.014s    -0.68/  0.68 ( -1.00/ +1.00)
     event6   POINTER_MOTION          +0.021s    -1.76/  0.88 ( -2.00/ +1.00)
     ...
    

    Se você executar grep na saída do stdbufcomando e iniciar um script quando detectar alguns eventos específicos, você poderá fazer o que quiser

    NB: você pode redirecionar a saída para um descritor de arquivo que você pode ler mais tarde no bash (com read -u)

    Por exemplo:

    exec {fd0}< <(stdbuf -oL -eL libinput debug-events --device /dev/input/event6 | grep POINTER_MOTION)
    while read -u ${fd0}; do exec_my_action.sh ; done &
    
    • 4
  3. Best Answer
    Gridzbi Spudvetch
    2025-04-11T09:14:07+08:002025-04-11T09:14:07+08:00

    A solução completa para meus problemas específicos acaba sendo um par de scripts conectados entre si. O principal lida com o libinputlog de eventos (que é canalizado para ele) e executa o comando final:

    #!/usr/bin/env bash
    
    while read -r input_line
    do
      case "${input_line}" in
          *"KEY_VOLUMEUP (115) pressed") VUP=1  ;;
          *"KEY_VOLUMEDOWN (114) pressed") VDOWN=1  ;;
          *"KEY_VOLUMEUP (115) released") VUP=0 ;;
          *"KEY_VOLUMEDOWN (114) released") VDOWN=0 ;;
            "") ;;   # ignore empty lines
             *) ;;   # ignore other lines
      esac
      if [ ${VUP} == 1 ] && [ ${VDOWN} == 1 ]; then
          modprobe -r ipts;
          sleep 1;
          modprobe ipts;
          su - username -c "notify-send 'Touchscreen restarted.'";
      fi
    done
    

    Um segundo script supervisiona o primeiro:

    libinput debug-events --device $(libinput list-devices | awk -v name="Surface Pro 3/4 Buttons" '
      /^Device:/ { dev = substr($0, index($0, $2)); found = (dev == name) }
      found && /^Kernel:/ { print $2; exit }
    ') | (path to first script)
    

    O segundo script é objeto de um systemdserviço que o executa como root. Lembre-se de garantir que usuários não root não possam modificá-lo.

    • 1

relate perguntas

  • Verifique o histórico de login do usuário root

  • Uma maneira rápida de duplicar um site (Wordpress) no meu ambiente de servidor Nginx?

  • problema ao iniciar aplicativos: linha de comando vs. gui

  • Shell Script para encontrar string no arquivo de log

  • Renomeie (acrescentar) arquivos CSV em massa com base em um valor dentro

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Possível firmware ausente /lib/firmware/i915/* para o módulo i915

    • 3 respostas
  • Marko Smith

    Falha ao buscar o repositório de backports jessie

    • 4 respostas
  • Marko Smith

    Como exportar uma chave privada GPG e uma chave pública para um arquivo

    • 4 respostas
  • Marko Smith

    Como podemos executar um comando armazenado em uma variável?

    • 5 respostas
  • Marko Smith

    Como configurar o systemd-resolved e o systemd-networkd para usar o servidor DNS local para resolver domínios locais e o servidor DNS remoto para domínios remotos?

    • 3 respostas
  • Marko Smith

    apt-get update error no Kali Linux após a atualização do dist [duplicado]

    • 2 respostas
  • Marko Smith

    Como ver as últimas linhas x do log de serviço systemctl

    • 5 respostas
  • Marko Smith

    Nano - pule para o final do arquivo

    • 8 respostas
  • Marko Smith

    erro grub: você precisa carregar o kernel primeiro

    • 4 respostas
  • Marko Smith

    Como baixar o pacote não instalá-lo com o comando apt-get?

    • 7 respostas
  • Martin Hope
    user12345 Falha ao buscar o repositório de backports jessie 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl Por que a maioria dos exemplos do systemd contém WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky Como exportar uma chave privada GPG e uma chave pública para um arquivo 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll status systemctl mostra: "Estado: degradado" 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim Como podemos executar um comando armazenado em uma variável? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S Por que /dev/null é um arquivo? Por que sua função não é implementada como um programa simples? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 Como ver as últimas linhas x do log de serviço systemctl 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - pule para o final do arquivo 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla Por que verdadeiro e falso são tão grandes? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis Substitua a string em um arquivo de texto enorme (70 GB), uma linha 2017-12-30 06:58:33 +0800 CST

Hot tag

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve