1 (изменено: stealzy, 2015-02-24 14:02:12)

Тема: AHK: Фиксим баг ControlGetFocus с залипанием клавиш и двойным кликом

Обратил внимание на зажатие(логическое), время от времени, некоторых клавиш - модификаторов при использовании нек. AHK - скриптов.
Приходилось клацать по "зажатым" клавишам, чтобы их "отжать".

Выяснилось, что повинна в этом поведении команда ControlGetFocus. Сама она клавиши не нажимает, но, каким-то образом, не дает отпускать нажатые(физически). Точнее, если во время работы команды была зажата клавиша-модификатор, есть вероятность, что она залипнет.

Небольшая функция, правящая сей недостаток —
— приводит логическое состояние клавиш к физическому:

+ source code
ControlGetFixBugUnpressKeys() {
    Static ArrayKeys
    ArrayKeys:=Object()
    ArrayKeys:=["RCtrl", "LCtrl", "LShift", "RShift", "RAlt", "LAlt"]
    i:= ArrayKeys.MaxIndex()
    Loop %i%
    {
        Key:=ArrayKeys[A_Index]
        GetKeyStatePhys := GetKeyState(Key, "P")
        GetKeyStateLogi := GetKeyState(Key)
        DiffKeyState := GetKeyStateLogi-GetKeyStatePhys
        if DiffKeyState {
            Direction := (DiffKeyState=1) ? "Up" : "Down"
            SendInput {%Key% %Direction%}
            ; MsgBox %Key% will be not %Direction%. I fix it.
        }
    }
}

-----------------------------------------------
UPD: в другой ветке Irbis радикально сократил объем кода:

+ открыть спойлер

FixBugUnpressKeys() {
   for key, key in ["RCtrl", "LCtrl", "LShift", "RShift", "RAlt", "LAlt"]
      if Direction := [0,0,"Up"][2+GetKeyState(Key)-GetKeyState(Key, "P")]
         SendInput {%Key% %Direction%}
}

-----------------------------------------------
UPD2: ниже Alectric предложил альтернативу ControlGetFocus с помощью DllCall,
почти? не страдающую этим недостатком,
+ работает двойной клик (известная проблема ControlGetFocus),
- работает на 16мс дольше.

controlgetfocus bug nipped pressed down keys

2

Re: AHK: Фиксим баг ControlGetFocus с залипанием клавиш и двойным кликом

А предоставьте наипростейший код, который бы демонстрировал баг (пускай и не всегда).

3 (изменено: stealzy, 2015-01-31 07:01:54)

Re: AHK: Фиксим баг ControlGetFocus с залипанием клавиш и двойным кликом

Запустите и поработайте какое-то время. Используйте клавиши Ctrl, Alt и Shift.
Не залипают?

Loop {
Sleep 50
ControlGetFocus, focusElement, A
}

4

Re: AHK: Фиксим баг ControlGetFocus с залипанием клавиш и двойным кликом

В момент "взятия фокуса" двойной клик не работает...

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

5

Re: AHK: Фиксим баг ControlGetFocus с залипанием клавиш и двойным кликом

stealzy пишет:

Если во время работы команды была зажата клавиша-модификатор, вполне вероятно, что она залипнет.

Что-то такое припоминаю, но без использования ControlGetFocus. В скрипте имеются горячие клавиши?

6 (изменено: Drugoy, 2015-01-31 18:22:31)

Re: AHK: Фиксим баг ControlGetFocus с залипанием клавиш и двойным кликом

stealzy пишет:

Запустите и поработайте какое-то время. Используйте клавиши Ctrl, Alt и Shift.
Не залипают?

Нет, не залипают.

Alectric пишет:

В момент "взятия фокуса" двойной клик не работает...

Подтверждаю. Но не везде: не могу открыть что-либо с рабочего стола двойным кликом и в TotalCommander'е перестал двойной клик работать, а в остальных местах вроде бы всё ок.

7 (изменено: stealzy, 2015-01-31 22:56:59)

Re: AHK: Фиксим баг ControlGetFocus с залипанием клавиш и двойным кликом

ypppu пишет:

Что-то такое припоминаю, но без использования ControlGetFocus. В скрипте имеются горячие клавиши?

Имееются. У меня без использования ControlGetFocus все ок.
2 Drugoy: хорошо вам.
Про двойной клик это давно известная проблема, если увеличить интервал между командами, будет незаметно. А залипания (у меня) остаются.

8

Re: AHK: Фиксим баг ControlGetFocus с залипанием клавиш и двойным кликом

Бывает, когда "горячая клавиша" состоит из сочетания нескольких клавиш, случаются залипания. В частности, когда одновременно нажимается несколько клавиш, часть которых входит в состав "горячей клавиши". Как-то так.

9

Re: AHK: Фиксим баг ControlGetFocus с залипанием клавиш и двойным кликом

stealzy пишет:

Выяснилось, что повинна в таком неподобающем поведении команда ControlGetFocus.

Вот замена для ControlGetFocus:


loop
{
  sleep,30
  mousegetpos,,,mwin,mctrl

  fctrl:=GetFocusedClassNN(mwin)

  tooltip,Под мышкой: "%mctrl%"`n    В фокусе: "%fctrl%"
}


GetFocusedClassNN(hwindow)
{
  GuiThreadInfoSize := 24 + (A_PtrSize * 6)
  VarSetCapacity(GuiThreadInfo, GuiThreadInfoSize)
  NumPut(GuiThreadInfoSize, GuiThreadInfo, 0)
  GuiThreadID:=DllCall("GetWindowThreadProcessId",ptr, hwindow,int,0)
  if DllCall("GetGUIThreadInfo", uint, GuiThreadID, ptr, &GuiThreadInfo)
  {
    WinGet, ClassNNList, ControlList, ahk_id %hwindow%
    Loop, PARSE, ClassNNList, `n
    {
      ControlGet, hwnd, hwnd,,%A_LoopField%,ahk_id %hwindow%
      if (hWnd = NumGet(GuiThreadInfo, 8 + A_PtrSize))
        return A_LoopField
    }
  }
}
Win 10 x64
AHK v1.1.33.02
                       Справка тебе в помощь.

10 (изменено: stealzy, 2015-02-14 13:45:36)

Re: AHK: Фиксим баг ControlGetFocus с залипанием клавиш и двойным кликом

Провел сравнительный тест на 1000 циклов — ваш вариант vs ControlGetFocus.
Поскольку ControlGetFocus работал  на 16мс быстрее, добавил к нему соответствующий sleep.

Результат: ControlGetFocus - стабильные залипания; DllCall - залипаний не обнаружено.
Взял на вооружение, спасибо!
------------------------------------------------------------
Есть некоторые проблемы с понимаем DllCall.
Вот как я распарсил ваш код:

GuiThreadInfoSize := 24 + (A_PtrSize * 6)

; устанавливаем размер в 24+4*6 (32-bit)
; судя по тому, что в GUITHREADINFO structure 9 элементов
; из них 6 типа HWND, можно сделать вывод, что HWND зависит от битности системы, а DWORD и RECT занимают по 8 bit.

VarSetCapacity(GuiThreadInfo, GuiThreadInfoSize)

; объявляем перем. GuiThreadInfo размером %GuiThreadInfoSize%

NumPut(GuiThreadInfoSize, GuiThreadInfo, 0)

; присваиваем GuiThreadInfo значение GuiThreadInfoSize.
Но ведь туда будет возвращено значение из функции, т.е. она должна быть пустой. Понял, переменной присвоен адрес, по которому будет возращено значение.
Почему именно по этому адресу? Почему не по адресу 12345?
Номер адреса возврата должен всегда совпадать с размером возращаемой структуры?

+ дальше понятно
GuiThreadID:=DllCall("GetWindowThreadProcessId",ptr, HwndMain,int,0)
; получаем Id процесса
if DllCall("GetGUIThreadInfo", uint, GuiThreadID, ptr, &GuiThreadInfo)
; передаем id, и указатель на структуру,
; куда будет возвращено значение
  {
    WinGet, ClassNNList, ControlList, ahk_id %HwndMain%
    Loop, PARSE, ClassNNList, `n
    {
      ControlGet, hwnd, hwnd,,%A_LoopField%,ahk_id %HwndMain%
      if (hWnd = NumGet(GuiThreadInfo, 8 + A_PtrSize))
; получаем id из структуры GuiThreadInfo со смещением 8 + A_PtrSize:
; понятно, там находится hwndFocus
}

11 (изменено: Alectric, 2015-02-14 14:04:52)

Re: AHK: Фиксим баг ControlGetFocus с залипанием клавиш и двойным кликом

Понял, переменной присвоен адрес, по которому будет возращено значение.
Почему именно по этому адресу? Почему не по адресу 12345?

При создании любой переменной ей дается адрес в памяти процесса самого скрипта. (на сколько я знаю)

Номер адреса возврата должен всегда совпадать с размером возращаемой структуры?

Как я уже сказал выше, переменная получает адрес, затем VarSetCapacity расширяет место этой переменной (т.е. последующие адреса становятся частью переменной, например: адрес переменной 0x4000 -> соответственно 0x4001...0x4100 (смотря сколько дала VarSetCapacity) будет являться частью переменной).

Может я ошибаюсь в терминах, сам еще не разобрался во всем.
Функции данные взял из свежей справки и дописал к ним, чтобы можно было указывать hwnd окна, изначально функция использовала текущий поток.

NumPut(GuiThreadInfoSize, GuiThreadInfo, 0)

Меняет формат содержимого переменной насколько я знаю. (надо еще справку почитать...)

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

12

Re: AHK: Фиксим баг ControlGetFocus с залипанием клавиш и двойным кликом

NumPut(GuiThreadInfoSize, GuiThreadInfo, 0)

Кажется понял: записывает в начало содержимого переменной ее собственный размер, видимо для того чтобы dllcall знал сколько он сможет туда записать (конечный адрес переменной).

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

13

Re: AHK: Фиксим баг ControlGetFocus с залипанием клавиш и двойным кликом

http://forum.script-coding.com/viewtopi … 576#p91576

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

14

Re: AHK: Фиксим баг ControlGetFocus с залипанием клавиш и двойным кликом

Отрапортовал lexikos'у о баге. Баг был исправлен в версии 1.1.19.0.3.

15

Re: AHK: Фиксим баг ControlGetFocus с залипанием клавиш и двойным кликом

Отлично, заодно и работа с A_CaretX & A_CaretY стала намного проще  - многие "костыли" стали не нужны.
Вообще, изменений много, что не может не радовать. )) Рекомендую заглянуть в ChangeLog АНК 1.1.20.x, для более подробного ознакомления.