Como mapear modificadores (por exemplo, CTRL) para os botões do polegar do mouse usando xbindkeys

13

Esta pergunta já foi feita, mas nunca foi respondida corretamente. Após a liberação com @Seth, agora estou perguntando novamente. Isso me permitirá responder e possivelmente modificar a pergunta muito mais facilmente. A pergunta original pode ser encontrada aqui:

Mapeie Ctrl e Alt para os botões do polegar do mouse


Questão:

Embora seja muito simples mapear qualquer pressionamento de tecla para um botão do mouse usando xbindkeysem conjunto com xdotoolou xtepareça muito mais problemático mapear uma tecla modificadora (por exemplo , ALT , CTRL , SHIFT etc.) para ela.

A solução final deve permitir um clique CTRL + (por exemplo, para selecionar várias entradas de uma lista) com apenas o mouse.

Algumas abordagens possíveis para resolver isso podem ser encontradas aqui no Stack Exchange e em outros fóruns relacionados ao Linux. Mas nenhum deles funciona como esperado, pois leva a outros problemas e efeitos colaterais.

Notas:

Alguns dos exemplos abaixo envolvem a sintaxe do Guile com Scheme e dependem do .xbindkeysrc.scmarquivo, enquanto outros dependem do.xbindkeysrc arquivo com sua respectiva sintaxe. Estou ciente de que eles não vão trabalhar juntos.

Além disso, os trechos abaixo dependem xdotoolapenas, mas estou aberto a abordagens que envolvam outros aplicativos como, por exemplo xte, também - embora pareça levar aos mesmos resultados e, portanto, estou usando apenas xdotoolações aqui.

Abordagem A:

Atualizando o .xbindkeysrcarquivo com:

"xdotool keydown ctrl"
  b:8

"xdotool keyup ctrl"
  release + b:8

Foi o que eu tentei inicialmente, mas tem o efeito colateral de que o modificador está sendo mantido e não pode ser liberado.

Abordagem B:

Atualizando o .xbindkeysrc.scmarquivo com:

(xbindkey '("b:8") "xdotool keydown ctrl")
(xbindkey '(release "b:8") "xdotool keyup ctrl")

(xbindkey '("m:0x14" "b:8") "xdotool keydown ctrl")
(xbindkey '(release "m:0x14" "b:8") "xdotool keyup ctrl")

Encontrado em http://www.linuxforums.org/forum/hardware-peripherals/169773-solved-map-mouse-button-modifier-key.html e tenta resolver o problema em que o modificador está sendo mantido (conforme descrito na abordagem uma).

Embora conserte que ele funciona apenas parcialmente, pois não é possível executar outros cliques do mouse enquanto o botão do polegar é pressionado.

Abordagem C:

Atualizando o .xbindkeysrcarquivo com:

"xdotool keydown ctrl"
  b:8

"xdotool keyup ctrl"
  release + control + b:8

Tentei pelo OP da questão vinculada aqui no askubuntu. Muito mais simples e mais sólido, pois não envolve estados modificadores. No entanto, o problema permanece, ou seja, um clique CTRL + não é possível.

Parece que esse xbindkeysé o problema aqui, pois reconhece o clique, mas não o executa. Isso pode ser testado usando xev | grep buttone xbindkeys -v:

Um clique normal do mouse, conforme registrado por, xevdeve se parecer com:

state 0x10, button 1, same_screen YES
state 0x110, button 1, same_screen YES

Bem como para o botão do polegar:

state 0x10, button 8, same_screen YES
state 0x10, button 8, same_screen YES

Mas ao xbindkeysativar a configuração acima, ela não registra nada. Embora faça sentido para o botão do polegar, pois ele é mapeado para CTRL e, portanto, não é mais um botão do mouse, é estranho que o botão 1 também não seja gravado. Provavelmente, porque xbindkeysnão o executa, mas ele próprio o reconhece:

Button press !
e.xbutton.button=8
e.xbutton.state=16
"xdotool keydown ctrl"
    m:0x0 + b:8   (mouse)
got screen 0 for window 16d
Start program with fork+exec call
Button press !
e.xbutton.button=1
e.xbutton.state=20
Button release !
e.xbutton.button=1
e.xbutton.state=276
Button release !
e.xbutton.button=8
e.xbutton.state=20
"xdotool keyup ctrl"
    Release + m:0x4 + b:8   (mouse)
got screen 0 for window 16d
Start program with fork+exec call

Abordagem D:

Atualizando o .xbindkeysrcarquivo com:

"xdotool keydown ctrl"
  b:8

"xdotool keyup ctrl"
  release + control + b:8

"xdotool click 1"
  b:1

Simples demais ... mas leva a um loop infinito de cliques.


ATUALIZAR:

Enquanto isso, comprei um Logitech G502 e notei que, uma vez configurado através do driver no Windows, não apenas o perfil em si é armazenado na memória do dispositivo, mas o pressionamento de tecla real é feito pelo mouse. Isso de fato resolveu meu problema no Linux!

O único outro mouse que me lembro que foi capaz de fazer isso foi o Razer Copperhead na época. Mas acho que existem outros ratos disponíveis hoje que podem fazer o mesmo.

conceptdeluxe
fonte
1
aqui está uma solução usando Easystroke: askubuntu.com/a/1010647/27202
atti

Respostas:

8

Passei muito tempo tentando fazer essa ligação funcionar. Acabei encontrando uma solução que é complicada, mas funciona bem e não implica software de terceiros. Eu compartilho aqui esperando que ajude as pessoas. Além disso, sei que isso não é perfeito em termos de segurança, portanto, qualquer feedback construtivo é mais que bem-vindo.

Existem soluções realmente legais, como a proposta aqui , mas sempre sofrem com a limitação das xbindkeys que agarram o mouse inteiro, tornando incertos os modificadores + o mapeamento de cliques do mouse. Além disso, a solução baseada em guile do link acima usa ctrl + plus / ctrl + menos, que não é reconhecido pelo Gimp, por exemplo.

Eu descobri que o que queremos é um botão do mouse que atue como teclado, então usei o uinput, que pode ser acessado via python , escrevi um script que monitora / dev / my-mouse para o clique do botão polegar e envia a tecla ctrl para o teclado virtual. Aqui estão as etapas detalhadas:

1. Faça regras do udev

Queremos que os dispositivos estejam acessíveis (direitos e localização).

Para o mouse:

/etc/udev/rules.d/93-mxmouse.conf.rules
------------------------------------------------------------
KERNEL=="event[0-9]*", SUBSYSTEM=="input", SUBSYSTEMS=="input", 
ATTRS{name}=="Logitech Performance MX", SYMLINK+="my_mx_mouse", 
GROUP="mxgrabber", MODE="640"

O Udev procurará um dispositivo reconhecido pelo kernel com nomes como event5 e eu seleciono meu mouse com o nome. A instrução SYMLINK garante que encontrarei meu mouse em / dev / my_mx_mouse. O dispositivo será legível por um membro do grupo "mxgrabber".

Para encontrar informações sobre seu hardware, execute algo como

udevadm info -a -n /dev/input/eventX

Para entrada:

/etc/udev/rules.d/94-mxkey.rules
----------------------------------------------------
KERNEL=="uinput", GROUP="mxgrabber", MODE="660"

Não há necessidade de link simbólico, o uinput sempre estará dentro $/dev/uinputou$/dev/input/uinput dependendo do sistema em que você está. Apenas dê a ele o grupo e os direitos de ler e escrever, é claro.

Você precisa desconectar - conecte o mouse e o novo link deverá aparecer em / dev. Você pode forçar o udev a acionar suas regras com$udevadm trigger

2. Ative o módulo UINPUT

sudo modprobe uinput

E para tornar a inicialização persistente:

/etc/modules-load.d/uinput.conf
-----------------------------------------------
uinput

3. Crie um novo grupo

sudo groupadd mxgrabber

Ou o que você chamou de seu grupo de acesso. Então você deve se adicionar a ele:

sudo usermod -aG mxgrabber your_login

4. Script Python

Você precisa instalar a biblioteca python-uinput (obviamente) e a biblioteca python-evdev . Use pip ou seu pacote de distribuição.

O script é bastante simples, basta identificar o event.code do seu botão.

#!/usr/bin/python3.5
# -*- coding: utf-8 -*-

"""
Sort of mini driver.
Read a specific InputDevice (my_mx_mouse),
monitoring for special thumb button
Use uinput (virtual driver) to create a mini keyboard
Send ctrl keystroke on that keyboard
"""

from evdev import InputDevice, categorize, ecodes
import uinput

# Initialize keyboard, choosing used keys
ctrl_keyboard = uinput.Device([
    uinput.KEY_KEYBOARD,
    uinput.KEY_LEFTCTRL,
    uinput.KEY_F4,
    ])

# Sort of initialization click (not sure if mandatory)
# ( "I'm-a-keyboard key" )
ctrl_keyboard.emit_click(uinput.KEY_KEYBOARD)

# Useful to list input devices
#for i in range(0,15):
#    dev = InputDevice('/dev/input/event{}'.format(i))
#    print(dev)

# Declare device patch.
# I made a udev rule to assure it's always the same name
dev = InputDevice('/dev/my_mx_mouse')
#print(dev)
ctrlkey_on = False

# Infinite monitoring loop
for event in dev.read_loop():
    # My thumb button code (use "print(event)" to find)
    if event.code == 280 :
        # Button status, 1 is down, 0 is up
        if event.value == 1:
            ctrl_keyboard.emit(uinput.KEY_LEFTCTRL, 1)
            ctrlkey_on = True
        elif event.value == 0:
            ctrl_keyboard.emit(uinput.KEY_LEFTCTRL, 0)
            ctrlkey_on = False

5. Aproveite!

Tudo o que você precisa agora é tornar seu arquivo python executável e solicitar ao seu gerente da área de trabalho que carregue o arquivo na inicialização. Talvez também um copo de vinho para comemorar o bom trabalho!

6. Extra de graça

Eu uso xbindkeys para comportamento adicional. Por exemplo, a seguinte configuração pode ser boa se você tiver um mouse com cliques no lado da roda:

~/.xbindkeysrc
---------------------------------------------
# Navigate between tabs with side wheel buttons
"xdotool key ctrl+Tab"
  b:7
"xdotool key ctrl+shift+Tab"
  b:6

# Close tab with ctrl + right click
# --clearmodifiers ensure that ctrl state will be 
# restored if button is still pressed
"xdotool key --clearmodifiers ctrl+F4"
  control+b:3

Para que esta última combinação funcione, você deve desativar o botão que configurou para o script python , caso contrário, ele ainda será agarrado pelo xbindkeys. Somente a tecla Ctrl deve permanecer:

~/.Xmodmap
-------------------------------------------
! Disable button 13
! Is mapped to ctrl with uinput and python script
pointer = 1 2 3 4 5 6 7 8 9 10 11 12 0 14 15

Recarregar com $ xmodmap ~/.Xmodmap

7. Conclusão

Como eu disse no começo, não estou perfeitamente feliz com o fato de ter que me dar o direito de escrever para / dev / uinput, mesmo que seja considerado o grupo "mxgrabber". Tenho certeza de que há uma maneira mais segura de fazer isso, mas não sei como.

Pelo lado positivo, funciona muito, muito bem. Qualquer combinação de teclas do teclado ou do mouse que funcione com o botão Ctrl do teclado agora funciona com o do mouse !!

Aurélien Cibrario
fonte
Muito obrigado pelo esforço e por compartilhar conosco! +1 ... Embora eu ainda não o tenha testado. BTW eu quase desisti de este - seria ótimo se isso funciona como esperado :)
conceptdeluxe
Seja bem-vindo ! Para mim, funciona perfeitamente. Se você tiver problemas, me avise. Tento completar minha resposta, mas como passei quase dois dias tentando fazê-la funcionar, posso ter esquecido algo. Será um prazer ajudar / editar minha postagem.
Aurélien Cibrario
Acabei de perceber que ctrl + click1 era uma péssima opção para fechar uma guia, pois ela abriria um link em uma nova guia. Eu editei a minha resposta a remoção última parte do script python e ajustes com xbindkeys, solução mais limpa
Aurélien Cibrario
só quero que você saiba que ainda não tive tempo para testá-lo - mas com certeza a tornarei a resposta aceita, se funcionar como esperado - desculpe pela espera - estou um pouco ocupada
conceptdeluxe
Gostaria de saber se podemos usar o script acima para rejeitar um botão do mouse com defeito. Eu tenho um mouse desgastado. Eu uso um script de autohotkey para corrigi-lo no Windows, mas não há ferramenta para corrigi-lo no Linux. Aqui está Autohhotkey roteiro para os fix botão esquerdo autohotkey.com/board/topic/63555-debounce-mouse-keys Espero porto alguém para Linux usando python3 - evdev
kenn
4

Encontrei uma solução com PyUserInput . Isso acaba sendo bastante simples e não requer direitos de administração. Com o python 2 e o PyUserInput instalados, usei o seguinte script:

#!/usr/bin/python
from pymouse import PyMouseEvent
from pykeyboard import PyKeyboard

k = PyKeyboard()
class MouseToButton(PyMouseEvent):
    def click(self, x, y, button, press):
        if button == 8:
            if press:    # press
                k.press_key(k.control_l_key)
            else:        # release
                k.release_key(k.control_l_key)

C = MouseToButton()
C.run()

Depois de conceder direitos de execução ao script, chamo-o com uma linha ~/.xsessionrc, por exemplo

~ / caminho / para / script.py &

Nota . isso não impede que o evento do botão do mouse seja disparado. No meu caso, eu costumava xinput set-button-mapalterar o mapeamento do botão xinput e atribuir o número do botão no qual estava interessado a algo que não estava em uso.

Por exemplo, se você deseja usar o botão 8 do mouse, mas o botão 8 já tem uma função (por exemplo, page-next), você pode usar o seguinte.xsessionrc

logitech_mouse_id=$(xinput | grep "Logitech M705" | sed 's/^.*id=\([0-9]*\)[ \t].*$/\1/')
xinput set-button-map $logitech_mouse_id 1 2 3 4 5 6 7 12 9 10 11 12 13 14 15 16 17 18 19 20
./.xbuttonmodifier.py &

botão fornecido 12não tem significado para o sistema operacional, e atribuir uma função personalizada para o botão 12no .xbuttonmodifier.py, o script que eu descrevi acima.

Máxima
fonte
Mas isso não impede que o evento original seja disparado. Portanto, se eu mapear o botão 8 para alternar e manter pressionado o botão 8 no Firefox, ele também tentará voltar à página anterior, o que é indesejável.
user23013
1
Verdade. Para resolver isso, mudei o ID do botão em que estava interessado para um botão usado xinput. Veja a pergunta editada.
Maxim
2

Eu tenho uma solução parcial. Eu não descobri como remover o mapeamento do botão existente, então você acaba com um clique no botão e o modificador que deseja. Portanto, se esse botão do mouse tiver algum objetivo existente, ele ainda será acionado. Por exemplo, refazer o botão direito do mouse em uma tecla de controle resultará no envio de um controle + clique.

Enfim, encontrei uma postagem no fórum que é semelhante à sua pergunta para a qual a resposta foi instalar o btnx e configurar seus modificadores por meio disso. Parece que o btnx não está mais disponível no repositório. Existe um ppa, mas ele não funciona para o ubuntu mais recente.

Post do fórum: post: http://ubuntuforums.org/showthread.php?t=1245930

Mas a fonte está disponível:

Você pode compilá-lo da fonte, mas isso colocará arquivos em seu sistema que o gerenciador de pacotes não pode manter.

Ou seja, os seguintes arquivos:

/usr/local/sbin/btnx
/etc/init.d/btnx
/usr/share/pixmaps/btnx.png
/usr/share/btnx-config (directory, multiple files)
/usr/share/applications/btnx-config.desktop
/usr/share/omf/btnx-config/btnx-manual-C.omf
/usr/share/locale/de/LC_MESSAGES/btnx-config.mo
/usr/share/locale/fr/LC_MESSAGES/btnx-config.mo
/usr/share/locale/nl/LC_MESSAGES/btnx-config.mo
/usr/share/locale/ru/LC_MESSAGES/btnx-config.mo

Os seguintes links simbólicos:

/etc/rc0.d/K49btnx -> ../init.d/btnx
/etc/rc1.d/K49btnx -> ../init.d/btnx
/etc/rc6.d/K49btnx -> ../init.d/btnx
/etc/rc2.d/S49btnx -> ../init.d/btnx
/etc/rc3.d/S49btnx -> ../init.d/btnx
/etc/rc4.d/S49btnx -> ../init.d/btnx
/etc/rc5.d/S49btnx -> ../init.d/btnx

Então ... se você não se importa em construir a partir da fonte ...

Obtenha as dependências para o btnx:

sudo apt-get install libdaemon-dev git

Se você nunca criou nada a partir do código-fonte, também pode ser essencial para o build:

sudo apt-get install build-essential

Em seguida, obtenha e compile o btnx:

git clone https://github.com/cdobrich/btnx
cd btnx
./configure
make
sudo make install
cd -

Possui uma ferramenta de configuração da GUI separada. Obtenha as dependências para isso:

sudo apt-get install libgtk2.0-dev libglade2-dev

Agora obtenha e compile a ferramenta de configuração da GUI:

git clone https://github.com/cdobrich/btnx-config
./configure
make
sudo make install

Agora execute a ferramenta:

sudo btnx-config

Clique em Detectar botões do mouse Se você quiser ler as instruções enquanto usa a ferramenta, redimensione a janela exibida, o texto da caixa de diálogo será cortado posteriormente, se você não o fizer, e se tentar redimensionar durante a detecção, ele será cancelado. a detecção. Apenas faça a janela um pouco maior.

Clique em Pressione para iniciar a detecção do mouse e tente não mover o mouse até o texto mudar ... Demora cerca de 5 a 10 segundos. O texto mudará. Quando isso acontecer, ignore o que diz e clique em Avançar.

Clique no botão "Pressione para iniciar a detecção do botão"

Aqui você clicará em um botão do mouse várias vezes (até que a barra de status seja preenchida). Em seguida, defina o nome do botão para algo que você reconhecerá mais tarde (ex: Botão Esquerdo) Clique no botão Adicionar.

Repita isso para cada botão do mouse (não se esqueça das rodas de rolagem, cliques de rolagem etc.). Você provavelmente pode pular os botões que não deseja remapear.

Quando você adicionar todos os botões, clique em OK.

Na GUI principal, clique em Botões, no painel esquerdo, selecione o botão que você deseja remapear. Ele usará os nomes digitados nas etapas anteriores. Para seus propósitos, convém selecionar apenas um modificador de chave em Combinação de teclas à direita.

Não clique em Excluir nesta tela, ele removerá o botão. Você precisará voltar e detectar o botão novamente, se o fizer.

Volte para a tela Configurações e clique em reiniciar btnx.

Experimente o novo botão.

Se você deseja desinstalar os aplicativos, pare o programa btnx e, em seguida, vá para os respectivos diretórios com check-out do git e faça a desinstalação:

sudo /etc/init.d/btnx stop
cd btnx
sudo make uninstall
cd -
cd btnx-config
sudo make uninstall
cd -
Stephen
fonte
2
Muito obrigado pela resposta detalhada que você postou em pastebin. Mas tenho medo de não ter permissão para usar um ppa não confiável ou criar um aplicativo de fonte desconhecida sem revisá-lo em detalhes no meu dispositivo. No entanto, votarei pelo esforço que você fez. Além disso, recomendo que você atualize sua resposta aqui e copie o que escreveu lá, pois essas informações podem ser úteis para outras pessoas, mas podem ser ignoradas. Finalmente, li que o pacote pode nem ser compilado no Ubuntu ou Debian - você já tentou isso?
Conceptdeluxe
Btw: Você pode ganhar 100 reputação adicionais facilmente, vinculando sua conta askubuntu a outras contas Stack Exchange, como, por exemplo, Linux e Unix.
Conceptdeluxe
Sim, eu testei no Ubuntu 14.04. Fiz o botão direito do mouse enviar uma chave de controle e confirmei que funcionava antes de postar. E quase abandonou o cargo por causa do requisito de reputação.
Stephen