0

on windows 10 there is an option to change the cursor indicator color (Win+I -> Ease of Access -> Text Cursor).

I would love (even pay if there was an app for it) to change the text cursor color depending on the selected input language. I am using both (English & Greek) a lot of time and continually interchange between them. Most of the times I start typing the first words really fast and then delete all of them, change the language, and start again. I wish I could avoid that. I know there is an indicator at the notification area, but it is very small and usually I just ignore it.

I use Autohotkey and my keyboard can perform macros. Any ideas would be very welcome.

2
  • Similar question and my solution superuser.com/a/1292388/456981
    – Mikhail V
    Nov 13, 2022 at 13:56
  • Note that system cursor will probably be handled by the application anyway so in most cases it is not possible to change it permamently.
    – Mikhail V
    Nov 13, 2022 at 13:59

3 Answers 3

1

Assuming the other code from user3419297 is correct for detecting the language (I didn't test it), the additional function below will change the cursor indicator color.

I put a few colors you can test--you can define your own colors in the code, or read them back from the registry key if you want to use the color chooser in the GUI where you would normally change the color (Easy Access settings). I'm assuming the number field might be Blue/Green/Red (in hex, one byte per color), but didn't check that either... at a minimum, red is the lowest byte. Or you can just use the straight hex codes if you want instead of defining named colors, but I typically like to define a few colors in English that I can swap between without having to use the hex values.

#SingleInstance Force
    SetTimer, ChangeCursor, 100
return

ChangeCursor:
    If GetKeyboardLanguage(WinActive("A")) = 0x0409  ; English  (0x0408 ; Greek)
        cursorIndicatorColorSet("gold")
    Else 
        cursorIndicatorColorSet()   ; set to black (note, this doesn't turn the cursor indicator off, just sets to black
return

; https://www.autohotkey.com/board/topic/116538-detect-which-language-is-currently-on/#entry672197

GetKeyboardLanguage(_hWnd=0){
    if !_hWnd
        ThreadId=0
    else
        if !ThreadId := DllCall("user32.dll\GetWindowThreadProcessId", "Ptr", _hWnd, "UInt", 0, "UInt")
            return false
    if !KBLayout := DllCall("user32.dll\GetKeyboardLayout", "UInt", ThreadId, "UInt")
        return false
    return KBLayout & 0xFFFF
}

cursorIndicatorColorSet(color:="") {
    hexColor := (color="Red")   ? "0xFF"
              : (color="Gold")  ? "0xBFFF"
              : (color="Black") ? "0x00"
              : "0x00"  ; default for no argument is black
    RegWrite, REG_DWORD, HKEY_CURRENT_USER, % "SOFTWARE\Microsoft\Accessibility\CursorIndicator", IndicatorColor, % hexColor
}

If you want to find other accessibility settings like this in order to modify them programmatically, download the SysInternals Procmon utility, then filter to only show SystemSettings.exe (or whatever program it is you are trying to look into, if it's not a system setting). Start logging in Procmon, toggle the item you want to capture in the System Settings, then stop logging in Procmon and look through the registry entries captured that the system settings tried to open or change when you changed settings.

In this case above I just opened the Accessibility settings, found the setting you said you wanted to use (cursor indicator color), toggled the color, and looked at which Registry items were read or modified.

To extend this code for example, it would probably be trivial to set the cursor indicator color for one language, but then turn it off completely for the other. That's a separate switch in the Accessibility settings to turn it on/off, vs. just setting the color, so the Accessibility settings will write a different registry key if you toggle that on/off (which you may or may not want to use, but it would be pretty easy to find--just as an example).

Same thing for say, the mouse cursor color (which might have different uses, and I'm not referring to simply the cursor shape in the other AutoHotkey example, but the mouse color option available in Accessibility).

At any rate, once you know how to log the registry keys, you can poke at the registry directly with RegEdit to see if it does what you want it to (Procmon will let you jump to the registry location directly from any entry that you capture, where you can then edit by hand, or watch the value change by changing settings and hitting refresh), and then if poking at it directly in RegEdit works, then you can add a registry read/write statement for that key/value to whatever kind of scripting action you may want to take (as shown above).

3

Try this AHK script

#Persistent
#SingleInstance Force

SetTimer, ChangeCursor, 100
OnExit("ExitFunc")
return

ChangeCursor:
If GetKeyboardLanguage(WinActive("A")) = 0x0409  ; English  (0x0408 ; Greek)
&& A_Cursor = "IBeam"
    applied ?: SetSystemCursor("IDC_SIZENS"), applied := true
else 
    (!applied) ?: RestoreCursors(), applied := false
return


 ; https://www.autohotkey.com/board/topic/116538-detect-which-language-is-currently-on/#entry672197

GetKeyboardLanguage(_hWnd=0){
    if !_hWnd
        ThreadId=0
    else
        if !ThreadId := DllCall("user32.dll\GetWindowThreadProcessId", "Ptr", _hWnd, "UInt", 0, "UInt")
            return false    
    if !KBLayout := DllCall("user32.dll\GetKeyboardLayout", "UInt", ThreadId, "UInt")
        return false    
    return KBLayout & 0xFFFF
}


ExitFunc(ExitReason, ExitCode){
    if ExitReason not in Logoff,Shutdown
        RestoreCursors()
}


; https://autohotkey.com/board/topic/32608-changing-the-system-cursor/
SetSystemCursor( Cursor = "", cx = 0, cy = 0 ) 
{
    BlankCursor := 0, SystemCursor := 0, FileCursor := 0 ; init

    SystemCursors = 32512IDC_ARROW,32513IDC_IBEAM,32514IDC_WAIT,32515IDC_CROSS
    ,32516IDC_UPARROW,32640IDC_SIZE,32641IDC_ICON,32642IDC_SIZENWSE
    ,32643IDC_SIZENESW,32644IDC_SIZEWE,32645IDC_SIZENS,32646IDC_SIZEALL
    ,32648IDC_NO,32649IDC_HAND,32650IDC_APPSTARTING,32651IDC_HELP

    If Cursor = ; empty, so create blank cursor 
    {
        VarSetCapacity( AndMask, 32*4, 0xFF ), VarSetCapacity( XorMask, 32*4, 0 )
        BlankCursor = 1 ; flag for later
    }
    Else If SubStr( Cursor,1,4 ) = "IDC_" ; load system cursor
    {
        Loop, Parse, SystemCursors, `,
        {
            CursorName := SubStr( A_Loopfield, 6, 15 ) ; get the cursor name, no trailing space with substr
            CursorID := SubStr( A_Loopfield, 1, 5 ) ; get the cursor id
            SystemCursor = 1
            If ( CursorName = Cursor )
            {
                CursorHandle := DllCall( "LoadCursor", Uint,0, Int,CursorID )   
                Break                   
            }
        }   
        If CursorHandle = ; invalid cursor name given
        {
            Msgbox,, SetCursor, Error: Invalid cursor name
            CursorHandle = Error
        }
    }   
    Else If FileExist( Cursor )
    {
        SplitPath, Cursor,,, Ext ; auto-detect type
        If Ext = ico 
            uType := 0x1    
        Else If Ext in cur,ani
            uType := 0x2        
        Else ; invalid file ext
        {
            Msgbox,, SetCursor, Error: Invalid file type
            CursorHandle = Error
        }       
        FileCursor = 1
    }
    Else
    {   
        Msgbox,, SetCursor, Error: Invalid file path or cursor name
        CursorHandle = Error ; raise for later
    }
    If CursorHandle != Error 
    {
        Loop, Parse, SystemCursors, `,
        {
            If BlankCursor = 1 
            {
                Type = BlankCursor
                %Type%%A_Index% := DllCall( "CreateCursor"
                , Uint,0, Int,0, Int,0, Int,32, Int,32, Uint,&AndMask, Uint,&XorMask )
                CursorHandle := DllCall( "CopyImage", Uint,%Type%%A_Index%, Uint,0x2, Int,0, Int,0, Int,0 )
                DllCall( "SetSystemCursor", Uint,CursorHandle, Int,SubStr( A_Loopfield, 1, 5 ) )
            }           
            Else If SystemCursor = 1
            {
                Type = SystemCursor
                CursorHandle := DllCall( "LoadCursor", Uint,0, Int,CursorID )   
                %Type%%A_Index% := DllCall( "CopyImage"
                , Uint,CursorHandle, Uint,0x2, Int,cx, Int,cy, Uint,0 )     
                CursorHandle := DllCall( "CopyImage", Uint,%Type%%A_Index%, Uint,0x2, Int,0, Int,0, Int,0 )
                DllCall( "SetSystemCursor", Uint,CursorHandle, Int,SubStr( A_Loopfield, 1, 5 ) )
            }
            Else If FileCursor = 1
            {
                Type = FileCursor
                %Type%%A_Index% := DllCall( "LoadImageA"
                , UInt,0, Str,Cursor, UInt,uType, Int,cx, Int,cy, UInt,0x10 ) 
                DllCall( "SetSystemCursor", Uint,%Type%%A_Index%, Int,SubStr( A_Loopfield, 1, 5 ) )         
            }          
        }
    }   
}

RestoreCursors() 
{
   SPI_SETCURSORS := 0x57
   DllCall( "SystemParametersInfo", UInt,SPI_SETCURSORS, UInt,0, UInt,0, UInt,0 )
}

or create/download an icon file and load that file using

Cursor = %A_ScriptDir%\mycursor.ani
CursorHandle := DllCall( "LoadCursorFromFile", Str,Cursor )

https://www.autohotkey.com/board/topic/32608-changing-the-system-cursor/

0
0

You can also use SKAN's function SetCursorScheme(Scheme):

#Persistent
#SingleInstance Force

SetTimer, ChangeCursor, 100
OnExit("ExitFunc")
return

ChangeCursor:
If GetKeyboardLanguage(WinActive("A")) = 0x0409  ; English  (0x0408 ; Greek)
&& A_Cursor = "IBeam"
   SetCursorScheme("Magnified")
else 
    SetCursorScheme("Windows Default")
return

 ; https://www.autohotkey.com/board/topic/116538-detect-which-language-is-currently-on/#entry672197
GetKeyboardLanguage(_hWnd=0){
    if !_hWnd
        ThreadId=0
    else
        if !ThreadId := DllCall("user32.dll\GetWindowThreadProcessId", "Ptr", _hWnd, "UInt", 0, "UInt")
            return false    
    if !KBLayout := DllCall("user32.dll\GetKeyboardLayout", "UInt", ThreadId, "UInt")
        return false    
    return KBLayout & 0xFFFF
}

; https://www.autohotkey.com/boards/viewtopic.php?t=82431
SetCursorScheme( Scheme )               { ; By SKAN on D3AO/D3AO @ tiny.cc/setcursorscheme
Local
  Cursors := "Arrow,Help,AppStarting,Wait,Crosshair,IBeam,NWPen,No,SizeNS,"
           . "SizeWE,SizeNWSE,SizeNESW,SizeAll,UpArrow,Hand,Pin,Person"
  SchemePath2 := "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Control Panel\Cursors"
  SchemePath1 := "HKCU\Control Panel\Cursors"
  SetRegView, 64
  If ( Scheme="Windows Default" )
  {
      RegWrite, REG_SZ,    %SchemePath1%,, Windows Default
      RegWrite, REG_DWORD, %SchemePath1%, Scheme Source, 2
      Loop, Parse, Cursors, CSV
      {
          RegRead, Val, %SchemePath2%\Default, %A_LoopField%
          If (! ErrorLevel )
          RegWrite, REG_EXPAND_SZ, %SchemePath1%, %A_LoopField%, %Val%
      }
      SetRegView, Default
      Return DllCall("SystemParametersInfo", "Int",0x57, "Int", 0, "Ptr", 0, "Int", 0)
  }
  SchemeSource := 2
  RegRead, Val, %SchemePath2%\Schemes, %Scheme%
  If ( ErrorLevel )
  {
      SchemeSource := 1
      RegRead, Val, %SchemePath1%\Schemes, %Scheme%
  }
  If ( ErrorLevel )
      SchemeSource := 0,    Scheme := ""
  Cur := StrSplit(Val, ",")
  RegWrite, REG_DWORD, %SchemePath1%, Scheme Source, %SchemeSource%
  RegWrite, REG_SZ, %SchemePath1%,, %Scheme%
  Loop, Parse, Cursors, CSV
  {
      RegRead, Val, %SchemePath2%\Default, %A_LoopField%
      If (! ErrorLevel )
          RegWrite, REG_EXPAND_SZ, %SchemePath1%, %A_LoopField%, % Cur[A_Index]
  }
  SetRegView, Default
Return DllCall("SystemParametersInfo", "Int",0x57, "Int", 0, "Ptr", 0, "Int", 0)
}

ExitFunc(ExitReason, ExitCode){
    if ExitReason not in Logoff,Shutdown
        SetCursorScheme("Windows Default")
}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .