1 (изменено: soulwhite, 2014-11-03 02:41:38)

Тема: AHK: Случайное срабатывание capslock при переключении языков

Добрый день. Задача стоит такая: переключение языка по капслук, включение/выключение режима капслук по Альт+капслук, реверс неверной раскладки (ghbdtn ? привет) по контрол+капслук. И следующее, капс + любые клавиши = мои функции, к примеру, капс + hjkl — Vim-подобная навигация. НО! Если добавить в скрипт (все написано в одном файле) эти функции, т.е. капс+ клавиши, то капс начинает глючить при переключении языков, т.е. он включает нижний/верхний регистр символов. Проблема не в функции переключения. Для примера, нажимаем очень быстро любые кнопки на клавиатуре и нажимаем на капс, результат:
uiouщшuoiгoiuщшuoiгщшгщuщшгщшuшщгiouшщuioгшщuioгoiuшщuioг
Как видим, все в порядке. Далее, добавляем в скрипт строку:


; раскладка вима для навигации
CapsLock & h:: send {Left}

И делаем то же самое, результат:
uoiUIOuIOUoiuoiГЩШгЩШГшщгщшuiГШЩГшouOuoiuOIUiouOIUIOгШЩГшщгшUIOuiou
Почему так? Это пример был тестовый, на деле же, капс лук в стандартном режиме срабатывает иногда.
Приведу свой код, функции взяты с форумов:


; Контекстное меню + wasd - навигация
AppsKey & w:: send {PgUp}
Return
AppsKey & s:: send {PgDn}
Return
AppsKey & a:: send {Home}
Return
AppsKey & d:: send {End}
Return
;-------------------------------------------------------------


; Контекстное меню + таб - неразрывный абзац.
AppsKey & tab:: send {ASC 255}{ASC 255}{ASC 255}{ASC 255}
;-------------------------------------------------------------


; вставка кавычек
~!,:: send «»{Left}
Return
~!.:: send «»{Left}
Return
~!':: send ""{Left}
Return
;-------------------------------------------------------------


; вствка длинного тире (альт + минус)
~!-:: —
Return
;-------------------------------------------------------------




; ДВОЙНОЕ нажатие windows — запуск диспетчера задач
~LWin::
  if (A_PriorHotkey <> "~LWin" or A_TimeSincePriorHotkey > 230)
; если предыдущая клавиша - не LWin,
; или со времени нажатия win прошло больше 230 миллисекунд, то...
{
  KeyWait, LWin
  ;ожидать, пока клавиша не будет отпущена
  ;(чтобы исключить срабатывание от простого удержания нажатой клавиши)
  Return ; закончить обработку горячей клавиши после отжатия клавиши
}
KeyWait, LWin
Run taskmgr.exe 
Return


;-------------------------------------------------------------
; обычная работа клавиши контекстного меню
~AppsKey::send, {AppsKey}
Return
;-------------------------------------------------------------




!CapsLock:: 
{ 
  
  GetKeyState, state, CapsLock, T ;  D if CapsLock is ON or U otherwise.
  state := GetKeyState("Capslock", "T")  ; True if CapsLock is ON, false otherwise.

  if(state)
  {
    SetCapsLockState, off
    Return
  }
  if(not state)
  {
    SetCapsLockState, on
    Return
  }
}






$CapsLock::LangSwitch(2)
;$CapsLock up::LangSwitch(2)

LangSwitch( iKeyDownUp=0 )
{
    static tickLast
    IfEqual,iKeyDownUp,1
    {    tickLast=%A_TickCount%
        return
    }
    IfEqual,iKeyDownUp,2
        If( A_TickCount-tickLast>900 )
            return

    HKL:=DllCall("GetKeyboardLayout", "uint",GetThreadOfWindow(), "uint")

    HKLnum:=DllCall("GetKeyboardLayoutList","uint",0,"uint",0)
    VarSetCapacity( HKLlist, HKLnum*4, 0 )
    DllCall("GetKeyboardLayoutList","uint",HKLnum,"uint",&HKLlist)
    loop,%HKLnum%
    {    if( NumGet( HKLlist, (A_Index-1)*4 ) = HKL )
        {    HKL:=NumGet( HKLlist, mod(A_Index,HKLnum)*4 )
            break
        }
    }
    ControlGetFocus,ctl,A
    SendMessage,0x50,0,HKL,%ctl%,A ;WM_INPUTLANGCHANGEREQUEST

    ;show traytip
    LOCALE_SENGLANGUAGE=0x1001
    LOCALE_SENGCOUNTRY=0x1002
    VarSetCapacity( sKbd, 260, 0 )
    VarSetCapacity( sCountry, 260, 0 )
    DllCall("GetLocaleInfo","uint",HKL>>16,"uint",LOCALE_SENGLANGUAGE, "str",sKbd, "uint",260)
    DllCall("GetLocaleInfo","uint",HKL & 0xFFFF,"uint",LOCALE_SENGCOUNTRY, "str",sCountry, "uint",260)
    traytip,%sKbd%,%sCountry%
    SetTimer,REMOVE_TOOLTIP,5000 ;0.5 second
    return
REMOVE_TOOLTIP:
    SetTimer,REMOVE_TOOLTIP,off
    traytip
    return
}

;returns first thread for the <processID>
;sets optional <List> to pipe | separated thread list for the <processID>
GetProcessThreadOrList( processID, byRef list="" )
{
    ;THREADENTRY32 {
    THREADENTRY32_dwSize=0 ; DWORD
    THREADENTRY32_cntUsage = 4    ;DWORD
    THREADENTRY32_th32ThreadID = 8    ;DWORD
    THREADENTRY32_th32OwnerProcessID = 12    ;DWORD
    THREADENTRY32_tpBasePri = 16    ;LONG
    THREADENTRY32_tpDeltaPri = 20    ;LONG
    THREADENTRY32_dwFlags = 24    ;DWORD
    THREADENTRY32_SIZEOF = 28

    TH32CS_SNAPTHREAD=4

    hProcessSnap := DllCall("CreateToolhelp32Snapshot","uint",TH32CS_SNAPTHREAD, "uint",0)
    ifEqual,hProcessSnap,-1, return

    VarSetCapacity( thE, THREADENTRY32_SIZEOF, 0 )
    NumPut( THREADENTRY32_SIZEOF, thE )

    ret=-1

    if( DllCall("Thread32First","uint",hProcessSnap, "uint",&thE ))
        loop
        {
            if( NumGet( thE ) >= THREADENTRY32_th32OwnerProcessID + 4)
                if( NumGet( thE, THREADENTRY32_th32OwnerProcessID ) = processID )
                {    th := NumGet( thE, THREADENTRY32_th32ThreadID )
                    IfEqual,ret,-1
                        ret:=th
                    list .=  th "|"
                }
            NumPut( THREADENTRY32_SIZEOF, thE )
            if( DllCall("Thread32Next","uint",hProcessSnap, "uint",&thE )=0)
                break
        }

    DllCall("CloseHandle","uint",hProcessSnap)
    StringTrimRight,list,list,1
    return ret
}

; Returns thread owning specified window handle
; default = Active window
GetThreadOfWindow( hWnd=0 )
{
    IfEqual,hWnd,0
        hWnd:=WinExist("A")
    DllCall("GetWindowThreadProcessId", "uint",hWnd, "uintp",id)
    GetProcessThreadOrList(  id, threads )
    IfEqual,threads,
        return 0
    CB:=RegisterCallback("GetThreadOfWindowCallBack","Fast")
    lRet=0
    lParam:=hWnd
    loop,parse,threads,|
    {    NumPut( hWnd, lParam )
        DllCall("EnumThreadWindows", "uint",A_LoopField, "uint",CB, "uint",&lParam)
        if( NumGet( lParam )=true )
        {    lRet:=A_LoopField
            break
        }
    }
    DllCall("GlobalFree", "uint", CB)
    return lRet
}

GetThreadOfWindowCallBack( hWnd, lParam )
{
    IfNotEqual,hWnd,% NumGet( 0+lParam )
        return true
    NumPut( true, 0+lParam )
    return 0
}






LControl & $CapsLock::RecodeTextENRU()

RecodeTextENRU()
{
    StringCaseSense On
    AutoTrim,Off

    clipSave:=clipAnsi()
    send ^{Insert}
    sleep,50

    dest=
    text:=clipAnsi()
    StringCaseSense,On
    prevCharToEN=0
    ;        АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ
    RUtoEN=F<DULT:PBQRKVYJGHCNEA{WXIO}SM">Zf,dult;pbqrkvyjghcnea[wxio]sm'.z
    RUtoSP1=хъжэбюХЪЖЭБЮ.,/"№;:?
    RUtoSP2=[];',.{}:"<>/?|@#$^&
    ;"         ABCDEFGHIJKLMNOPQRSTUVWXYZ
    ENtoRU=ФИСВУАПРШОЛДЬТЩЗЙКЫЕГМЦЧНЯфисвуапршолдьтщзйкыегмцчня

    loop,parse,text
    {
        destChar=%A_LoopField%

        ; check explicit (non punctuations) ranges
        ifGreaterOrEqual,A_LoopField,А
            prevCharToEN=1
        else if A_LoopField between A and Z
            prevCharToEN=0
        else if A_LoopField between a and z
            prevCharToEN=0

        ; to Russian
        ifEqual,prevCharToEN,0
        {    StringGetPos,i,RUtoEN,%A_LoopField%
            ifEqual,ErrorLevel,0
                Transform,destChar,chr,% i + 0xC0
            else
            {    StringGetPos,i,RUtoSP2,%A_LoopField%
                ifEqual,ErrorLevel,0
                    StringMid,destChar,RUtoSP1,% i+1, 1
            }
        }

        ; to English because nothing changed
        ifEqual,destChar,%A_LoopField%
        {
            StringGetPos,i,ENtoRU,%A_LoopField%
            ifEqual,ErrorLevel,0
                Transform,destChar,chr,% i + (i>=26 ? 71 : 65)
            else ; check .,;':"[]{}
            {    StringGetPos,i,RUtoSP1,%A_LoopField%
                ifEqual,ErrorLevel,0,StringMid,destChar,RUtoSP2,% i+1, 1
            }
            ifNotEqual,destChar,%A_LoopField%
                prevCharToEN=1
        }
        dest=%dest%%destChar%
    }

    ; decide compatibility of unicode clipboard
    WinGetClass,cls,A
    if cls in TMsgEditor,wndclass_desked_gsk
    {
        ControlGetFocus,cls,A
        ifInString,cls,TXTRichEdit
            clipSetUnicode(dest)
        else
            Clipboard=%dest%
    }
    else
        clipSetUnicode(dest)
    sleep,50
    send +{Insert}
    sleep 50

    clipSetUnicode(clipSave)
    LangSwitch()
}

; read unicode clipboard into ansi string
clipAnsi()
{
    StringLen,L,Clipboard
    L:=(L+1)*4
    transform,ca_Clip,unicode
    varSetCapacity(ca_WideText,L,0)
    varSetCapacity(ca_AnsiText,L,0)
    ; Convert UTF-8 to UTF-16.    CP_UTF8=65001
    if dllCall("MultiByteToWideChar",uint,65001, uint,0, str,ca_Clip
                  , uint,-1, str,ca_WideText, uint,L/2)
        dllCall("WideCharToMultiByte",uint,0, uint,0, str,ca_WideText
                  , uint,-1, str,ca_AnsiText, uint,L/2, uint,0, uint,0)
        ; Convert UTF-16 to ANSI.  CP_ACP=0
    return ca_AnsiText
}

;--------------------------------------------------------------
; copy ansi string to clipboard in unicode mode
clipSetUnicode(cu_AnsiText)
{
    StringLen,L,cu_AnsiText
    L:=(L+1)*4
    varSetCapacity(cu_WideText,L,0)
    varSetCapacity(cu_UTFtext,L,0)
    ; ANSI to UTF-16.    CP_ACP=0
    if dllCall("MultiByteToWideChar",uint,0, uint,0, str,cu_AnsiText
                  , uint,-1, str,cu_WideText, uint,L/2)
        dllCall("WideCharToMultiByte",uint,65001, uint,0, str,cu_WideText
                  , uint,-1, str,cu_UTFtext, uint,L/2, uint,0, uint,0)
        ; Convert UTF-16 to UTF-8.  CP_UTF8=65001
    transform,clipboard,unicode,%cu_UTFtext%
}











; раскладка вима для навигации
CapsLock & h:: send {Left}




2

Re: AHK: Случайное срабатывание capslock при переключении языков

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

; ... 
$CapsLock::
   State := GetKeyState("Capslock", "T") ? "On" : "Off"
   LangSwitch(2)
   SetCapsLockState, %State%
Return
; ...

Возможно, как-то конфликтуют другие функции, слишком много всего завязано на одну клавишу. Надо бы по-хорошему весь этот сборный "компот" пересобрать, например переключение по Alt+CapsLock проще в одну строку сделать:

!CapsLock:: SetCapsLockState, % GetKeyState("Capslock", "T") ? "Off" : "On"

3

Re: AHK: Случайное срабатывание capslock при переключении языков

Irbis пишет:

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

; ... 
$CapsLock::
   State := GetKeyState("Capslock", "T") ? "On" : "Off"
   LangSwitch(2)
   SetCapsLockState, %State%
Return
; ...

Возможно, как-то конфликтуют другие функции, слишком много всего завязано на одну клавишу. Надо бы по-хорошему весь этот сборный "компот" пересобрать, например переключение по Alt+CapsLock проще в одну строку сделать:

!CapsLock:: SetCapsLockState, % GetKeyState("Capslock", "T") ? "Off" : "On"

Сделал все как вы сказали. Не сработало. Видимо, нельзя использовать капслук для переключения, и для горячих клавиш.  А очень жаль, ибо на него можно повесить много всего. Еще конечно остается правый контрол и контекстное меню, но мне удобней для левой руки бы. По поводу кода, с английским не очень, только изучаю автохоткей, ваши приемы сокращения придут с опытом.

4

Re: AHK: Случайное срабатывание capslock при переключении языков

Тут вставляется случайно скорее всего «родное» срабатываение капслука. Не знаю, как быть. Я, конечно, уже сделал, то что хочу, для вима, а именно, включение/выключение режима своих клавиш по двойному нажатию правого шифта. То есть, если я хочу использовать альт+l для движения курсора влево (кстати, как сделать так, чтобы с зажатым альт+шифт+l еще и текст выделялся?), я включаю режим вима (два раза шифт) и использую. Если нужна стандартная работа клавиш альт+l (в тотале к примеру переназначены) то снова два раза шифт, и он выключается. Но очень бы хотелось иметь капслук как клавишу. Тут же куча вариаций, капслук + клавиши ни одна программа не использует.

5 (изменено: stealzy, 2014-11-12 18:46:46)

Re: AHK: Случайное срабатывание capslock при переключении языков


#If GetKeyState("CapsLock", "P")
    vk48:: ; h keycode
    myFunc()
    return
#If

Также я надеюсь переключение языка у вас срабатывает по отпусканию Caps`a, с использованием KeyWait.
Также можно отключить Caps в системе.
И еще:

#If CapsRShift:=(GetKeyState("CapsLock", "P") And GetKeyState("RShift", "P"))
    vk48:: ; h keycode
    myFunc()
    return
#If