1 (изменено: serzh82saratov, 2017-07-06 17:13:15)

Тема: AHK: Замена стандартного элемента управления "Hotkey"

Известно, что встроенный элемент управления GUI - "Hotkey" имеет большие ограничения по количеству определяемых клавиш. Более того всё равно приходится переделывать его записи буквенных клавиш в коды, и при чтении обратно - т.к. при несоответствующей записи раскладке языка, ГК (горячая клавиша) не будет работать, а при чтении (для отображения в контроле) запись не будет видна.
   Так как иногда приходится писать знакомым небольшие скрипты, и потом долго объяснять куда и что записать для изменения кнопки - решил написать функции для простого добавления пользователем, и для себя в код, ГК через GUI. Данный код определяет практически все кнопки, и кнопки первых четырёх джойстиков, также по необходимости определяет левые\правые модификаторы. 

----------------------------------------------

Блок функций для разработчика

----------------------------------------------

Всё просто, при старте скрипта указываем имя функции в которую передаётся массив данных (значения его ключей в примере) при каждом нажатии клавиш, и опции:

Hotkey_Init(FuncName, Options)

Можно вызывать повторно для изменения функции или опций.
Options - необязательный параметр из любых возможных букв "MLRJU", в любой последовательности и регистре. Если не указан, то только клавиатура.

M - Кнопки мыши без левой и правой.
L - Левая кнопка мыши, определяется только с модификаторами.
R - Правая кнопка мыши.
J - Кнопки джойстика, определяются только без модификаторов.
U - (редко используется) Отправлять событие отпускания кнопки и в том случае когда есть конечная клавиша, также в этом случае при отпускании модификаторов она сбрасывается. Опция может быть полезна например для создания истории нажатий.

Для установки или снятия перехвата нажатий (хука) вызываем:

Hotkey_Hook(Value)

Value = 1 - установка хука.
Value = 0 - снятие хука.

Текущее cостояние перехвата вернёт:

Hotkey_Arr("Hook")

Простой пример:


#NoEnv
#SingleInstance Force
OnExit, GuiClose
OnMessage(0x6, "WM_ACTIVATE")
Hotkey_Init("MyFunc", "MLRJ")
Gui, +AlwaysOnTop
Gui, Add, Text, w400 r19 vText, Нажимайте в активном окне
Gui, Show
Return

MyFunc(K)   {
    GuiControl, , Text, % K.Mods K.Name "`n`n"
        . K.Pref K.HK "`n`n---`n`n"
        . K.LRMods K.Name "`n`n"
        . K.LRPref K.HK "`n`n---`n`n"
        . K.TK "`n`n"
        . K.VK "`n`n"
        . K.SC "`n`n"
		. "Up: " K.Up "`t"
		. "IsMod: " K.IsMod "`t"
		. "IsJM: " K.IsJM "`t"   ; 1 - Joy, 2 - Mouse, 0 - Keyboard
		. "NFP: " K.NFP "`t"		; Не физическое нажатие
		. "Time: " K.Time "      "
		. K.PCtrl K.PAlt K.PShift K.PWin "`t"
		. K.PLCtrl K.PRCtrl K.PLAlt K.PRAlt K.PLShift K.PRShift K.PLWin K.PRWin
}

WM_ACTIVATE(wp)   {
    Hotkey_Hook(wp & 0xFFFF)
}

GuiClose:
    ExitApp

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

Для наилучшей производительности клавиатурного хука в секции автовыполнения рекомендуется использование:

#NoEnv
ListLines Off  
SetBatchLines -1
По вопросам возмездной помощи пишите письма
E-Mail: serzh82saratov@mail.ru
OS: Win7x64, AutoHotkey_L v1.1.26.01 (Unicode 32-bit).

2 (изменено: serzh82saratov, 2017-07-06 17:12:52)

Re: AHK: Замена стандартного элемента управления "Hotkey"

В коллекции библиотека с помощью которой возможно регистрировать контролы "Edit" копирующие поведение контрола "Hotkey".

По вопросам возмездной помощи пишите письма
E-Mail: serzh82saratov@mail.ru
OS: Win7x64, AutoHotkey_L v1.1.26.01 (Unicode 32-bit).

3 (изменено: teadrinker, 2013-08-14 04:26:38)

Re: AHK: Замена стандартного элемента управления "Hotkey"

"Код для иллюстрации" из поста в Коллекции не работает. Там явная ошибка:

IniWrite, % %A_GuiControl%, % A_ScriptFullPath, Section, % A_GuiControl

Путь к ini-файлу не может быть A_ScriptFullPath.

Кроме того, в коде такой недостаток: в функциях используется несколько OnMessage(). Если пользователь добавит в свой скрипт такие же, отслеживающие те же сообщения, твои перестанут работать. Также используется команда OnExit, если пользователь вставит свою — твоя перестанет работать.

Набросал свой вариант, более простой в использовании и различающий левые и правые модификаторы:

Gui, Add, Edit, hwndhEdit1 vHK1 gHotkey w150 h20 Center
Gui, Add, Edit, hwndhEdit2 vHK2 gHotkey w150 h20 Center
Gui, Add, Edit, vShowHotkey w150 h20 Center
Gui, Show

HotkeyInit(hEdit1, hEdit2)   ; передаём в функцию хендлы нужных контролов через запятую
return

Hotkey:
   HotkeyString := ""
   KeysArray := {Ctrl: "^", Alt: "!", Shift: "+", Win: "#"}
   
   GuiControlGet, Text, %A_Gui%:, %A_GuiControl%
   if (Text != "" && Text != "Нет" && Substr(Text, -1) != "+ ")
   {
      String := RegExReplace(Text, "\s")
      Loop, parse, String, +
      {
         IsSym := ""
         for k,v in KeysArray
            if InStr(A_LoopField, k)
               HotkeyString .= (SubStr(A_LoopField, 1, 1) = "L" ? "<" : ">") . v, IsSym := 1
         
         PrevFormat := A_FormatInteger
         SetFormat, IntegerFast, H
         if !IsSym
            HotkeyString .= "vk" . SubStr(GetKeyVK(A_LoopField), 3) . "sc" . SubStr(GetKeySC(A_LoopField), 3)
         SetFormat, IntegerFast, % PrevFormat
      }
      
      GuiControl, %A_Gui%:, ShowHotkey, % HotkeyString
;     Hotkey, % HotkeyString, HKLabel, On   ; раскомментировать для установки хоткея
   }
   return
   
HKLabel:
   MsgBox, Вы нажали горячую клавишу %A_ThisHotkey%
   return

GuiClose:
   ExitApp

HotkeyInit(handles*)
{
   global oHK_VarsArray := {handles: handles}
   
   hEdit := oHK_VarsArray.handles.1
   hGui := DllCall("GetParent", Ptr, hEdit, Ptr)
   
   ControlGetFocus, Var, ahk_id %hGui%
   GuiControlGet, OutputVar, %hGui%:Hwnd, % Var
   
   for k,v in handles
   {
      ControlSetText,, Нет, % "ahk_id" v
      if (OutputVar = v)
         oHK_VarsArray.hHook := SetWindowsHookEx()
            , oHK_VarsArray.hControl := v
   }
   
   SetWinEventHook(0x8005, 0x8005, 0, RegisterCallback("HookProc", "F"),0,0,0)   ; EVENT_OBJECT_FOCUS := 0x8005
}

SetWindowsHookEx()
{
   Return DllCall("SetWindowsHookEx" . (A_IsUnicode ? "W" : "A")
      , Int, WH_KEYBOARD_LL := 13
      , Ptr, RegisterCallback("LowLevelKeyboardProc", "Fast")
      , Ptr, DllCall("GetModuleHandle", UInt, 0, Ptr)
      , UInt, 0, Ptr)
}

LowLevelKeyboardProc(nCode, wParam, lParam)
{
   global oHK_VarsArray
   static WM_KEYDOWN := 0x100, WM_KEYUP := 0x101, WM_SYSKEYDOWN := 0x104, WM_SYSKEYUP := 0x105
      , prevMessage, prevKey, keys, EndKey
   
   SetFormat, IntegerFast, H
   Message := wParam, Extended := NumGet(lParam+0, 8, "UInt") & 1
   sc := Extended << 8 | NumGet(lParam+0, 4, "UInt"), vk := NumGet(lParam+0, 0, "UInt")
   key := GetKeyName("vk" SubStr(vk, 3) "sc" SubStr(sc, 3))

   if (wParam = prevMessage && key = prevKey)
      Return nCode < 0 ? DllCall("CallNextHookEx", Ptr, 0, Int, nCode, UInt, wParam, UInt, lParam) : 1
   
   prevMessage := wParam, prevKey := key
   
   if key in LControl,RControl
      key := SubStr(key, 1, 1) . "Ctrl"
   
   if (Message = WM_KEYDOWN || Message = WM_SYSKEYDOWN)
   {
      if (keys != "" && EndKey)
         keys := EndKey := ""
      
      if key in LCtrl,RCtrl,LAlt,RAlt,LShift,RShift,LWin,RWin
      {
         if !InStr(keys, key)
            keys := key . " + " . keys
      }
      else if (SubStr(keys, -1) = "+ " || keys = "")
         keys .= key
   }
   
   if (Message = WM_KEYUP || Message = WM_SYSKEYUP)
   {
      if key in LCtrl,RCtrl,LAlt,RAlt,LShift,RShift,LWin,RWin
         keys := RegExReplace(keys, key . " \+ ")
      else if (keys != "")
         EndKey := 1
         
      if !EndKey
         SetTimer, SetText, -10
      
      Return DllCall("CallNextHookEx", Ptr, 0, Int, nCode, UInt, wParam, UInt, lParam)
   }

   if !EndKey
      SetTimer, SetText, -10
   Return nCode < 0 ? DllCall("CallNextHookEx", Ptr, 0, Int, nCode, UInt, wParam, UInt, lParam) : 1
   
SetText:
   ControlSetText,, % keys = "" ? "Нет" : keys, % "ahk_id" oHK_VarsArray.hControl
   return
}

SetWinEventHook(eventMin, eventMax, hmodWinEventProc, lpfnWinEventProc, idProcess, idThread, dwFlags)
{
   return DllCall("SetWinEventHook" , UInt, eventMin
                                    , UInt, eventMax
                                    , Ptr, hmodWinEventProc
                                    , Ptr, lpfnWinEventProc
                                    , UInt, idProcess
                                    , UInt, idThread
                                    , UInt, dwFlags, Ptr)
}

HookProc(hWinEventHook, event, hwnd)
{
   global oHK_VarsArray
   
   for k,v in oHK_VarsArray
      if (k = "handles")
         for m,n in v
            if (hwnd = n)
               IsValue := 1, oHK_VarsArray.hControl := n
   
   if (IsValue && !oHK_VarsArray.hHook)
      oHK_VarsArray.hHook := SetWindowsHookEx()
   else if (!IsValue && oHK_VarsArray.hHook)
      DllCall("UnhookWindowsHookEx", Ptr, oHK_VarsArray.hHook), oHK_VarsArray.hHook := ""
}

Первые два Edit-контрола для ввода клавиш, третий — для демонстрации модифицированного вида.
Код работает для любой битности.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

4 (изменено: serzh82saratov, 2013-08-14 15:41:06)

Re: AHK: Замена стандартного элемента управления "Hotkey"

Спасибо за пример. Как всегда познавательный.
Я тоже думал сделать вариант различающий левые и правые модификаторы, но пошёл по подобию обычного контрола. Также в начале передавались хэндлы, но заменил на обычные переменные для понимания начинающих пользователей. Опять же для простоты ассоциированным переменным Edit назначаются коды кнопок. Вообщем задача была полностью скопировать Hotkey.

Набросал свой вариант, более простой в использовании

Врядли начинающим твоя подпрограмма Hotkey будет более понятна, чем простое  использование значения ассоциированной переменной.

Кроме того, в коде такой недостаток: в функциях используется несколько OnMessage(). Если пользователь добавит в свой скрипт такие же, отслеживающие те же сообщения, твои перестанут работать. Также используется команда OnExit, если пользователь вставит свою — твоя перестанет работать.

Да на полную библиотечность мой код не претендует, это точно.
А если пользователь поставит свой SetWinEventHook?

третий — для демонстрации модифицированного вида.

Символьные кнопки выдают vk0sc0.

Код работает для любой битности.

Подскажи, почему неработают мои в х64? Позавчера я честно пытался переделать.

Путь к ini-файлу не может быть A_ScriptFullPath.

??? Всё работает в некомпилированном виде. Сделано для теста, чтоб не создавать мусор.

По вопросам возмездной помощи пишите письма
E-Mail: serzh82saratov@mail.ru
OS: Win7x64, AutoHotkey_L v1.1.26.01 (Unicode 32-bit).

5 (изменено: serzh82saratov, 2013-08-14 15:42:12)

Re: AHK: Замена стандартного элемента управления "Hotkey"

HotkeyInit(handles*)

Кстати что значит звёздочка после параметра? Сколько читал, непойму.

По вопросам возмездной помощи пишите письма
E-Mail: serzh82saratov@mail.ru
OS: Win7x64, AutoHotkey_L v1.1.26.01 (Unicode 32-bit).

6 (изменено: serzh82saratov, 2013-08-14 15:46:37)

Re: AHK: Замена стандартного элемента управления "Hotkey"

teadrinker
При деактивации окна нажатые модификаторы (без кнопки) остаются прописанными, а надо бы сброс на слово "нет" по аналогии.

По вопросам возмездной помощи пишите письма
E-Mail: serzh82saratov@mail.ru
OS: Win7x64, AutoHotkey_L v1.1.26.01 (Unicode 32-bit).

7

Re: AHK: Замена стандартного элемента управления "Hotkey"

serzh82saratov пишет:

Врядли начинающим твоя подпрограмма Hotkey будет более понятна, чем простое  использование значения ассоциированной переменной.

Ассоциированная переменная не уникальна, они могут быть одинаковыми в разных GUI. Придётся тогда в функцию и идентификатор GUI передавать, что несколько усложняет использование.

serzh82saratov пишет:

Да на полную библиотечность мой код не претендует, это точно.

Это ещё и потому, что используется огромное количество глобальных переменных. Не ровён час, пользователь может с чем-то пересечься, таким образом получатся совершенно "необъяснимые" глюки. У меня, правда, тоже там есть один глобальный массив. Если удастся привести к "библиотечному" виду, выложу в Коллекции.

serzh82saratov пишет:

А если пользователь поставит свой SetWinEventHook?

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

Символьные кнопки выдают vk0sc0.

У тебя, наверно, русская раскладка по умолчанию стоит. В русской почему-то не считывает, исправлю.

Подскажи, почему неработают мои в х64? Позавчера я честно пытался переделать.

Не, не заставишь

??? Всё работает в некомпилированном виде. Сделано для теста, чтоб не создавать мусор.

Я, наверно, чего-то не понял. Я думал, ини-файлы нужны, чтобы сохранять хоткеи от сессии к сессии. Для чего они там вообще? И как они работают, если путь невалидный?

Кстати что значит звёздочка после параметра?

Говорит о том, что функция в данном параметре принимает массив параметров. Нужно, когда заранее неизвестно, сколько параметров понадобится передавать.

При деактивации окна нажатые модификаторы (без кнопки) остаются прописанными, а надо бы сброс на слово "нет" по аналогии.

Тут дело вкуса, это ведь просто демонстрационный контрол, пользователю он не нужен.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

8

Re: AHK: Замена стандартного элемента управления "Hotkey"

teadrinker пишет:

Ассоциированная переменная не уникальна, они могут быть одинаковыми в разных GUI. Придётся тогда в функцию и идентификатор GUI передавать, что несколько усложняет использование.

Так в описании так и написано HF_Hotkey( "GuiName:MyHotkey1"). Содержимое переменной нужно только в момент вызова метки, так что ошибки не будет.

WriteIni:  
    Gui Show, , %  A_GuiControl " = " %A_GuiControl% 
    return

Если надо сохранять более длительно, то нетрудно это учесть и задать разные имена переменных.

teadrinker пишет:

Это ещё и потому, что используется огромное количество глобальных переменных. Не ровён час, пользователь может с чем-то пересечься, таким образом получатся совершенно "необъяснимые" глюки.

Описание пишет:

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

Это тоже нетрудно учесть.

teadrinker пишет:

Не, не заставишь

Очень жаль, я сам не могу понять в чём дело. Ну да и бог с ним х64 интерпретатором.

teadrinker пишет:

Я, наверно, чего-то не понял. Я думал, ини-файлы нужны, чтобы сохранять хоткеи от сессии к сессии. Для чего они там вообще? И как они работают, если путь невалидный?

Почему ты думаешь что путь невалидный? Всё сохраняется как положено. Ини файлом служит текстовый файл самого скрипта, в чём тут проблема? Самих по себе хоткеев там нет, просто демонстрация правильности записи, и обратного их представления в Edit при перезапуске скрипта.

/*
[Section]
MyHotkey1=Space  
MyHotkey2=^!vk46  
MyHotkey3=vk44  
*/
teadrinker пишет:

Говорит о том, что функция в данном параметре принимает массив параметров. Нужно, когда заранее неизвестно, сколько параметров понадобится передавать.

Мало что понял, объясни подробнее, например по строкам:

HotkeyInit(handles*)
{
   global oHK_VarsArray := {handles: handles}
   
   hEdit := oHK_VarsArray.handles.1
teadrinker пишет:

Тут дело вкуса, это ведь просто демонстрационный контрол, пользователю он не нужен.

Думаю тут дело правила. Кому нужны модификаторы без конечной клавиши? Оно и в Винде и в AutoHotkey так. Модификаторы должны сбрасыватся если нет конечной клавиши.
Может ты меня не так понял, я про это

LWin + LAlt + LShift + LCtrl + 

оно остаётся не в демонстрационном контроле. Плюс в моём варианте переменная в таком случае очищается.

По вопросам возмездной помощи пишите письма
E-Mail: serzh82saratov@mail.ru
OS: Win7x64, AutoHotkey_L v1.1.26.01 (Unicode 32-bit).

9

Re: AHK: Замена стандартного элемента управления "Hotkey"

serzh82saratov пишет:

Так в описании так и написано HF_Hotkey( "GuiName:MyHotkey1").

Так это к вопросу о простоте использования . Кроме переменной нужно ещё и GUI прописывать. Имхо, хэндл проще.

Это тоже нетрудно учесть.

Ну я и говорю, много чего учитывать нужно .

Ини файлом служит текстовый файл самого скрипта

Ну вот видишь, даже я ничего не понял, куда там несчастному пользователю!

Мало что понял, объясни подробнее, например по строкам:

MyFunc("раз", "два", "три")

MyFunc(params*)
{
   for k,v in params
      MsgBox, % v
}

оно остаётся не в демонстрационном контроле.

Ты, может, код из почтового сообщения взял? Там была такая ошибка, отредактировано.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

10

Re: AHK: Замена стандартного элемента управления "Hotkey"

teadrinker пишет:

Так это к вопросу о простоте использования . Кроме переменной нужно ещё и GUI прописывать. Имхо, хэндл проще.

Ну зато hwnd в опции не надо дописывать

teadrinker пишет:

Ну вот видишь, даже я ничего не понял, куда там несчастному пользователю!

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

teadrinker пишет:

MyFunc("раз", "два", "три")

MyFunc(params*)
{
   for k,v in params
      MsgBox, % v
}

А, понял. Тут params это одномерный (не ассоциативный) массив. Не понял только строку

HK_VarsArray := {handles: handles}

Массив обычно объявляется так

HK_VarsArray := {}
teadrinker пишет:

Ты, может, код из почтового сообщения взял? Там была такая ошибка, отредактировано.

Точно нет. Ещё раз проверил код из 4 сообщения.

По вопросам возмездной помощи пишите письма
E-Mail: serzh82saratov@mail.ru
OS: Win7x64, AutoHotkey_L v1.1.26.01 (Unicode 32-bit).

11

Re: AHK: Замена стандартного элемента управления "Hotkey"

А такой код как работает?

Gui, Add, Edit, hwndhEdit1 gHotkey w150 h20 Center
Gui, Add, Edit, hwndhEdit2 gHotkey w150 h20 Center
Gui, Add, Edit, vShowHotkey w150 h20 Center
Gui, Show

HotkeyInit(HotkeyString, hEdit1, hEdit2)   ; передаём в функцию переменную для передачи информации
return                                     ; и хендлы нужных контролов через запятую

Hotkey:
   VarSetCapacity(HotkeyString, -1)
   GuiControl, %A_Gui%:, ShowHotkey, % HotkeyString
   
;  Hotkey, % HotkeyString, HKLabel, On   ; раскомментировать для установки хоткея
   return
   
HKLabel:
   MsgBox, Вы нажали горячую клавишу %A_ThisHotkey%
   return

GuiClose:
   ExitApp

HotkeyInit(ByRef info, handles*)
{
   global oHK_VarsArray := {handles: handles}
   
   VarSetCapacity(info, 50)
   oHK_VarsArray.pInfo := &info
   
   hGui := DllCall("GetParent", Ptr, handles.1, Ptr)
   
   ControlGetFocus, Var, ahk_id %hGui%
   GuiControlGet, OutputVar, %hGui%:Hwnd, % Var
   
   for k,v in handles
   {
      ControlSetText,, Нет, % "ahk_id" v
      if (OutputVar = v)
         oHK_VarsArray.hHook := SetWindowsHookEx()
            , oHK_VarsArray.hControl := v
   }
   
   SetWinEventHook(0x8005, 0x8005, 0, RegisterCallback("HookProc", "F"),0,0,0)   ; EVENT_OBJECT_FOCUS := 0x8005
}

SetWindowsHookEx()
{
   Return DllCall("SetWindowsHookEx" . (A_IsUnicode ? "W" : "A")
      , Int, WH_KEYBOARD_LL := 13
      , Ptr, RegisterCallback("LowLevelKeyboardProc", "Fast")
      , Ptr, DllCall("GetModuleHandle", UInt, 0, Ptr)
      , UInt, 0, Ptr)
}

LowLevelKeyboardProc(nCode, wParam, lParam)
{
   global oHK_VarsArray
   static WM_KEYDOWN := 0x100, WM_KEYUP := 0x101, WM_SYSKEYDOWN := 0x104, WM_SYSKEYUP := 0x105
      , prevMessage, prevKey, keys, EndKey, KeysArray := {Ctrl: "^", Alt: "!", Shift: "+", Win: "#"}
   
   SetBatchLines, -1
   SetFormat, IntegerFast, H
   Message := wParam, Extended := NumGet(lParam+0, 8, "UInt") & 1
   sc := Extended << 8 | NumGet(lParam+0, 4, "UInt"), vk := NumGet(lParam+0, 0, "UInt")
   key := GetKeyName("vk" SubStr(vk, 3) "sc" SubStr(sc, 3))

   if (wParam = prevMessage && key = prevKey)
      Return nCode < 0 ? DllCall("CallNextHookEx", Ptr, 0, Int, nCode, UInt, wParam, UInt, lParam) : 1
   
   prevMessage := wParam, prevKey := key
   
   if key in LControl,RControl
      key := SubStr(key, 1, 1) . "Ctrl"
   
   if (Message = WM_KEYDOWN || Message = WM_SYSKEYDOWN)
   {
      if (keys != "" && EndKey)
         keys := EndKey := ""
      
      if key in LCtrl,RCtrl,LAlt,RAlt,LShift,RShift,LWin,RWin
      {
         if !InStr(keys, key)
            keys := key . " + " . keys
      }
      else if (SubStr(keys, -1) = "+ " || keys = "")
         keys .= key
            , oHK_VarsArray.EndKey := "vk" . SubStr(vk, 3) . "sc" . SubStr(sc, 3)
   }
   
   if (Message = WM_KEYUP || Message = WM_SYSKEYUP)
   {
      if key in LCtrl,RCtrl,LAlt,RAlt,LShift,RShift,LWin,RWin
         keys := RegExReplace(keys, key . " \+ ")
      else if (keys != "")
         EndKey := 1
         
      if !EndKey
         SetTimer, SetText, -30
      
      Return DllCall("CallNextHookEx", Ptr, 0, Int, nCode, UInt, wParam, UInt, lParam)
   }

   if !EndKey
      SetTimer, SetText, -30
   Return nCode < 0 ? DllCall("CallNextHookEx", Ptr, 0, Int, nCode, UInt, wParam, UInt, lParam) : 1
   
SetText:
   SetBatchLines, -1
   if (keys != "" && keys != "Нет" && Substr(keys, -1) != "+ ")
   {
      String := RegExReplace(keys, "\s")
      Loop, parse, String, +
      {
         IsSym := ""
         for k,v in KeysArray
            if InStr(A_LoopField, k)
               HKString .= (SubStr(A_LoopField, 1, 1) = "L" ? "<" : ">") . v, IsSym := 1
         
         if !IsSym
            HKString .= oHK_VarsArray.EndKey
      }
      StrPut(HKString, oHK_VarsArray.pInfo)
   }
   ControlSetText,, % keys = "" ? "Нет" : keys, % "ahk_id" oHK_VarsArray.hControl
   return
}

SetWinEventHook(eventMin, eventMax, hmodWinEventProc, lpfnWinEventProc, idProcess, idThread, dwFlags)
{
   return DllCall("SetWinEventHook" , UInt, eventMin
                                    , UInt, eventMax
                                    , Ptr, hmodWinEventProc
                                    , Ptr, lpfnWinEventProc
                                    , UInt, idProcess
                                    , UInt, idThread
                                    , UInt, dwFlags, Ptr)
}

HookProc(hWinEventHook, event, hwnd)
{
   global oHK_VarsArray
   
   for k,v in oHK_VarsArray
      if (k = "handles")
         for m,n in v
            if (hwnd = n)
               IsValue := 1, oHK_VarsArray.hControl := n
   
   if (IsValue && !oHK_VarsArray.hHook)
      oHK_VarsArray.hHook := SetWindowsHookEx()
   else if (!IsValue && oHK_VarsArray.hHook)
      DllCall("UnhookWindowsHookEx", Ptr, oHK_VarsArray.hHook), oHK_VarsArray.hHook := ""
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

12

Re: AHK: Замена стандартного элемента управления "Hotkey"

А такой код как работает?

Плохо. Выяснилось также что они не сбрасываются и для других.
То есть нажимаем в 1 поле LShift + LCtrl + и деактивируем окно. LShift + LCtrl + остаются в поле. Активируем окно, во втором поле нажимаем (например) Space, и прописывается LShift + LCtrl + Space.

По вопросам возмездной помощи пишите письма
E-Mail: serzh82saratov@mail.ru
OS: Win7x64, AutoHotkey_L v1.1.26.01 (Unicode 32-bit).

13

Re: AHK: Замена стандартного элемента управления "Hotkey"

То-есть, проблема в том, что если деактивировать окно, удерживая клавиши, они остаются в поле? И всё? Если не деактивировать, всё нормально?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

14

Re: AHK: Замена стандартного элемента управления "Hotkey"

Ну в общем, да.

По вопросам возмездной помощи пишите письма
E-Mail: serzh82saratov@mail.ru
OS: Win7x64, AutoHotkey_L v1.1.26.01 (Unicode 32-bit).

15

Re: AHK: Замена стандартного элемента управления "Hotkey"

serzh82saratov пишет:

А такой код как работает?

Плохо.

Ну ты строгий! Исправлю

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

16

Re: AHK: Замена стандартного элемента управления "Hotkey"

Gui, Add, Edit, hwndhEdit1 gHotkey w150 h20 Center
Gui, Add, Edit, hwndhEdit2 gHotkey w150 h20 Center
Gui, Add, Edit, vShowHotkey w150 h20 Center
Gui, Show

HotkeyInit(HotkeyString, hEdit1, hEdit2)   ; передаём в функцию переменную для передачи информации
return                                     ; и хендлы нужных контролов через запятую

Hotkey:
   VarSetCapacity(HotkeyString, -1)
   GuiControl, %A_Gui%:, ShowHotkey, % HotkeyString
   
;  Hotkey, % HotkeyString, HKLabel, On   ; раскомментировать для установки хоткея
   return
   
HKLabel:
   MsgBox, Вы нажали горячую клавишу %A_ThisHotkey%
   return

GuiClose:
   ExitApp

HotkeyInit(ByRef info, handles*)
{
   global oHK_VarsArray := {handles: handles}
   
   VarSetCapacity(info, 50)
   oHK_VarsArray.pInfo := &info
   
   hGui := DllCall("GetParent", Ptr, handles.1, Ptr)
   
   ControlGetFocus, Var, ahk_id %hGui%
   GuiControlGet, OutputVar, %hGui%:Hwnd, % Var
   
   for k,v in handles
   {
      ControlSetText,, Нет, % "ahk_id" v
      if (OutputVar = v)
         oHK_VarsArray.hHook := SetWindowsHookEx()
            , oHK_VarsArray.hControl := v
   }
   
   SetWinEventHook(0x8005, 0x8005, 0, RegisterCallback("HookProc", "F"),0,0,0)   ; EVENT_OBJECT_FOCUS := 0x8005
}

SetWindowsHookEx()
{
   Return DllCall("SetWindowsHookEx" . (A_IsUnicode ? "W" : "A")
      , Int, WH_KEYBOARD_LL := 13
      , Ptr, RegisterCallback("LowLevelKeyboardProc", "Fast")
      , Ptr, DllCall("GetModuleHandle", UInt, 0, Ptr)
      , UInt, 0, Ptr)
}

LowLevelKeyboardProc(nCode, wParam, lParam)
{
   global oHK_VarsArray
   static WM_KEYDOWN := 0x100, WM_KEYUP := 0x101, WM_SYSKEYDOWN := 0x104, WM_SYSKEYUP := 0x105
      , prevMessage, prevKey, keys, EndKey, KeysArray := {Ctrl: "^", Alt: "!", Shift: "+", Win: "#"}
   
   SetBatchLines, -1
   SetFormat, IntegerFast, H
   Message := wParam, Extended := NumGet(lParam+0, 8, "UInt") & 1
   sc := Extended << 8 | NumGet(lParam+0, 4, "UInt"), vk := NumGet(lParam+0, 0, "UInt")
   key := GetKeyName("vk" SubStr(vk, 3) "sc" SubStr(sc, 3))

   if (wParam = prevMessage && key = prevKey)
      Return nCode < 0 ? DllCall("CallNextHookEx", Ptr, 0, Int, nCode, UInt, wParam, UInt, lParam) : 1
   
   prevMessage := wParam, prevKey := key
   
   if key in LControl,RControl
      key := SubStr(key, 1, 1) . "Ctrl"
   
   if (Message = WM_KEYDOWN || Message = WM_SYSKEYDOWN)
   {
      if (keys != "" && EndKey)
         keys := EndKey := ""
      
      if key in LCtrl,RCtrl,LAlt,RAlt,LShift,RShift,LWin,RWin
      {
         if !InStr(keys, key)
            keys := key . " + " . keys
      }
      else if (SubStr(keys, -1) = "+ " || keys = "")
         keys .= key
            , oHK_VarsArray.EndKey := "vk" . SubStr(vk, 3) . "sc" . SubStr(sc, 3)
   }
   
   if (Message = WM_KEYUP || Message = WM_SYSKEYUP)
   {
      if key in LCtrl,RCtrl,LAlt,RAlt,LShift,RShift,LWin,RWin
         keys := RegExReplace(keys, key . " \+ ")
      else if (keys != "")
         EndKey := 1
         
      if !EndKey
         SetTimer, SetText, -30
      
      Return DllCall("CallNextHookEx", Ptr, 0, Int, nCode, UInt, wParam, UInt, lParam)
   }

   SetTimer, SetText, -30
   Return nCode < 0 ? DllCall("CallNextHookEx", Ptr, 0, Int, nCode, UInt, wParam, UInt, lParam) : 1
   
SetText:
   if (keys != "" && keys != "Нет" && Substr(keys, -1) != "+ ")
   {
      String := RegExReplace(keys, "\s")
      Loop, parse, String, +
      {
         IsSym := ""
         for k,v in KeysArray
            if InStr(A_LoopField, k)
               HKString .= (SubStr(A_LoopField, 1, 1) = "L" ? "<" : ">") . v, IsSym := 1
         
         if !IsSym
            HKString .= oHK_VarsArray.EndKey
      }
      StrPut(HKString, oHK_VarsArray.pInfo)
   }
   ControlSetText,, % keys = "" ? "Нет" : keys, % "ahk_id" oHK_VarsArray.hControl
   return
}

SetWinEventHook(eventMin, eventMax, hmodWinEventProc, lpfnWinEventProc, idProcess, idThread, dwFlags)
{
   return DllCall("SetWinEventHook" , UInt, eventMin
                                    , UInt, eventMax
                                    , Ptr, hmodWinEventProc
                                    , Ptr, lpfnWinEventProc
                                    , UInt, idProcess
                                    , UInt, idThread
                                    , UInt, dwFlags, Ptr)
}

HookProc(hWinEventHook, event, hwnd)
{
   global oHK_VarsArray
   
   for k,v in oHK_VarsArray.handles
      if (hwnd = v)
         IsValue := 1, oHK_VarsArray.hControl := v
   
   if (IsValue && !oHK_VarsArray.hHook)
      oHK_VarsArray.hHook := SetWindowsHookEx()
   else if (!IsValue && oHK_VarsArray.hHook)
   {
      DllCall("UnhookWindowsHookEx", Ptr, oHK_VarsArray.hHook), oHK_VarsArray.hHook := ""
      
      for k,v in oHK_VarsArray.handles
      {
         ControlGetText, Text,, ahk_id %v%
         if SubStr(Text, -1) = "+ "
            ControlSetText,, Нет, ahk_id %v%
      }
   }
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

17

Re: AHK: Замена стандартного элемента управления "Hotkey"

Плохо. Выяснилось также что они не сбрасываются и для других.
То есть нажимаем в 1 поле LShift + LCtrl + и деактивируем окно. LShift + LCtrl + остаются в поле. Активируем окно, во втором поле нажимаем (например) Space, и прописывается LShift + LCtrl + Space.

Осталась проблема:

Активируем окно, во втором поле нажимаем (например) Space, и прописывается LShift + LCtrl + Space.

По вопросам возмездной помощи пишите письма
E-Mail: serzh82saratov@mail.ru
OS: Win7x64, AutoHotkey_L v1.1.26.01 (Unicode 32-bit).

18

Re: AHK: Замена стандартного элемента управления "Hotkey"

serzh82saratov пишет:

Осталась проблема:

Честно говоря, не понял. У меня всё нормально работает. Что нажато, то и прописывается. Опиши подробнее.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

19 (изменено: serzh82saratov, 2013-08-14 22:20:13)

Re: AHK: Замена стандартного элемента управления "Hotkey"

Даже не знаю как ещё описать. В новом коде оказалось что всё тоже самое просто через раз:

То есть нажимаем в 1 поле LShift + LCtrl + и деактивируем окно. LShift + LCtrl + остаются в поле. Активируем окно, во втором поле нажимаем (например) Space, и прописывается LShift + LCtrl + Space.

В 1 поле держим нажатыми LShift + LCtrl, деактивируем окно. В поле один (теперь через раз) остаётся

LShift + LCtrl + 

это не гуд. Иногда всё таки пишется слово "Нет".
Далее:
Осталось: после этого активируем окно (не важно LShift + LCtrl + остались прописаны или нет в 1 поле), во 2 поле нажимаем (например) Space, и о чудо - прописывается LShift + LCtrl + Space. А нажата была только Space. И это тоже не гуд.

По вопросам возмездной помощи пишите письма
E-Mail: serzh82saratov@mail.ru
OS: Win7x64, AutoHotkey_L v1.1.26.01 (Unicode 32-bit).

20

Re: AHK: Замена стандартного элемента управления "Hotkey"

Действительно, чудо. У меня всё нормально работает на любом интерпретаторе. Win 7 64. А ты уверен, что это не последствия работы какого-то твоего скрипта, где остаются неотжатыми клавиши?

Если кто ещё читает этот пост, можете протестить последний код?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

21

Re: AHK: Замена стандартного элемента управления "Hotkey"

Удалось поймать. У меня выходит глюк, если нажать модификаты при активном контроле, удерживая их, деактивировать окно, затем отпустить нажатые клавиши. Так, или ещё как-то?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

22

Re: AHK: Замена стандартного элемента управления "Hotkey"

То есть нажимаем в 1 поле LShift + LCtrl + и деактивируем окно. LShift + LCtrl + остаются в поле.

Удалось поймать.

Теперь это надо ловить.
---
Но это:

Активируем окно, во втором поле нажимаем (например) Space, и прописывается LShift + LCtrl + Space.

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

По вопросам возмездной помощи пишите письма
E-Mail: serzh82saratov@mail.ru
OS: Win7x64, AutoHotkey_L v1.1.26.01 (Unicode 32-bit).

23

Re: AHK: Замена стандартного элемента управления "Hotkey"

А так?

Gui, Add, Edit, hwndhEdit1 gHotkey w150 h20 Center
Gui, Add, Edit, hwndhEdit2 gHotkey w150 h20 Center
Gui, Add, Edit, vShowHotkey w150 h20 Center
Gui, Show

HotkeyInit(HotkeyString, hEdit1, hEdit2)   ; передаём в функцию переменную для передачи информации
return                                     ; и хендлы нужных контролов через запятую

Hotkey:
   VarSetCapacity(HotkeyString, -1)
   GuiControl, %A_Gui%:, ShowHotkey, % HotkeyString
   
;  Hotkey, % HotkeyString, HKLabel, On   ; раскомментировать для установки хоткея
   return
   
HKLabel:
   MsgBox, Вы нажали горячую клавишу %A_ThisHotkey%
   return

GuiClose:
   ExitApp

HotkeyInit(ByRef info, handles*)
{
   global oHK_VarsArray := {handles: handles}
   
   VarSetCapacity(info, 50)
   oHK_VarsArray.pInfo := &info
   
   hGui := DllCall("GetParent", Ptr, handles.1, Ptr)
   
   ControlGetFocus, Var, ahk_id %hGui%
   GuiControlGet, OutputVar, %hGui%:Hwnd, % Var
   
   for k,v in handles
   {
      ControlSetText,, Нет, % "ahk_id" v
      if (OutputVar = v)
         oHK_VarsArray.hHook := SetWindowsHookEx()
            , oHK_VarsArray.hControl := v
   }
   
   SetWinEventHook(0x8005, 0x8005, 0, RegisterCallback("HookProc", "F"),0,0,0)   ; EVENT_OBJECT_FOCUS := 0x8005
}

SetWindowsHookEx()
{
   Return DllCall("SetWindowsHookEx" . (A_IsUnicode ? "W" : "A")
      , Int, WH_KEYBOARD_LL := 13
      , Ptr, RegisterCallback("LowLevelKeyboardProc", "Fast")
      , Ptr, DllCall("GetModuleHandle", UInt, 0, Ptr)
      , UInt, 0, Ptr)
}

LowLevelKeyboardProc(nCode, wParam, lParam)
{
   global oHK_VarsArray
   static WM_KEYDOWN := 0x100, WM_KEYUP := 0x101, WM_SYSKEYDOWN := 0x104, WM_SYSKEYUP := 0x105
      , prevMessage, prevKey, EndKey
   
   SetBatchLines, -1
   SetFormat, IntegerFast, H
   Message := wParam, Extended := NumGet(lParam+0, 8, "UInt") & 1
   sc := Extended << 8 | NumGet(lParam+0, 4, "UInt"), vk := NumGet(lParam+0, 0, "UInt")
   key := GetKeyName("vk" SubStr(vk, 3) "sc" SubStr(sc, 3))

   if (wParam = prevMessage && key = prevKey)
      Return nCode < 0 ? DllCall("CallNextHookEx", Ptr, 0, Int, nCode, UInt, wParam, UInt, lParam) : 1
   
   prevMessage := wParam, prevKey := key
   
   if key in LControl,RControl
      key := SubStr(key, 1, 1) . "Ctrl"
   
   if (Message = WM_KEYDOWN || Message = WM_SYSKEYDOWN)
   {
      if (oHK_VarsArray.keys != "" && EndKey)
         oHK_VarsArray.keys := EndKey := ""
      
      if key in LCtrl,RCtrl,LAlt,RAlt,LShift,RShift,LWin,RWin
      {
         if !InStr(oHK_VarsArray.keys, key)
            oHK_VarsArray.keys := key . " + " . oHK_VarsArray.keys
      }
      else if (SubStr(oHK_VarsArray.keys, -1) = "+ " || oHK_VarsArray.keys = "")
         oHK_VarsArray.keys .= key
            , oHK_VarsArray.EndKey := "vk" . SubStr(vk, 3) . "sc" . SubStr(sc, 3)
   }
   
   if (Message = WM_KEYUP || Message = WM_SYSKEYUP)
   {
      if key in LCtrl,RCtrl,LAlt,RAlt,LShift,RShift,LWin,RWin
         oHK_VarsArray.keys := RegExReplace(oHK_VarsArray.keys, key . " \+ ")
      else if (oHK_VarsArray.keys != "")
         EndKey := 1
         
      if !EndKey
         SetTimer, SetText, -30
      
      Return DllCall("CallNextHookEx", Ptr, 0, Int, nCode, UInt, wParam, UInt, lParam)
   }

   SetTimer, SetText, -30
   Return nCode < 0 ? DllCall("CallNextHookEx", Ptr, 0, Int, nCode, UInt, wParam, UInt, lParam) : 1
   
SetText:
   keys := oHK_VarsArray.keys
   if (keys != "" && keys != "Нет" && Substr(keys, -1) != "+ ")
   {
      String := RegExReplace(keys, "\s")
      Loop, parse, String, +
      {
         IsSym := ""
         for k,v in {Ctrl: "^", Alt: "!", Shift: "+", Win: "#"}
            if InStr(A_LoopField, k)
               HKString .= (SubStr(A_LoopField, 1, 1) = "L" ? "<" : ">") . v, IsSym := 1
         
         if !IsSym
            HKString .= oHK_VarsArray.EndKey
      }
      StrPut(HKString, oHK_VarsArray.pInfo)
   }
   ControlSetText,, % keys = "" ? "Нет" : keys, % "ahk_id" oHK_VarsArray.hControl
   return
}

SetWinEventHook(eventMin, eventMax, hmodWinEventProc, lpfnWinEventProc, idProcess, idThread, dwFlags)
{
   return DllCall("SetWinEventHook" , UInt, eventMin
                                    , UInt, eventMax
                                    , Ptr, hmodWinEventProc
                                    , Ptr, lpfnWinEventProc
                                    , UInt, idProcess
                                    , UInt, idThread
                                    , UInt, dwFlags, Ptr)
}

HookProc(hWinEventHook, event, hwnd)
{
   global oHK_VarsArray
   
   for k,v in oHK_VarsArray.handles
      if (hwnd = v)
         IsValue := 1, oHK_VarsArray.hControl := v
   
   if (IsValue && !oHK_VarsArray.hHook)
      oHK_VarsArray.hHook := SetWindowsHookEx()
   else if (!IsValue && oHK_VarsArray.hHook)
   {
      DllCall("UnhookWindowsHookEx", Ptr, oHK_VarsArray.hHook)
      oHK_VarsArray.keys := oHK_VarsArray.hHook := ""
      
      for k,v in oHK_VarsArray.handles
      {
         ControlGetText, Text,, ahk_id %v%
         if SubStr(Text, -1) = "+ "
            ControlSetText,, Нет, ahk_id %v%
      }
   }
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

24

Re: AHK: Замена стандартного элемента управления "Hotkey"

Держишь модификатор (к примеру) LAlt. Нажимаешь Space. Пишется

LAlt + Space

Ещё раз нажимаешь Space (держа далее LAlt), пишется Space.

По вопросам возмездной помощи пишите письма
E-Mail: serzh82saratov@mail.ru
OS: Win7x64, AutoHotkey_L v1.1.26.01 (Unicode 32-bit).

25

Re: AHK: Замена стандартного элемента управления "Hotkey"

А теперь нажатые модификаторы при деактивации не залипают?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg