Как сопоставить модификаторы (например, CTRL) с кнопками большого пальца мыши, используя xbindkeys

Этот вопрос уже задавался, но так и не был дан правильный ответ. После разрешения с @Seth я теперь спрашиваю это снова. Это позволит мне ответить и, возможно, изменить вопрос намного проще. Оригинальный вопрос можно найти здесь:

Привязать Ctrl и Alt к кнопкам большого пальца мыши


Выпуск:

Хотя очень просто сопоставить любые нажатия клавиш с кнопкой мыши, используя xbindkeys в сочетании с xdotool или же xte кажется намного более проблематичным сопоставить ключ модификатора (например, ALT, CTRL, SHIFT и т. д.) с ним.

Окончательное решение должно позволять нажатие клавиши CTRL + (например, для выбора нескольких записей в списке) только с помощью мыши.

Несколько возможных подходов к решению этой проблемы можно найти здесь, на Stack Exchange, а также на других форумах, связанных с Linux. Но ни одна из этих работ не работает так, как ожидалось, поскольку они приводят к другим проблемам и побочным эффектам.

Заметки:

Некоторые из приведенных ниже примеров включают в себя Guile с синтаксисом Scheme и полагаются на .xbindkeysrc.scm в то время как другие полагаются на .xbindkeysrc файл с соответствующим синтаксисом. Я знаю, что они не будут работать вместе.

Кроме того, нижеприведенные фрагменты опираются на xdotool только, но я открыт для подходов с участием других приложений, таких как, например, xte а также - хотя кажется, что оба приводят к тем же результатам, и поэтому я использую только xdotool действия здесь.

Подход А:

Обновление .xbindkeysrc файл с:

"xdotool keydown ctrl"
  b:8

"xdotool keyup ctrl"
  release + b:8

Это то, что я первоначально попробовал, но у него есть побочный эффект, что модификатор удерживается и не может быть освобожден.

Подход Б:

Обновление .xbindkeysrc.scm файл с:

(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")

Находится по адресу http://www.linuxforums.org/forum/hardware-peripherals/169773-solved-map-mouse-button-modifier-key.html и пытается решить проблему, где хранится модификатор (как описано в подходе а).

Хотя это исправляет, что это работает только частично, поскольку невозможно выполнить другие щелчки мыши, пока нажата кнопка большого пальца.

Подход C:

Обновление .xbindkeysrc файл с:

"xdotool keydown ctrl"
  b:8

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

Опробовано по OP связанного вопроса здесь, в askubuntu. Намного проще и надежнее, так как в нем нет состояний модификаторов. Тем не менее проблема остается, то есть нажатие CTRL + невозможно.

Кажется, что xbindkeys Сама проблема здесь, поскольку он распознает щелчок, но не выполнит его. Это можно проверить с помощью xev | grep button а также xbindkeys -v:

Обычный щелчок мыши, записанный xev должен выглядеть так:

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

Как и для кнопки большого пальца:

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

Но когда выше xbindkeys конфигурация включена, она ничего не записывает. Хотя это имеет смысл для кнопки большого пальца, поскольку она сопоставлена ​​с CTRL и, следовательно, больше не является кнопкой мыши, странно, что кнопка 1 также не записывается. Это, вероятно, потому что xbindkeys не выполняет это, но сам признает это:

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

Подход D:

Обновление .xbindkeysrc файл с:

"xdotool keydown ctrl"
  b:8

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

"xdotool click 1"
  b:1

Просто слишком просто... но приводит к бесконечной петле кликов.


ОБНОВИТЬ:

Тем временем я купил Logitech G502 и заметил, что после настройки через драйвер в Windows не только сам профиль сохраняется в памяти устройства, но и фактическое нажатие клавиши осуществляется мышью. Это фактически решило мою проблему в Linux!

Единственная другая мышь, которую я помню, которая была способна сделать это, была Razer Copperhead в те времена. Но я думаю, сегодня есть и другие мыши, которые могут сделать то же самое.

3 ответа

Я потратил много времени, пытаясь заставить эту обязательную работу работать. В конце концов я нашел решение, которое является сложным, но работает хорошо и не подразумевает стороннего программного обеспечения. Я делюсь этим здесь, надеясь, что это поможет людям. Кроме того, я знаю, что это не идеально с точки зрения безопасности, поэтому любая конструктивная обратная связь приветствуется.

Есть решения, которые действительно хороши, такие как предложенные здесь, но они всегда страдают от ограничений xbindkeys, которые захватывают всю мышь, делая неопределенными модификаторы + отображение щелчка мыши. Кроме того, решение на основе guile из приведенной выше ссылки использует ctrl + plus / ctrl + minus, который, например, не распознается Gimp.

Я понял, что нам нужна кнопка мыши, которая действует как клавиатура, поэтому я использовал uinput, к которому можно получить доступ через python, написал скрипт, который отслеживает / dev / my-mouse для нажатия кнопки большого пальца и посылает клавишу ctrl на виртуальную клавиатуру. Вот подробные шаги:

1. Сделать правила Udev

Мы хотим, чтобы устройства были доступны (права и местоположение).

Для мыши:

/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"

Udev будет искать устройство, распознаваемое ядром, с такими именами, как event5, и я выбираю мышь с именем. Инструкция SYMLINK гарантирует, что я найду свою мышь в /dev/my_mx_mouse. Устройство будет доступно для чтения участнику группы "mxgrabber".

Чтобы найти информацию о вашем оборудовании, вы должны запустить что-то вроде

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

Для ввода:

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

Нет необходимости в символической ссылке, uinput всегда будет в $/dev/uinput или же $/dev/input/uinput в зависимости от системы, на которой вы находитесь. Просто дайте ему группу и права читать и писать, конечно.

Вам нужно отключить - подключите вашу мышь, и новая ссылка должна появиться в /dev. Вы можете заставить udev запускать ваши правила с помощью $udevadm trigger

2. Активируйте модуль UINPUT

sudo modprobe uinput

И сделать его загрузочным постоянным:

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

3. Создать новую группу

sudo groupadd mxgrabber

Или как вы называли свою группу доступа. Тогда вы должны добавить себя к этому:

sudo usermod -aG mxgrabber your_login

4. Python скрипт

Вам необходимо установить библиотеку python-uinput (очевидно) и библиотеку python-evdev. Используйте pip или ваш дистрибутив.

Сценарий довольно прост, вам просто нужно идентифицировать event.code вашей кнопки.

#!/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. Наслаждайтесь!

Все, что вам сейчас нужно, это сделать исполняемый файл Python и попросить менеджера рабочего стола загрузить файл при запуске. Возможно также стакан вина, чтобы отпраздновать хорошую работу!

6. Дополнительно бесплатно

Я использую xbindkeys для дополнительного поведения. Например, следующая конфигурация может быть полезна, если у вас есть мышь с щелчками по колесу:

~/.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

Чтобы эта последняя комбинация работала, вы должны отключить кнопку, которую вы настроили для скрипта python, иначе она все равно будет захвачена xbindkeys. Должна остаться только клавиша Ctrl:

~/.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

Перезагрузить с $ xmodmap ~/.Xmodmap

7. Заключение

Как я уже говорил в начале, я не совсем доволен тем, что мне нужно дать себе права писать в / dev / uinput, даже если это группа mxgrabber. Я уверен, что есть более безопасный способ сделать это, но я не знаю как.

С другой стороны, это работает очень, очень хорошо. Любая комбинация клавиатуры или клавиши мыши, которая работает с клавишей Ctrl на клавиатуре, теперь работает с мышью!!

Я нашел решение с помощью PyUserInput. Это оказывается довольно простым и не требует прав администратора. С установленным Python 2 и PyUserInput я использовал следующий скрипт:

#!/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()

После предоставления прав на выполнение скрипта, я вызываю его с помощью строки в ~/.xsessionrc, например

~/path/to/script.py &

Примечание это не предотвращает срабатывание события кнопки мыши. В моем случае я использовал xinput set-button-map изменить отображение кнопок xinput и присвоить интересующий меня номер кнопки чему-то, что не использовалось.

Например, если вы хотите использовать кнопку 8 на вашей мыши, но кнопка 8 уже имеет функцию (например, page-next), вы можете использовать следующее .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 &

предоставленная кнопка 12 не имеет никакого значения для ОС, и назначить пользовательскую функцию для кнопки 12 в .xbuttonmodifier.pyСценарий, который я описал выше.

У меня есть частичное решение. Я не понял, как отменить отображение существующей кнопки, так что в итоге вы нажимаете кнопку и выбираете нужный вам модификатор. Так что, если эта кнопка мыши имеет какое-то существующее назначение, она все равно будет срабатывать. Например, переназначение правой кнопки мыши на управляющую клавишу приведет к отправке управляющего + щелчка.

Во всяком случае, я нашел сообщение на форуме, похожее на ваш вопрос, ответ на который должен был установить btnx и настроить ваши модификаторы через него. Похоже, btnx больше не доступен через репо. Существует ppa, но он не работает для последней версии Ubuntu.

Сообщение на форуме: post: http://ubuntuforums.org/showthread.php?t=1245930

Но источник доступен:

Вы можете скомпилировать его из исходного кода, но это поместит в вашу систему файлы, которые менеджер пакетов не сможет поддерживать.

А именно следующие файлы:

/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

Следующие символические ссылки:

/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

Так что... если вы не возражаете против строительства из источника...

Получите зависимости для btnx:

sudo apt-get install libdaemon-dev git

Если вы никогда не создавали ничего из исходного кода, вам также может понадобиться build-essential:

sudo apt-get install build-essential

Затем получите и скомпилируйте btnx:

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

У этого есть отдельный инструмент конфигурации GUI. Получите зависимости для этого:

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

Теперь получите и скомпилируйте инструмент конфигурации GUI:

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

Теперь запустите инструмент:

sudo btnx-config

Нажмите на кнопку "Определить мышь". Если вы хотите иметь возможность читать указания во время использования инструмента, измените размер всплывающего окна, текст диалога обрезается позже, если вы этого не сделаете, и если вы попытаетесь изменить размер во время обнаружения, он отменит обнаружение. Просто сделайте окно немного больше.

Нажмите на "Нажмите", чтобы начать обнаружение мыши, затем попытайтесь не перемещать мышь, пока текст не изменится... Займет около 5-10 секунд. Текст изменится. Когда это произойдет, проигнорируйте сказанное и нажмите "Вперед".

Нажмите кнопку "Нажмите, чтобы начать обнаружение кнопки"

Здесь вы будете нажимать одну кнопку мыши несколько раз (пока строка состояния не заполнится). Затем установите имя кнопки на то, что вы узнаете позже (например: LeftButton) Нажмите кнопку Добавить.

Повторите это для каждой кнопки мыши (не забывайте колесико прокрутки, щелчки прокрутки и т. Д.). Вы, вероятно, можете пропустить любые кнопки, которые вы не хотите переназначать.

Когда вы добавили все кнопки, нажмите OK.

В главном графическом интерфейсе нажмите кнопку "Кнопки", в левой панели выберите кнопку, которую хотите переназначить. Он будет использовать имена, которые вы ввели в предыдущих шагах. Для ваших целей, вы захотите выбрать только модификатор Key под комбинацией клавиш справа.

Не нажимайте кнопку "Удалить" на этом экране, она удалит кнопку. Вам придется вернуться и снова обнаружить кнопку, если вы это сделаете.

Вернитесь на экран Conrigurations и нажмите перезагрузить btnx.

Попробуйте новую кнопку.

Если вы хотите удалить приложения, остановите программу btnx, а затем перейдите в соответствующие каталоги git check out и выполните удаление:

sudo /etc/init.d/btnx stop
cd btnx
sudo make uninstall
cd -
cd btnx-config
sudo make uninstall
cd -

Есть метод для мыши Logitech, используйте неофициальный драйвер с именем logiops https://github.com/PixlOne/logiops (респект участникам) . Я обнаружил, что в этом проекте мои боковые кнопки идеально имитируют Ctrl и Shift.

Вот моя конфигурация. Я использую мышь M720, а cid:0x56 это кнопка вперед, а cid:0x53это кнопка назад. Дополнительную помощь можно найти в вики этой страницы репо.

devices: (
{
    name: "M720 Triathlon Multi-Device Mouse";
    buttons: (
        {
            cid: 0x56;
            action =
            {
                type: "Keypress";
                keys: ["KEY_LEFTCTRL"];
            };
        },
        {
            cid: 0x53;
            action =
            {
                type: "Keypress";
                keys: ["KEY_LEFTSHIFT"];
            };
        }
    );
    hiresscroll:
    {
        hires: true;
        invert: false;
        target: false;
    };
}
);
Другие вопросы по тегам