В двух словах: перемещаем документ зажатым колесом мыши в Microsoft Office с помощью скрипта на Autohotkey.
Введение
При работе в дизайнерских программах, при просмотре карт или PDF-документов Вы можете передвигать чертёж/карту/документ при зажатой кнопке мыши. В CADах это обычно средняя кнопка, в PDF — левая, в 2gis — левая или правая.
Обычно за включение этого режима отвечает кнопка с иконкой руки (panning hand), вроде такой:
Однако в офисных приложениях нажатие на колесо вызывает режим прокрутки, когда документ начинает ползти в сторону перемещения мыши, что не всегда удобно. Попробуем вернуть «нормальное» поведение колеса в приложениях Microsoft Office.
Word
С word-ом проще всего. Функция «рука» встроена в ворд, она называется «Режим панорамирования»:
В этом режиме удобно редактировать графические элементы в word при большом увеличении. Если функция панорамирования в ворде нужна Вам периодически, то можно вынести её на панель быстрого доступа (см. картинку выше). А чтобы назначить эту функцию на среднюю кнопку мыши, используем следующий скрипт AHK:
#HotIf WinActive("ahk_class OpusApp") ; Когда открыт Word...
MButton:: WordPan()
WordPan(*) {
if !(wd := GetWord()) ; Если ворд не берётся,
return ; то выход
try {
WD.ActiveWindow.View.Panning := True ; рука вкл
Click "down" ; зажали ЛКМ
KeyWait "MButton" ; ждём отпускания колеса
Click "up" ; отжали лкм
WD.ActiveWindow.View.Panning := False ; рука выкл
}
}
GetWord(Force:=0) {
static wd := ""
return GetComApp(&wd, force, "Word.Application", "Word")
}
В скрипте используется функция GetComApp
Visio
В visio тоже несложно использовать «руку», но она активируется странным сочетанием Ctrl+Shift+Правая кнопка мыши. Поменяем на среднюю кнопку:
#HotIf WinActive("ahk_class VISIOA")
MButton:: {
SendInput "{Ctrl down}{Shift down}"
Sleep 20
Send "{Rbutton down}"
KeyWait "MButton"
Send "{Rbutton up}"
SendInput "{Ctrl up}{Shift up}"
}
Для большего сходства с автокадом включите опцию «Панорамирование с помощью IntelliMouse» в настройках visio, чтобы поворот колеса менял увеличение:
Excel
А теперь начинается самое интересное. В экселе режима руки нет, хотя он был бы очень кстати для прокрутки широких таблиц влево-вправо. С другой стороны, в Excel имеется поддержка клавиши ScrollLock. Когда Scroll Lock активен (индикатор на клавиатуре горит), клавиши управления курсором ↑↓←→ не передвигают выделение, а осуществляют прокрутку листа, при этом выделение не сбивается. Попробуйте сами. Excel — одна из немногих программ, где работает Scroll Lock.
А ведь это решение! При зажатии колеса мыши мы будем активировать режим Scroll Lock, а при отжатии — снимать его. Останется периодически опрашивать положение мыши, и, если она передвинулась, сдвигать лист в соответствующую сторону клавишами ↑↓←→. Скрипт для Excel:
#HotIf WinActive("ahk_class XLMAIN") ; Excel
MButton:: ScrollLockPan ; Панорамирование СкроллЛоком
ScrollLockPan() {
static XT := 30 ; Порог обнаружения движения мыши (пикселей)
static YT := 30
static MPOLLING := 50 ; Частота опроса мыши, мс
mx0:=my0:=mx1:=my1 := 0 ; Начальные и конечные координаты мыши
MouseGetPos &mx0, &my0
SetScrollLockState 1 ; Скролл лок ВКЛ
Loop {
Sleep MPOLLING
if !GetKeyState("MButton", "P") { ; Если колесо отпущено,
SetScrollLockState 0 ; отключаем скролл лок
return ; и выходим
}
MouseGetPos &mx1, &my1
dx := mx1-mx0
dy := my1-my0
dx := round(dx/XT*1) ; Здесь значения можно подобрать по вкусу
dy := round(dy/YT*4) ; Я умножил на 4, чтобы по вертикали двигалось поживее
;tooltip "dx " dx " dy " dy
if dX > 0 {
Send "{Left " dX "}" ; Нажимаем «влево» нужное число раз (в dX — число)
} else if dX < 0 {
Send "{Right " abs(dX) "}"
}
if dY > 0 {
Send "{Up " dY "}"
} else if dY < 0 {
Send "{Down " abs(dY) "}"
}
mx0 := mx1
my0 := my1
}
}
Разумеется, перемещение листа будет не плавным, как в Word или Visio, а скачками: целыми колонками и строчками сразу. Также сдвиг не будет численно соответствовать количеству пикселей, на которые переместилась мышь. Да это и невозможно, ведь в общем случае все колонки имеют разную ширину, а строки отличаются по высоте.
Отрегулируйте параметры задержки (MPOLLING), порогов (XT, YT) и множители в формулах определения dX/dY так, как Вам будет удобнее.
PowerPoint
В PowerPoint тоже нет функции «рука». Действуем аналогично: опрашиваем положение мыши, вычисляем сдвиг, но вместо ScrollLock вызываем функцию SmallScroll, передавая в неё величину сдвигов:
#HotIf WinActive("ahk_class PPTFrameClass") ; PowerPoint 2010+
MButton:: ComPanP(GetPoint())
#HotIf WinActive("ahk_class PP12FrameClass") ; PowerPoint 2007
MButton:: ComPanP(GetPoint())
ComPanP(App) { ; Панорамирование для PowerPoint
static XT := 20 ; Это для панорамирования колёсиком
static YT := 20
static MPOLLING := 50
mx0:=mx1:=my0:=my1:=0
MouseGetPos &mx0, &my0
if !GetKeyState("MButton", "P")
return
loop {
sleep MPOLLING
MouseGetPos &mx1, &my1
dx := mx1-mx0
dy := my1-my0
if !GetKeyState("MButton", "P")
return
dx := round(dx/XT*2)
dy := round(dy/YT*4)
;tooltip "dx " dx " dy " dy
if (dX||dY) {
try {
App.ActiveWindow.SmallScroll -dY, dY, -dX, dX ; Отрицательные значения не воспринимает
} catch {
Tooltip "Отпустите кнопку и начните ещё раз!"
KeyWait "MButton"
Sleep 50
SendLevel 1
SendEvent "^+{MButton}"
SendLevel 0
Tooltip
return
}
mx0 := mx1
my0 := my1
}
}
}
GetPoint(Force:=0) {
static pp := ""
return GetComApp(&pp, force, "PowerPoint.Application", "PowerPoint", "PP_")
}
Аналогично, параметры настраиваем по вкусу.
В powerpoint есть неприятная особенность: слайд переключатся на следующий, если прокрутить в самый низ или верх слайда. См. Как отключить переход к следующему слайду колёсиком в PowerPoint.
Другие программы
Использованный приём с регулярным опросом мыши можно распространить и на другие приложения, где Вам хотелось бы добавить панорамирование. Вопрос в том, как сообщать программе, что мы хотим сдвинуть её окно. Один из способов сделать это — послать окну программы сообщение о прокрутке:
PostMessage 0x114, 1, 0, ctrl, win
Здесь 0x114 — горизонтальная прокрутка (0x115 — вертикальная),
1 — направление,
ctrl — id элемента управления
win — HWND окна.
Узнать id элемента управления можно задав ClassNN, полученный с помощью утилиты Window spy из комплекта программы AutoHotKey:
Ниже пример скрипта для WordPad. Маловероятно, что Вам захочется панорамировать WordPad, но как пример подойдёт:
#HotIf WinActive("ahk_class WordPadClass") ; WordPad
MButton::PanWordPad()
PanWordPad(*) {
static XT := 30
static YT := 30
static MOUSEPOLLING := 50
mx0:=my0:=mx1:=my1:=0
win := WinGetID("A") ; получим id активного окна
ctrl := ControlGetHWND("RICHEDIT50W1", win) ; получим id основного элемента управления, который двигать будем
MouseGetPos &mx0, &my0
Loop {
Sleep MOUSEPOLLING
if !GetKeyState("MButton", "P") {
return
}
MouseGetPos &mx1, &my1
dx := mx1-mx0
dy := my1-my0
dx := -round(dx/XT*3)
dy := -round(dy/YT*1)
;tooltip "dx " dx " dy " dy
if (dX||dY) {
if dX > 0 {
loop dX
PostMessage 0x114, 1, 0, ctrl, win ; вправо
} else if dX < 0 {
loop abs(dX)
PostMessage 0x114, 0, 0, ctrl, win ; влево
}
if dY > 0 {
loop dY
PostMessage 0x115, 1, 0, ctrl, win ; вниз
} else if dY < 0 {
loop abs(dY)
PostMessage 0x115, 0, 0, ctrl, win ; вверх
}
}
mx0 := mx1
my0 := my1
}
}
Скрипты проверялись в AutoHotKey 2.0.2