1 (изменено: mkone112, 2020-07-20 03:32:24)

Тема: AHK: Сочетания Shift и Alt в разных порядках

Подскажите, как реализовать следующее поведение:

  • {LAlt Down}{LShift Down}{LAlt Up}{LShift Up} без нажатий других клавиш:

    • Выбрать русскую раскладку

  • {LShift Down}{LAlt Down}{LShift Up}{LAlt Up} без нажатий других клавиш:

    • Выбрать английскую раскладку

  • Одиночное нажатие LAlt:

    • Послать !{/}

  • Одиночное нажатие LShift:

    • Послать {Esc}

  • Одиночное нажатие LShift при нажатом Alt:

    • Послать +!{/}

  • Одиночное нажатие LAlt при нажатом LShift:

    • Послать {F13}

  • Остальные сочетания с LAlt, LShift работают как обычно

Бьюсь уже часов 20, все что смог написать либо работает не так, либо адово глючит ,либо не работает вовсе.
Последний нерабочий концепт:

/*
Запуск всегда с максимальными правами
*/
if not A_IsAdmin
{
   Run *RunAs "%A_ScriptFullPath%"  ; Requires v1.0.92.01+
   ExitApp
}


#SingleInstance, force
#NoEnv
SetWorkingDir %A_ScriptDir%

/*
  Чтобы клавиши не залипали
*/
Process, Priority, , H
SetBatchLines, -1
SetKeyDelay, 50
SendMode Input
/*
  Чтобы работало со всеми окнами
*/
DetectHiddenWindows, On



/*
~ посылает клавиши в окно
*/
~LAlt & ~LShift::
    except_lalt_lsh := false
    /*
      Пока LAlt не отпущен - перебираем клавиши в поисках нажатой
    */
    while ( GetKeyState("LAlt", "P") )
    {
        Loop, 256
        {
            key_with_lalt_lsh := Format("vk{:x}", A_Index-1)

            /*
              VK12=Alt    VKA4=LAlt    VK10=Shift    VKA0=LShift
            */
            if ( GetKeyState(key_with_lalt_lsh, "P")
                 && key_with_lalt_lsh != "vk12" && key_with_lalt_lsh != "vka4"
                 &&  key_with_lalt_lsh != "vk10" && key_with_lalt_lsh != "vka0" )
            {
                /*
                  Нажата клавиша кроме LAlt или LShift
                */
                except_lalt_lsh := true
                break 2
            }
        }
    }

    /*
      Если не нажимались клавиши кроме LShift или LAlt, и LShift еще нажат
    */
    if ( !except_lalt_lsh && GetKeyState("LShift", "P") )
    {
        /*
          Ждем отпускания LShift и переключаем раскладку на Английскую
        */
        KeyWait, LShift
        ControlGetFocus, control, A
        PostMessage 0x50, 0, -255851511, %control%, A
    }
return




/*
~ посылает клавиши в окно
LAlt не посылается - иначе, отрываеся меню программ
*/
~LShift & LAlt::
    except_lsh_lalt := false
    /*
      Пока LShift не отпущен - перебираем клавиши в поисках нажатой
    */
    while ( GetKeyState("LShift", "P") )
    {
        Loop, 256
        {
            key_with_lsh_lalt := Format("vk{:x}", A_Index-1)

            /*
              VK10=Shift    VKA0=LShift    VK12=Alt    VKA4=LAlt
            */
            if ( GetKeyState(key_with_lsh_lalt, "P")
                 && key_with_lsh_lalt != "vk10" && key_with_lsh_lalt != "vka0"
                 && key_with_lsh_lalt != "vk12" && key_with_lsh_lalt != "vka4" )
            {
                /*
                  Нажата клавиша кроме LShift или LAlt
                */
                except_lsh_lalt := true
                break 2
            }
        }
        lsh_single := false
    }

    /*
      Если LShift & LAlt
      не были задействованы ни в каких других сочетаниях
      клавиш(в это время ни одна другая клавиша 
      не была нажата), - переключаем раскладку на Русскую
    */
    if (!except_lsh_lalt)
    {
        ControlGetFocus, control, A
        PostMessage 0x50, 0, -255785959, %control%, A
    }
return




~$LShift::
    lsh_single := true
    /*
      Пока LShift не отпущен - перебираем клавиши в поисках нажатой
    */
    while ( GetKeyState("LShift", "P") )
    {
        Loop, 256
        {
            key_with_lshift := Format("vk{:x}", A_Index-1)

            /*
              VK10=Shift    VKA0=LShift
            */
            if ( GetKeyState(key_with_lshift, "P")
                 && key_with_lshift != "vk10" && key_with_lshift != "vka0" )
            {
                lsh_single := false
                break 2
            }
        }
        /*
          Если одиночный LShift удерживается дольше 300мс - Esc не будет послан
        */
        if (A_TimeSinceThisHotkey > 300)
        {
            lsh_single := false
            break
        }
    }
    /*
      Ждем отпускания LShift
    */
    KeyWait, LShift
    /*
      Если LShift был зажат менее 300мс и
      не был задействован в сочетании
      клавиш(в это время ни одна другая клавиша не была нажата),
      посылаем Esc
    */
    if (lsh_single)
    {
        Send {Esc}
    }
return


~$LAlt::
    lalt_single := true

    while ( GetKeyState("LAlt", "P") )
    {
        Loop, 256
        {
            key_with_lalt := Format("vk{:x}", A_Index-1)

            /*
              VK12=Alt    VKA4=LAlt
            */
            if ( GetKeyState(key_with_lalt, "P")
                 && key_with_lalt != "vk12" && key_with_lalt != "vka4" )
            {
                lalt_single := false
                break 2
            }
        }

        if (A_TimeSinceThisHotkey > 300)
        {
            lalt_single := false
            break
        }
    }
    /*
      Ждем отпускания LAlt
    */
    KeyWait, LAlt
    /*
      Если LAlt был зажат менее 300мс и
      не был задействован в сочетании
      клавиш(в это время ни одна другая клавиша не была нажата),
      посылаем {Alt Down}{/ Down}{/ Up}{Alt Up}
    */
    if (lalt_single)
    {
        Send !{/}
    }
return

2

Re: AHK: Сочетания Shift и Alt в разных порядках

mkone112 пишет:

Подскажите, как реализовать следующее поведение:

  • {LAlt Down}{LShift Down}{LAlt Up}{LShift Up} без нажатий других клавиш:

    • Выбрать русскую раскладку

  • {LShift Down}{LAlt Down}{LShift Up}{LAlt Up} без нажатий других клавиш:

    • Выбрать английскую раскладку

А зачем такие сложности? Не проще переключать раскладку по одной и той же клавише, например RShift?

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

3

Re: AHK: Сочетания Shift и Alt в разных порядках

teadrinker
Нет, одно действие должно выбирать одну раскладку, sh + alt -> точно русский, alt + sh -> точно английский.
К тому-же RShift уже занят.

4

Re: AHK: Сочетания Shift и Alt в разных порядках

И что, и порядок отжатия тоже важен? А если {LAlt Down}{LShift Down}{LShift Up}{LAlt Up} — тогда что должно произойти?

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

5 (изменено: __Михаил__, 2020-07-20 21:15:13)

Re: AHK: Сочетания Shift и Alt в разных порядках

Такие сложности, не легче ли будет установить одну клавишу для переключения языка, от двойного - второе действие, а если её удерживаешь третье? Так же можно сделать проверку тех же Shift, Alt, Win, Ctrl.
Зачем нажимать 4 и более клавиши ради такого бестолкового действия?
+По стандарту в винде можно назначить кнопки если что.

Win10x64, AHK v1.1.37.01 (Unicode 64-bit) | AHK-Wiki | Переменные и выражения | RegEx101

6

Re: AHK: Сочетания Shift и Alt в разных порядках

__Михаил__ пишет:

Зачем нажимать 4 и более клавиши ради такого бестолкового действия?

Не 4, а 2.

7

Re: AHK: Сочетания Shift и Alt в разных порядках

teadrinker пишет:

И что, и порядок отжатия тоже важен?

Да, важен - в этом вся суть.

teadrinker пишет:

А если {LAlt Down}{LShift Down}{LShift Up}{LAlt Up} — тогда что должно произойти?

Это 5й пункт.

8

Re: AHK: Сочетания Shift и Alt в разных порядках

__Михаил__ пишет:

+По стандарту в винде можно назначить кнопки если что.

Не с таким сложным поведением.

9

Re: AHK: Сочетания Shift и Alt в разных порядках

Лично у меня подобный код не переключает язык:

ControlGetFocus, control, A
PostMessage 0x50, 0, -255785959, %control%, A
Win10x64, AHK v1.1.37.01 (Unicode 64-bit) | AHK-Wiki | Переменные и выражения | RegEx101

10

Re: AHK: Сочетания Shift и Alt в разных порядках

__Михаил__
Он ее не переключает, а устанавливает на конкретную(модифицированный colemak). В вашей системе ее нет поэтому код ничего не делает, узнать номер текущей раскладки можно так.

+ открыть спойлер
DllCall("GetKeyboardLayout", "Int", DllCall("GetWindowThreadProcessId", "Int", WinActive("A"), "Int", 0))

И проблема в любом случае не в установке языка, а данном коде проблемы в том что LAlt при нажатии залипает посылая +{/} многократно и срабатывает при нажатии LAlt & LShift.

11 (изменено: teadrinker, 2020-07-20 23:23:46)

Re: AHK: Сочетания Shift и Alt в разных порядках

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

Hook := InputHook("V")
Hook.KeyOpt("{LAlt}{LShift}", "VN")
Hook.OnKeyDown := Func("KeyDown")
Hook.OnKeyUp := Func("KeyUp")
Hook.Start()
Return

KeyDown(Hook, vk, sc) {
   keyName := GetKeyName(Format("vk{:x}sc{:x}", vk, sc))
   ToolTip % keyName . " Down"
}

KeyUp(Hook, vk, sc) {
   keyName := GetKeyName(Format("vk{:x}sc{:x}", vk, sc))
   ToolTip % keyName . " Up"
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

12

Re: AHK: Сочетания Shift и Alt в разных порядках

mkone112, сначала нужно будет создать инструмент для установки таких произвольных горячих клавиш.
Алгоритм такой:
• записываем в память скрипта лог всех нажатий и отпусканий клавиш,
• устанавливаем последовательности, которые будут служить хоткеями,
• по нажатию любой их конечных клавиш хоткеев проводим проверку: совпадает ли лог нажатий с последовательностью хоткея, если совпадает выполняем действие.

Результат выглядеть будет как-то так (без кода самого инструмента):

ohk := New OptionalHotKey
ohk.SetHotkey("{LAlt Down}{LShift Down}{LAlt Up}{LShift Up}", Func("SetLayout").Bind("ru"))
ohk.SetHotkey("{LShift Down}{LAlt Down}{LShift Up}{LAlt Up}", Func("SetLayout").Bind("en"))
ohk.SetHotkey("{LAlt Down}{LShift Down}{LShift Up}{LAlt Up}", Func("Send").Bind("+!{vkBF}"))
ohk.SetHotkey("{LShift Down}{LAlt Down}{LAlt Up}{LShift Up}", Func("Send").Bind("{F13}"))
ohk.SetHotkey("{LAlt Down}{LAlt Up}", Func("Send").Bind("!{vkBF}"))
ohk.SetHotkey("{LShift Down}{LShift Up}", Func("Send").Bind("{Esc}"))

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

13

Re: AHK: Сочетания Shift и Alt в разных порядках

__Михаил__ пишет:

Такие сложности, не легче ли будет установить одну клавишу для переключения языка, от двойного - второе действие, а если её удерживаешь третье? Так же можно сделать проверку тех же Shift, Alt, Win, Ctrl.

Одиночное нажатие уже посылает Esc или DeadKey, следовательно двойное нажатие либо не сделать, либо предется городить задержки.
Удержание уже занято.
Все Shift, Alt, Win и Ctrl уже заняты.

14

Re: AHK: Сочетания Shift и Alt в разных порядках

stealzy
teadrinker
Ваши ответы навели меня на более простое, хоть и менее элегантное решение. Спасибо!


~$LAlt::
while GetKeyState("LAlt", "P")
{
    while (GetKeyState("LAlt", "P") && !GetKeyState("LShift", "P"))
        Sleep, 30

    if GetKeyState("LShift","P")
    {
        sh_down_time := A_TimeSinceThisHotkey
        while (GetKeyState("LAlt", "P") && GetKeyState("LShift", "P"))
            Sleep, 30

        if (GetKeyState("LAlt"), "P")
        {
            if ( (A_TimeSinceThisHotkey - sh_down_time) < single_press_time )
            {
                if ( WinActive("ahk_class SunAwtFrame") || WinActive("ahk_class SunAwtDialog") )
                {
                    key_seq := ["{RAlt Down}", "{LShift Down}", "{VKBF Down}"
                                   , "{VKBF Up}", "{LShift Up}", "{RAlt Up}"]
                    for i, key in key_seq
                    {
                        Send, %key%
                        Sleep, %key_delay%
                    }
                }
            }
        }
        else
        {
            KeyWait, LShift
            SetLayout(dvolemak_code)
        }
    }
    else
    {
        KeyWait, LAlt
        if (A_PriorKey == "LAlt" && A_TimeSinceThisHotkey < single_press_time)
        {
            if ( WinActive("ahk_class SunAwtFrame") || WinActive("ahk_class SunAwtDialog") )
            {
                key_seq := ["{LAlt Down}", "{VKBF Down}", "{VKBF Up}", "{LAlt Up}"]
                for i, key in key_seq
                {
                    Send, %key%
                    Sleep, %key_delay%
                }
            }
        }
    }
}
return

~$LShift::
while GetKeyState("LShift", "P")
{
    while (GetKeyState("LShift", "P") && !GetKeyState("LAlt", "P"))
        Sleep, 30

    if GetKeyState("LAlt","P")
    {
        lalt_down_time := A_TimeSinceThisHotkey
        while (GetKeyState("LShift", "P") && GetKeyState("LAlt", "P"))
            Sleep, 30

        if (GetKeyState("LShift"), "P")
        {
            if ( (A_TimeSinceThisHotkey - lalt_down_time) < 300 )
            {
                ; TODO: Single Press LAlt With Hold LShift
            }
        }
        else
        {
            KeyWait, LAlt
            SetLayout(dictor_code)
        }
    }
    else
    {
        KeyWait, LShift
        if (A_PriorKey == "LShift" && A_TimeSinceThisHotkey < single_press_time)
        {
            Send, {Esc}
        }
    }
}
return