1

Тема: AHK: Скролинг неактивного окна/Чем заменить PostMessage

Есть скрипт для прокрутки неактивного окна роликом.
Вот его урезанный вариант который работает, но не во всех программах.

#SingleInstance,Force
SetWinDelay,100  ; пробовал разные варианты не помогает

F1::
mousegetpos,,,win,ctrl       ; берем id окна и контрола
ControlFocus,%ctrl%,ahk_id %win%   ; переключаем фокус на этот контрол
PostMessage,0x115,1,0,%ctrl%,ahk_id %win%   ; отправляем контролу сообщение о прокрутке
tooltip,%win%`n"%ctrl%"`nE%errorlevel%    ; информация для отладки
return

Почему некоторые программы не воспринимают "PostMessage"? (XYplorer например)
И есть ли замена "PostMessage" чем можно скролить неактивные окна?

Win 10 x64
AHK
                       Справка AHK v1 тебе в помощь.

2

Re: AHK: Скролинг неактивного окна/Чем заменить PostMessage

А этот скрипт там тоже не работает?

3 (изменено: Alectric, 2013-11-02 21:05:22)

Re: AHK: Скролинг неактивного окна/Чем заменить PostMessage

Да работает, спасибо.
Но

  WinID:=DllCall("WindowFromPoint", "int", mX, "int", mY)      ; ID (handle) окна

эта часть кода считает что окно над которым курсор не существует (окно 1by1-плеера, и даже справка Autohotkey) и берет хэндл окна под ним.
Почему нельзя использовать хэндл выдаваемый "Mousegetpos"?
Я посмотрел - они отличаются друг от друга.

Win 7 x64
Autohotkey Version v1.1.13.01


И еще вопрос: Можно ли с помощью "DllCall" напрямую отправить окну "WM_MOUSEWHEEL" или "WM_VSCROLL" с указанием хэндла полученного от "MouseGetPos"?
(DllCall не получается изучить, слишком много там всего)


OFF: Не хватает у меня фантазии ключевые слова подбирать в поиске... да еще эта дурацкая задержка в 30 секунд просто убивает.


20 minuts later:
Нашел на каком-то форуме:

According to MSDN, WindowFromPoint() takes a POINT struct, defined as two 32 bit values (LONG). Since "int" is 32 bits in both x86 and x64, it would seem the argument sizes shouldn't need to be changed for x64. However, in AHK_L x64 (latest version 1.1.05.06), only the x argument has any effect, and as a result it returns hwnds only for windows along the top of the screen. 

Координата Y не передается функции на 64-х разрядных машинах, из-за этого все проблемы.

Win 10 x64
AHK
                       Справка AHK v1 тебе в помощь.

4 (изменено: YMP, 2013-11-02 10:16:19)

Re: AHK: Скролинг неактивного окна/Чем заменить PostMessage

Проблема в битности не машины, а AutoHotkey. У вас AutoHotkey x64? Вот этот вариант должен работать при любой битности.


WheelUp::
WheelDown::
    Critical
    If(A_ThisHotkey!=A_PriorHotkey || A_TimeSincePriorHotkey>40) ; Определить скорость
        Scroll:= A_ThisHotkey="WheelUp" ? 120<<16 : -120<<16     ; вращения колеса и
    Else                                                         ; задать скорость
        Scroll:= A_ThisHotkey="WheelUp" ? 240<<16 : -240<<16     ; прокрутки.

    CoordMode, Mouse, Screen
    MouseGetPos, mX, mY
    mX &= 0x00000000FFFFFFFF
    Point := mX | mY<<32
    WinID:=DllCall("WindowFromPoint", "int64", Point, "ptr")   ; ID (handle) окна
    Point := mX | (mY-20)<<32                                  ; под мышью.
    NextID:=DllCall("WindowFromPoint", "int64", Point, "ptr")
    mX &= 0x0000FFFF
    SendMessage, 0x20A, %Scroll%, (mY<<16)|mX,, ahk_id %WinID%   ; 0x20A = WM_MOUSEWHEEL
    If (!ErrorLevel && (WinID != NextID))
        SendMessage, 0x20A, %Scroll%, (mY<<16)|mX,, ahk_id %NextID%
Return

5

Re: AHK: Скролинг неактивного окна/Чем заменить PostMessage

Да так работает.
Спасибо большое.

Win 10 x64
AHK
                       Справка AHK v1 тебе в помощь.

6

Re: AHK: Скролинг неактивного окна/Чем заменить PostMessage

Немного исправил вычисление Point, чтобы корректно работало при отрицательных значениях Х. Насколько помню, они получаются, если Рабочий стол расширен на второй монитор, стоящий слева. К сожалению, нет сейчас возможности проверить. Отрицательные Y (если 2-й монитор сверху) проблем вызывать не должны.

7 (изменено: Alectric, 2020-11-05 20:16:59)

Re: AHK: Скролинг неактивного окна/Чем заменить PostMessage

Вот мой готовый вариант, который благодаря YMP'у может прокручивать что угодно, где угодно и без потери основных функций ролика в системе.


#SingleInstance,Force
#NoEnv
CoordMode,Mouse,Screen
DetectHiddenWindows,On
Menu,Tray,UseErrorLevel
SetBatchLines,-1
SetTitleMatchMode,2
SetWinDelay,-1
SetWorkingDir,%A_ScriptDir%
StringCaseSense,Off


scrollspeedup:=1


~*$WheelDown::
~*$WheelUp::
MouseGetPos,X,Y,mwin
WinGet,ActiveWin,id,A
stringtrimleft,Wheel,A_ThisHotkey,3
keywait,%Wheel%,L
if (whellwork=1)
  return
whellwork:=1
if !scrollspeedup
  scrollloop=1
else
{
  if A_TimeSincePriorHotkey<400
  {
    if (!speedup:=speedup>10 ? 0 : speedup="" ? 1 : speedup+1)
      scrollmulti++
  }
  if (A_TimeSincePriorHotkey>400 or A_ThisHotkey!=A_PriorHotkey)
  {
    scrollmulti=1
    speedup=
  }
  oldthishotkey:=a_thishotkey
  if scrollmulti>65
    scrollmulti=65
  if A_TimeSincePriorHotkey<17
    scrollloop=4
  else if A_TimeSincePriorHotkey<20
    scrollloop=3
  else if A_TimeSincePriorHotkey<30
    scrollloop=2
  else
    scrollloop=1
  scrollloop*=scrollmulti
}
if (A_OSVersion~="10.*?")
{
  if (scrollloop!=1)
  {
    if (Wheel="WheelUp")
      loop,% scrollloop
        mouseclick, WheelUp
    else
      loop,% scrollloop
        mouseclick, wheeldown
  }
}
else
{
  scroll:=Wheel="WheelUp" ? (120*scrollloop+1)<<16 : Wheel="WheelDown" ? -(120*scrollloop+1)<<16 : 0
  WheelWinID :=DllCall("WindowFromPoint","int64",(X&0x00000000FFFFFFFF)|(Y<<32),"ptr")
  WheelWinID2:=DllCall("WindowFromPoint","int64",(X&0x00000000FFFFFFFF)|((Y-20)<<32),"ptr")
  ControlGetFocus,focctrl,ahk_id %mwin%
  ControlGet,hfocctrl,Hwnd,,% focctrl,ahk_id %mwin%
  if (WheelWinID!=hfocctrl)
    ControlFocus,,ahk_id %WheelWinID%
  if (scroll!=0 and (scrollloop!=1 or ActiveWin!=mwin))
  {
    PoSTMessage,0x20A,Scroll,(X&0x0000FFFF)|(Y<<16),,ahk_id %WheelWinID%
    If (ErrorLevel or (WheelWinID!=WheelWinID2))
      PoSTMessage,0x20A,Scroll,(X&0x0000FFFF)|(Y<<16),,ahk_id %WheelWinID2%
  }
}
whellwork=0
return

Только нужно доработать режимы ускорения (сделать помягче).

Чуть не забыл. YMP, объясните пожалуйста что значит это выражение:

mX & 0x00000000FFFFFFFF | mY<<32

1) Для чего здесь добавляется 16-ричный код?
2) Какую функцию выполняет - | и &? В справке на этот счет мало информации.
3) Зачем Y умножать на 2 в степени 32?
И чему например будет равно выражение в итоге:

0x0011 | 0x0022

0x0033 или 0x1122 или 0x00110022?

Win 10 x64
AHK
                       Справка AHK v1 тебе в помощь.

8

Re: AHK: Скролинг неактивного окна/Чем заменить PostMessage

Ещё исправил и упростил. Перед WindowFromPoint mX урезается до 32 бит; перед SendMessage — до 16. Всё для того, чтобы корректно работали отрицательные значения Х. Возможно, нули в начале и не нужны, но я не знаю в подробностях, как AutoHotkey хранит и обрабатывает числа, и хотел бы как-то ему показать, какой разрядности число имею в виду.

1) Для чего здесь добавляется 16-ричный код?

Для отрезания верхних битов числа. У отрицательных чисел они заполнены единицами, соответственно, помещение туда Y оператором | (побитовое или) ничего не даст.

2) Какую функцию выполняет - | и &? В справке на этот счет мало информации.

Побитовое "или" и "и". В Википедии можно почитать, например.

3) Зачем Y умножать на 2 в степени 32?

Чтобы сдвинуть его в верхнюю половину 64-битного числа. WindowFromPoint принимает структуру POINT, состоящую из двух 32-битных чисел. Я её передаю в виде одного 64-битного числа. Но тут и возникают проблемы, если Х отрицательное.

И чему например будет равно выражение в итоге:

А что мешает проверить?

9 (изменено: Alectric, 2013-11-02 10:38:56)

Re: AHK: Скролинг неактивного окна/Чем заменить PostMessage

Спасибо за ответы.

YMP пишет:

А что мешает проверить?

Мешает то, что ahk выдает 10-ричное число на выходе.

a=0x0011
b=0x0022
c:=a|b
msgbox,%a%`n%b%`n"%c%"
Win 10 x64
AHK
                       Справка AHK v1 тебе в помощь.

10

Re: AHK: Скролинг неактивного окна/Чем заменить PostMessage

А вы попросите у него 16-ричное.

SetFormat, Integer, H
a=0x0011
b=0x0022
c:=a|b
msgbox,%a%`n%b%`n"%c%"

11 (изменено: Alectric, 2013-11-02 11:19:31)

Re: AHK: Скролинг неактивного окна/Чем заменить PostMessage

Спасибо. Не знал как это делается.

А можно ли обойтись без "SetFormat", т.к. он изменяет представление всех переменных, или придется повторно его использовать для возврата к десятичным?

Win 10 x64
AHK
                       Справка AHK v1 тебе в помощь.

12

Re: AHK: Скролинг неактивного окна/Чем заменить PostMessage

Да, придётся.

13 (изменено: Alectric, 2013-11-02 13:04:21)

Re: AHK: Скролинг неактивного окна/Чем заменить PostMessage

Еще вопрос:
Почему в "большом" скрипте если не поставить "CoordMode" для мыши непосредственно перед "MouseGetPos" - скрипт отказывается работать?
Я пытался использовать "CoordMode" только в "голове" скрипта.
Хотя при этом в "большом" скрипте нигде больше не используется "CoordMode".

Структура моего скрипта:

Условия
Переменные
Основной цикл в виде таймера
Горячие клавиши
Окно настройки, меню, и сохранение/чтение даных
Подпрограммы для перехода по GoSub
Функции

Может есть предложения как лучше "отсортировать скрипт"?

Win 10 x64
AHK
                       Справка AHK v1 тебе в помощь.

14

Re: AHK: Скролинг неактивного окна/Чем заменить PostMessage

Не знаю. В справке написано, что поставленная в начало она меняет дефолтную настройку.

15 (изменено: Alectric, 2013-11-02 13:03:42)

Re: AHK: Скролинг неактивного окна/Чем заменить PostMessage

Нашел, все-таки был еще 1 "CoordMode", но он был точно такой-же, т.е. привязка к экрану.

Значит использование "CoordMode" где-либо еще отменяет его в качестве дефолтного и приходится ставить его перед всеми "MouseGetPos".

Win 10 x64
AHK
                       Справка AHK v1 тебе в помощь.

16

Re: AHK: Скролинг неактивного окна/Чем заменить PostMessage

Не должна отменять. А процедуры хоткеев, пунктов меню, таймеров — это отдельные потоки и там эта команда только на сам поток действует. Функции выполняются в том потоке, из которого вызываются.

17

Re: AHK: Скролинг неактивного окна/Чем заменить PostMessage

Как только убрал тот лишний "CoordMode", тот что в начале скрипта заработал. Значит все-таки отменяет.

Win 10 x64
AHK
                       Справка AHK v1 тебе в помощь.

18

Re: AHK: Скролинг неактивного окна/Чем заменить PostMessage

Не знаю. Мои эксперименты этого не подтвердили.

19 (изменено: Alectric, 2013-11-02 14:25:26)

Re: AHK: Скролинг неактивного окна/Чем заменить PostMessage

Видимо слишком большой  у меня скрипт (2921 строка).

Win 10 x64
AHK
                       Справка AHK v1 тебе в помощь.