1 (изменено: tubudum, 2008-10-10 21:52:32)

Тема: AHK: Многодельность клавиши

В моем понимании одним из аспектов комфортной работы на компе является использование удобной многокнопочной мыши. Обзоводясь подобными устройствами, сталкивался с жутчайшим функционалом программного обеспечения, поставляемого с мышами многих производителей. Впрочем, сейчас даже благодарен "славным" дровописцам - ведь именно поиском вариантов и методов способствующих получить максимальную отдачу от своей мыши и обязан знакомству с AutoHotkey.
  Желая и не встретив обзора возможностей, решил свести воедино основные примеры настройки кнопок, разбросанные в разделах справки (и стало быть в переведенных статьях). Код также встречается на ветках этого форума, порой приводимый в другом контексте. На английском форуме есть приятно отсистематизированное местечко, где собраны интересные скрипты, разбитые по смысловым разделам, в частности - для МышеКустомайза Script Listing (Eng), раздел Mouse Related. Однако просто перечень прямых ссылок на материалы - это не обзор, поэтому обрисую азы настройки с простыми примерами. Замечу что каждый пример можно реализовать различными вариантами кодов, кои при желании можно найти или выдумать в великом множестве. Дополнительное уточнение: если примеры у вас не заработали (любые, а не только приведенные здесь) - выгрузите свои работающие скрипты, оттестите еще раз отдельно капризничающий скрипт, и если не работает как надо - отпишите авторам.

  Для начала, список клавиш и кнопок мыши/джойстика в переведенной статье KeyList, там же, в последнем разделе описан способ нахождения произвольной кнопки. Не ощутил разницы в том как обращаться к клавише, по ее имени, виртуальному коду или скан коду, однако рекомендую буквенные клавиши переназначать через код, а не по имени, тогда не будет зависимости от "раскладки по умолчанию", а пояснить какая это клавиша нетрудно в комментарии к этой строке.
  Замечание: USB-устройства желательно подключать через родной порт. При использовании переходников (USB-PS/2) может затеряться часть кнопок - скажем у мышки Logitech MX610 подключенной через переходник видятся 5 кнопок, а после втыкания в USB - 9. А некоторые устройства просто не будут работать.
  Иногда приходится изголяться с установкой и сносом дров и только потом кнопки определяются! Например мыши от Genius (Ergo 520, 525, уверен что R815 и возможно справедливо для R800).
  Кнопки, не найденные штатным способом, можно попытаться определить при помощи метода HID-device-support (Eng). Или на базе метода предыдущей ссылки (без излишеств) - Keyboard Media Keys (for USB HID devices!) (Eng). Оба для винды не ниже ХР. Правда наклоны колеса никак определить так и не смог.
  Когда определились, что собираемся настраивать, начинаем думать, как это будем делать.
  Мне видятся такие способы реализации:
  1. Действие от одиночного нажатия.
  2. Действие от двойного нажатия.
  3. Действие от удерживаемого нажатия.
  4. Действие по истечении заданного интервала, при удерживании клавиши в нажатом состоянии.
  5. Действие от комбинации с другой/другими клавишами.
  6. Действие от перемещения мыши с нажатой кнопкой.


    1. Действие от одиночного нажатия. Встречается везде и многократно, ну в частности - Tutorial and Overview, Remapping. Тем не менее, приведу код для иллюстрации:

; нажатие на скролл (среднюю кнопку мышки) вызывает появление окошка:
MButton:: MsgBox Нажатие средней кнопки мышки

1.1 Банальное одиночное нажатие все же можно расширить, задав, допустим, разные действия в зависимости от того, в каком месте экрана произошло нажатие.

MButton::
CoordMode,Mouse,Screen ; координаты относительно экрана
MouseGetPos,x,y ; позиция курсора мыши
; сравниваем координаты клика с полушириной и полувысотой экрана
if (A_ScreenWidth/2 > x and A_ScreenHeight/2 > y)
  MsgBox %A_ThisHotkey% нажат в верхней левой четверти экрана
if (A_ScreenWidth/2 < x and A_ScreenHeight/2 > y)
  MsgBox %A_ThisHotkey% нажат в верхней правой четверти экрана
if (A_ScreenWidth/2 > x and A_ScreenHeight/2 < y)
  MsgBox %A_ThisHotkey% нажат в нижней левой четверти экрана
if (A_ScreenWidth/2 < x and A_ScreenHeight/2 < y)
  MsgBox %A_ThisHotkey% нажат в нижней правой четверти экрана
Return

1.2 Или в каком месте окна:

MButton::
WinGetPos,,, Width, Height, A ; поиметь размеры активного окошка
MouseGetPos,x,y ; хватаем позицию курсора мыши
; сравниваем координаты клика с полушириной и полувысотой окна
if (Width/2 > x and Height/2 > y)
  MsgBox %A_ThisHotkey% нажат в верхней левой четверти окна
if (Width/2 < x and Height/2 > y)
  MsgBox %A_ThisHotkey% нажат в верхней правой четверти окна
if (Width/2 > x and Height/2 < y)
  MsgBox %A_ThisHotkey% нажат в нижней левой четверти окна
if (Width/2 < x and Height/2 < y)
  MsgBox %A_ThisHotkey% нажат в нижней правой четверти окна
Return

Хотя применение двум последним примерам вижу с трудом, ну разве что можно завести PgUp/PgDown и допустим Ctrl+Home/Ctrl+End в каких то определенных приложениях...
 
    1.3 Одиночное нажатие может выполнять последовательно чередующиеся действия:

MButton::
If keystroke = ; если у переменной нет значения
  {
    keystroke = 1 ; присвоим переменной новое значение
    MsgBox Первое действие
  }
Else if keystroke = 1 ; условие: если переменная имеет значение 1
  {
    keystroke = ; очищаем переменную, или если надо, присвоим ей иное значение
    MsgBox Второе действие ; производим действие
  }
;...
return

1.4 Действие клавиши может различаться в зависимости от того нажат ли модификатор Capslock, Numlock, Scrolllock или Insert. Переключателем состояния можно сделать и произвольную клавишу, доработав вышеприведенный пример.

MButton::
If GetKeyState("NumLock", "T") = 1 ; если включен NumLock
  MsgBox %A_ThisHotkey% нажат при включенном NumLock
If GetKeyState("NumLock", "T") = 0 ; если выключен
  MsgBox NumLock вЫключен, нажата клавиша %A_ThisHotkey%
Return

1.5 Вот еще одно расширение, позволяющее увеличить функционал клавиши, добавляя уникальное действие в зависимости от того, над чем в данный момент находится мышь (над каким контролом).

#IfWinActive, ahk_class SciCalc ; только в калькуляторе
Mbutton::
MouseGetPos,,,, control ; смотрим над каким контролом мышь
If control = Edit1 ; если над строкой результата, то
MsgBox,,, Скролл нажат над полем результата калькулятора., 2 ; то выполняем вот это
Else ; во всех остальных местах калькулятора
MsgBox,,, Нажатие на колесо в калькуляторе., 2 ; вот это
Return
#IfWinActive

2. Действие от двойного нажатия. В качестве иллюстрации - цитата из статьи AutoHotkey и русский язык – дружба навеки с превосходными комментариями автора - Androgen`а (или то же в последнем, четвертом примере статьи хелпа "KeyWait", не переведенной на данный момент).

У PuntoSwitcher'а конвертация неправильно введенных символов жестко прошита на клавишу Break, а в силу особенностей моей клавы и её расположения, мне нажимать Break неудобно. Вот скрипт, который переназначает конвертацию на двойное нажатие (как двойной клик) клавиши Ctrl:

~Control:: ; Control (ДВОЙНОЕ нажатие) - конвертировать введенные символы в punto switcher
if (A_PriorHotkey <> "~Control" or A_TimeSincePriorHotkey > 300)
; если предыдущая клавиша - не Control,
; или со времени нажатия Control прошло больше 300 миллисекунд, то...
{
  KeyWait, Control
  ;ожидать, пока клавиша не будет отпущена
  ;(чтобы исключить срабатывание от простого удержания нажатой клавиши)
  Return ; закончить обработку горячей клавиши после отжатия клавиши
}
; а вот если предыдущая клавиша - Control,
; и со времени нажатия Control прошло НЕ больше 300 миллисекунд, то...
KeyWait, Control
; ожидать пока клавиша не будет отпущена
; (чтобы исключить срабатывание от клавиши CTRL + исправляемые punto switcher'ом буквы)
Send, {Break} ; переключить раскладку
Return ; закончить обработку горячей клавиши

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


    3. Действие от удерживаемого нажатия клавиши.
  Упрощенно действие на нажатие и отжатие клавиши можно записать вот так:

MButton:: MsgBox НАжата средняя кнопка мышки ; НАжатие на колесико
MButton Up:: MsgBox средняя кнопка мышки ОТжата ; ОТжатие кнопки

Или оставляя работоспособным одиночный клик, добавляем действие от удерживаемого нажатия по отжатии:

MButton::
KeyWait, %A_ThisHotkey%, U T.5 ; ожидать отжатия клавиши 0,5 секунды
If ErrorLevel = 0 ; если отжата
  Msgbox действие от одиночного клика
Else ; если не отжата
  {
    KeyWait, %A_ThisHotkey%, U ; ждать отжатия
    MsgBox действие от удеживаемого клика по отжатии
  }
Return

4. Действие по истечении заданного интервала, при удерживании клавиши в нажатом состоянии.

MButton::
Sleep, 500 ; пауза
If GetKeyState("MButton","P") = 0 ; отслеживаем состояние - если кнопка отпущена
  MouseClick, M ; выполняем обычное действие
else ; в противном случае, то есть если после паузы клавиша в нажатом состоянии
  MsgBox, клавиша %A_ThisHotkey% нажата по истечении заданного периода ; само действие
Return

Код не лишен недостатка. За указанное время можно успеть кликнуть несколько раз и задержать последний клик, но это всего лишь простой пример для иллюстрации.


    5. Действие от комбинации с другой/другими клавишами.
  По поводу действия от парных сочетаний кнопок мыши на старом варианте этого форума (нынче этот код есть в статье "AutoHotkey: настройка мыши в браузере IE для переходов вперёд-назад", однако ценные, на мой взгляд, коментрарии опустили). Androgen писал следующее:

Пораскинул я мозгами, и кажется мне, что найти универсальное решение для всех подобных случаев (как поведение мыши в браузере IE) мне не удастся. Потому, что никакого "подобия" между различными прогами не существует. Т.е. по-разному обскриптовывать нужно чуть ли не каждую прогу, где возможна такая навигация мышью. Задача представляется выполнимой, но только с учетом особенностей целевой проги. А потому предлагаю конкретное решение конкретной задачи (для IE).
Первый способ очевидный, но имеющий ограничения. Вот он:

~LButton & RButton:: Send, !{Right} ; "вперед" (здесь есть тильда, поэтому левая мышь не блокируется для других приложений)
RButton & LButton::Send, !{Left} ; "назад" (здесь тильды нет, поэтому правая мышь блокируется)
$RButton:: Send, {RButton} ; нажимать RButton всегда, кроме тех случаев, когда она используется в горячих клавишах (здесь мы разблокируем правую мышь)

Однако если мы так поступим, то заблокируем выделение правой кнопкой в Total Commander`е (или других прогах, где правая мышь служит не только для вызова контекстного меню). Т.е. в этом случае правый клик будет высылаться только в момент отжатия правой кнопки, поэтому не получится нажать правую кнопку и протащить выделение по файлам/папкам.  Если это не смущает, то можно так и оставить. Тем более, что тогда "мышиная навигация" заработает и в Тотале. А если это ограничение не нравится, то можно сделать наши суперклики контекстно чувствительными (т.е. работающими только в конкретных окнах).
Для этого можно использовать второй способ:

SetTitleMatchMode, 2 ; сравнивать с любой частью заголовка окна
GroupAdd, Mouse_Group, Internet Explorer ahk_class IEFrame ; добавляем в мышиную группу окон Internet Explorer
GroupAdd, Mouse_Group, ahk_class HH Parent ; добавляем в мышиную группу окон справку (chm)
; ... тут добавляем еще какие-нибудь требуемые и подходящие под способ окна
#IfWinActive, ahk_group Mouse_Group ; делаем наши клавиши активными только в каком-либо окне из нашей группы
~LButton & RButton:: Send, !{Right} ; "вперед" (здесь есть тильда, поэтому левая мышь не блокируется для других приложений)
RButton & LButton::Send, !{Left} ; "назад" (здесь тильды нет, поэтому правая мышь блокируется)
$RButton:: Send, {RButton} ; нажимать RButton всегда, кроме тех случаев, когда она используется в горячих клавишах (здесь мы разблокируем правую мышь)
#IfWinActive ; снимаем контекстную зависимость горячих клавиш

Несколько комментариев.
- При добавлении в группу IE я указал часть заголовка его окна. Это потому, что, например, Maxthon тоже ahk_class IEFrame, а в нем можно назначать свои жесты мыши. В том числе и рассматриваемые. И если это не учесть, то его жесты перестанут работать.
- В группу можно добавить и Проводник, но "вперед" в нем работать не будет. Хотя, у меня есть заблуждение, что скриптописцев использующих Проводник не существует в природе
На этом задачу про IE можно считать решенной (у меня, во всяком случае все работает нормально). Если хочется таких же суперкликов и для других приложений, то см. первый абзац.

Если назначить действия на все возможные комбинации даже обычной трехкнопочной мыши (не забываем про вращение колеса - это очень удобный хоткей), да еще дополнив двойными или удерживаемыми по истечении периода кликами именно сочетаний (само собой в контексте от активного приложения), то получим очень даже крутой функционал от обычной мыши!
  Небольшое замечание: учтите что первая клавиша - префиксная и свое основное действие (от одиночного нажатия самой себя) выполняет после отжатия, т. е. при удерживании клавиши в нажатом состоянии НЕ будет происходить многократный посыл заведенной на нее функции - автоповтор. Нажмите и удерживайте любую буквенную (или цифровую) клавишу в каком нибудь текстовом редакторе - сразу поймете, что имею ввиду под автоповтором.
  Удерживаемое нажатие кнопок клавы/мыши может стандартно использоваться в некоторых программах, так что применение данного метода (впрочем как и любого другого) лучше производить для конкретного приложения.

    5.1 И еще один способ. Перебор клавиш (последовательное нажатие). Не нахожу его удобным, но в качестве варианта, достоин упоминания:

; клавиши клавиатуры: вверх, вниз, влево, вправо
Up::
Down::
Left::
Right::
SoundBeep ; известить звуком о нажатии клавиши
If (A_PriorHotkey <> A_ThisHotkey and A_TimeSincePriorHotkey <> -1 and A_TimeSincePriorHotkey < 500)
  MsgBox Последовательно нажаты клавиши %A_PriorHotkey% и %A_ThisHotkey%
Return

6. Действие от перемещения мыши с нажатой кнопкой.

MButton::
sensitivity=20 ; настройка чувствительности
MouseGetPos,x1,y1 ; хватаем позицию курсора мыши
Sleep,200
If GetKeyState(A_ThisHotkey, "P") = 0 ; если по окончании задержки клавиша отпущена
{
  MouseClick,Middle ; выполнить обычное действие клавиши
  ShowAction = %A_ThisHotkey% Click ; выставить переменной "ShowAction" значение для отображения в окошке
  Gosub,ShowToolTip ; пойти на "показуху" - раздел "ShowToolTip"
  Goto,RemoveToolTip ; перейти к завершающему разделу
}

Loop
{
  MouseGetPos,x2,y2 ; взять текущую позицию курсора
  ; назначаем разные действия по разнице начальных и конечных координат:

  If (x1-x2 > sensitivity and y1-y2 > sensitivity) ; вверх-влево
    {
      ShowAction = Up&Left
      Gosub,ShowToolTip
      ;Goto,RemoveToolTip ; раскомментирование этой строки делает действие ОДНОКРАТНЫМ, иначе повторяетcя пока клавиша нажата
    }
  If (x1-x2 < -sensitivity and y1-y2 > sensitivity) ; вверх-вправо
    {
      ShowAction = Up&Right
      Gosub,ShowToolTip
      ;Goto,RemoveToolTip
    }
  If (x1-x2 > sensitivity and y1-y2 < -sensitivity) ; вниз-влево
    {
      ShowAction = Down&Left
      Gosub,ShowToolTip
      ;Goto,RemoveToolTip
    }
  If (x1-x2 < -sensitivity and y1-y2 < -sensitivity) ; вниз-вправо
    {
      ShowAction = Down&Right
      Gosub,ShowToolTip
      ;Goto,RemoveToolTip
    }
  If (x1-x2 < sensitivity and y1-y2 > sensitivity) ; вверх
    {
      ShowAction = Up
      Gosub,ShowToolTip
      ;Goto,RemoveToolTip
    }
  If (x1-x2 < sensitivity and y1-y2 < -sensitivity) ; вниз
    {
      ShowAction = Down
      Gosub,ShowToolTip
      ;Goto,RemoveToolTip
    }
  If (x1-x2 > sensitivity and y1-y2 < sensitivity) ; влево
    {
      ShowAction = Left
      Gosub,ShowToolTip
      ;Goto,RemoveToolTip
    }
  If (x1-x2 < -sensitivity and y1-y2 < sensitivity) ; вправо
    {
      ShowAction = Right
      Gosub,ShowToolTip
      ;Goto,RemoveToolTip
    }
  If GetKeyState(A_ThisHotkey, "P") = 0 ; по отжатии
Goto,RemoveToolTip ; перейти к завершающему разделу
}

ShowToolTip: ; "ПОКАЗУХА"
; присваиваем конечные координаты начальным переменным
; для отслеживания изменения относительно нового положения курсора
  x1:=x2
  y1:=y2
  ToolTip %ShowAction% ; отображать ToolTip`ом название нажатой кнопке

RemoveToolTip:
  Sleep,100 ; задержка на отображение ToolTip
  ToolTip ; по истечении задержки убираем ToolTip
Return ; полный конец

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

    Объединение нескольких вариантов в один.
  Венцом моего скриптописательства в настраивании действий кнопок стала функция, объединяющая четыре первых варианта (утяжелять код перемещениями с нажатой кнопкой не стал - доработать самостоятельно, при желании несложно, но очень громоздко):

; функция с параметрами по умолчанию
KeyAction(app, delay_time = 99, holding_time = 30, dlclick_time = 300)
{
#MaxThreads 1 ; ограничиваем количество потоков, для избавления от мааленького глючка одновременного нажатия (перебора) пары хоткеев
global MyLabel ; делаем переменную глобальной, дабы вывести из функции значение

Loop ; смотрим в цикле сколько клавиша держится нажатой
{
  pressing_time += 1 ; добавляем в переменную по единице за каждый цикл
  ; то есть суммируем время удержания клавиши в нажатом состоянии
  Sleep, 10 ; минимальная задержка - время ожидания между опросами состояния нажатия клавиши
  If GetKeyState(A_ThisHotKey, "P") = 0 ; если клавиша отпущена
    Break ; прекратить цикл
  ; действие по истечении заданного интервала:
  If (pressing_time > delay_time) ; если клавиша удерживается нажатой больше определенного нами периода, то:
  {
    action = delay ; вносим в переменную тип отслеженного поведения клавиши
    GoTo, Complete ; перейти к метке
  }
}

; удерживаемое нажатие (срабатывающее при отжатии клавиши):
If (pressing_time > holding_time) ; если по отжатии клавиша удерживалась нажатой больше определенного нами периода, то:
{
  action = held ; вносим в переменную тип отслеженного поведения клавиши
  GoTo, Complete
}

; отслеживаем количество нажатий
Loop
{
  If GetKeyState(A_ThisHotKey, "P") = 1 ; если клавиша нажата (т. е. уже повторно нажата), то:
  {
    action = twice ; вносим в переменную отслеженное количество нажатий
    GoTo, Complete
  }
  If (A_TimeSinceThisHotkey > dlclick_time) ; если время прошедшее после нажатия хоткея больше заданного параметра (dlclick_time)
  Break ; прекратить цикл
}
; а ежели все вышеидущие условия не подходят,
; следовательно клавиша была нажата единожды
        action = once ; вносим в переменную отслеженное количество нажатий
        GoTo, Complete

Complete:
MyLabel = %A_ThisHotKey%_%action%_%app% ; создаем полное имя конечной переменной
If IsLabel(MyLabel) ; проверяем существование целевой метки
  Return
Else ; если нет метки с действием на приложение
  ; переходим к метке, выполняющей действие "по умолчанию"
  MyLabel = %A_ThisHotKey%_%action%_Default
  If IsLabel(MyLabel)
    Return
  Else
    MsgBox Заданный хоткей "%A_ThisHotKey%" нажат в приложении "%app%"
    , но ему не задано действие меткой "%A_ThisHotKey%_%action%_%app%"
}

Использование функции:

; укажите путь до файла или вставьте код функции:
;#Include d:\total\Progs\ahk\scripts\Functions\KeyAction().ahk ; функция многодельной кнопки
SetTitleMatchMode, 2 ; сравнивать с любой частью заголовка окна - иногда надо
SendMode Input ; новый режим высылки без задержки и повышенной надежности
#NoEnv ; запрещаем имена переменных как у переменных окружения
; перечисляем клавиши которые будут обрабатываться функцией:
MButton::
; и далее, какие нужны...

; вызывая функцию можно задать параметры
; все кроме первого необязательны - в функции указаны значения "`по умолчанию"
; первый - псевдоним приложения (ОБЯЗАТЕЛЕН ДЛЯ УКАЗАНИЯ)
; второй - время чувствительности удерживаемого клика,
; третий - время до действия от удерживаемого клика (вне зависимости от отжатия хоткея)
; четвертый - время между двойным кликом
; перечисляем приложения где будет работать скрипт и присваиваем переменной имя приложения,
; для обеспечения уникальности имени меток, которые будут выполнять действия

; вводим зависимость вызова функции от активных приложений,
; присваиваем приложениям названия, для создания уникальных меток,
IfWinActive, ahk_class TTOTAL_CMD ; в Total Commander`е
  {
    KeyAction("Total")
    GoTo %MyLabel%
  }
;...
Else ; во всех остальных случаях
  {
    KeyAction("Default",29) ; delay_time = 30 мс - действие по истечении заданного интервала
    GoTo %MyLabel%
  }

; и собственно действия:

; ~~~ Total Commander ~~~
MButton_delay_total:
MButton_held_total:
MButton_once_total:
MButton_twice_total:
  GoTo Message
Return

; и тут куча всех приложений

; ~~~ Default ~~~
; действия во всех остальных, не обговоренных выше приложениях:

; К примеру одна и та же кнопка - копировать/вставить/вырезать...
MButton_delay_Default:
MButton_held_Default:
  Send, ^{sc02F} ; вставить
Return
MButton_once_Default:
  Send, ^{vk43} ; копировать
Return
MButton_twice_Default:
  Send, ^{vk58sc02D} ; вырезать
Return

Message:
  MsgBox %MyLabel%
return

Неприятность: было бы удобно и приятно назначать клавиши каждому приложению в отведенных для него блоках (или даже в отдельных файлах) настроек отбивая с помощью #IfWinActive, однако это оказалось глючно - решения не нашел. Так можно настроить обычные клавиши клавиатуры и стандартные кнопки мыши (включая дополнительные XButton1 и XButton2). Однако при использовании директивы "#IfWinActive" мультимедийные клавиши на все действия начинают реагировать как на одиночный клик)! Чему был немало удивлен! Приходится менять на менее удобный синтаксис (приведенный выше в примере), тогда настраиваются и мультимедийные!
  Замечания к использованию функции:
  Настройки ограниченно возможны или невозможны вовсе разве что для кнопки Break/Pause а также, наверное, кнопкам управления электропитанием, таким как Power, WakeUp мож еще каким... у меня на клаве таких кнопищ нету - проверить не могу.
  Назначать действие самой кнопки на какой либо вариант действий можно путем высыла значений кодов ASCII (из таблицы символов в WinXP она в Пуск->Программы->Стандартные->Служебные->Таблица символов) - неудобно но работоспособно.
  То бишь скажем единицу (hex=0x31->dec=49 перевести можно даже стандартным калькулятором в инженерном виде) можно выслать вот так:

Send, {ASC 49} ; высыл ASCII-кода символа единицы

Однако плотно не тестил может при этом есть проблемы или подводные камни - меня это не волновало, ибо настраивал мультимедийные кнопки, а их дефолтное действие меня совершенно не интересует.
  Если вдруг возможностей функции и приведенных выше вариантов вдруг мало, то для расширения возможностей, можно завесить на какой-нибудь из вариантов действия "умный" скрипт, выводящий дополнительные опции, содержание которых можно ввести в зависимость от активного на данный момент приложения. Это можно сделать как в скрипте User Configurable Mouse Menu (этот скрипт внесен в раздел хелпа "Script Showcase" под названием "ToolTip Mouse Menu") или AutoHotkey: меню своих команд по средней кнопке мыши на рабочем столе или создать самому GUI-toolbar.
  Притом, возможно, удобно будет на последующие клики кнопки, вызвавшей появление данного меню назначить навигацию по этому меню (чтоб позицию пальца не менять). Выглядеть тогда будет как перебор вариантов букв клавиши телефона или что еще удобнее, осуществить навигацию по меню вращением колеса (предложение чисто гипотетическое, ибо заниматься этим не собираюсь - хоткеев достаточно).
  Зачастую использую лишь пару наиболее удобных действий - одиночный клик и действие производимое по истечении отведенного интервала. Считаю удобным отказаться от удерживаемого клика и уменьшить задержку до действия, выполняемого по прошествии интервала времени. Для этого достаточно сделать параметр функции delay_time <= holding_time, и вызвать функцию вот так:

  KeyAction("total", 30)

Удобство двойного клика напрямую зависит от расположения клавиши, скажем кнопка под мизинцем, по моему очень быстро утомит кисть (а результаты такой универсализации в попытке угодить и правшам-левшам встречаются часто).


  Итого.
  Даже не берусь предположить сколько можно слепить комбинаций из вышеприведенных способов. Однако это количество вызывает у меня смелое убеждение, что все их запомнить будет нереально.
  Однако несколько дополнительных действий на кнопках могут существенно увеличить комфорт! Когда функции продуманы они очень легко и быстро доходят до автоматизма. Приложение сознательных усилий в отслеживании куда надо нажать характерно для непродолжительного ознакомительного периода, а далее пальцы уже жмут интуитивно.
  Что касается настройки кнопок мышы - навешивание всех приходящих на ум действий вряд ли необходимо - порой проще, освободить вторую руку от подпирания падающей в ночи головы (или от бокала с кофе или от рюмки, а может и от ковыряния в носу), дотянуться до клавы и воспользоваться комбинацией клавиш. Тут очень уместен девиз "Все хорошо в меру".
  Все! Приятной настройки!