Jump to content

_WinAPI_GetKeyboardLayout Doesn't Work On Command Line


Adele
 Share

Recommended Posts

I want to detect when the user has changed the keyboard layout on command line. I've tried _WinAPI_GetKeyboardLayout() function. It works wonderful with other programs but doesn't work on command line. I change the keyboard layout but the function returns always initial value.

I've prepared a script to detect changes. You could see the problem with through testing.

#include <WinAPISys.au3>
#RequireAdmin
Global $hWnd, $bKey

Opt("TrayAutoPause", 0)

Run("cmd.exe")
$hWnd = WinWait("[CLASS:ConsoleWindowClass]")

OnAutoItExitRegister("closing")

While 1
    Sleep(100)

    $bNewKey = _WinAPI_GetKeyboardLayout($hWnd)

    ConsoleWrite("Current keyboard layout: " & $bNewKey & @CRLF)

    If $bKey AND $bNewKey AND $bNewKey <> $bKey Then
        MsgBox(64, "Warning", "The keyboard layout changes has been detected." & @CRLF & "The previous keyboard layout: "& $bKey & @CRLF & "The new keyboard layout: " & $bNewKey)
        Exit
    ElseIf Not $bNewKey Then
        Exit
    EndIf

    $bKey = $bNewKey
WEnd

Func closing()
    WinKill($hWnd)
EndFunc

If you test it with Notepad, there isn't a problem.

kodevreni_1439942461__keyboard_layout.pn

#include <WinAPISys.au3>
#RequireAdmin
Global $hWnd, $bKey

Opt("TrayAutoPause", 0)

Run("notepad.exe")
$hWnd = WinWait("[CLASS:Notepad]")

OnAutoItExitRegister("closing")

While 1
    Sleep(100)

    $bNewKey = _WinAPI_GetKeyboardLayout($hWnd)

    ConsoleWrite("Current keyboard layout: " & $bNewKey & @CRLF)

    If $bKey AND $bNewKey AND $bNewKey <> $bKey Then
        MsgBox(64, "Warning", "The keyboard layout changes has been detected." & @CRLF & "The previous keyboard layout: "& $bKey & @CRLF & "The new keyboard layout: " & $bNewKey)
        Exit
    ElseIf Not $bNewKey Then
        Exit
    EndIf

    $bKey = $bNewKey
WEnd

Func closing()
    WinKill($hWnd)
EndFunc

Thank you in advance. 

Edited by Adele
Link to comment
Share on other sites

I read your post a couple of times.  I think you are saying that it does not work without a window for a program to detect the changes.  If so, that is in line with the explanation in the help file: "Retrieves the active input locale identifier for the specified window".

I think you can do it from the command line as discussed here: http://superuser.com/questions/841236/how-to-know-which-keyboard-layout-is-currently-active-using-cmd-in-windows-7-32b

Edited by Jfish

Build your own poker game with AutoIt: pokerlogic.au3 | Learn To Program Using FREE Tools with AutoIt

Link to comment
Share on other sites

Sorry for my English.

In summary; _WinAPI_GetKeyboardLayout() can get specific window's keyboard layout. It works with other programs but doesn't get on command prompt window. It always returns the same value.

 

I read your post a couple of times.  I think you are saying that it does not work without a window for a program to detect the changes.  If so, that is in line with the explanation in the help file: "Retrieves the active input locale identifier for the specified window".

I think you can do it from the command line as discussed here: http://superuser.com/questions/841236/how-to-know-which-keyboard-layout-is-currently-active-using-cmd-in-windows-7-32b

Unfortunately, I don't mean this. I want to get command prompt window's keyboard layout via Autoit. Thank you for reply.

Link to comment
Share on other sites

You're Adele, English is your native language!

UDF List:

 
_AdapterConnections()_AlwaysRun()_AppMon()_AppMonEx()_ArrayFilter/_ArrayReduce_BinaryBin()_CheckMsgBox()_CmdLineRaw()_ContextMenu()_ConvertLHWebColor()/_ConvertSHWebColor()_DesktopDimensions()_DisplayPassword()_DotNet_Load()/_DotNet_Unload()_Fibonacci()_FileCompare()_FileCompareContents()_FileNameByHandle()_FilePrefix/SRE()_FindInFile()_GetBackgroundColor()/_SetBackgroundColor()_GetConrolID()_GetCtrlClass()_GetDirectoryFormat()_GetDriveMediaType()_GetFilename()/_GetFilenameExt()_GetHardwareID()_GetIP()_GetIP_Country()_GetOSLanguage()_GetSavedSource()_GetStringSize()_GetSystemPaths()_GetURLImage()_GIFImage()_GoogleWeather()_GUICtrlCreateGroup()_GUICtrlListBox_CreateArray()_GUICtrlListView_CreateArray()_GUICtrlListView_SaveCSV()_GUICtrlListView_SaveHTML()_GUICtrlListView_SaveTxt()_GUICtrlListView_SaveXML()_GUICtrlMenu_Recent()_GUICtrlMenu_SetItemImage()_GUICtrlTreeView_CreateArray()_GUIDisable()_GUIImageList_SetIconFromHandle()_GUIRegisterMsg()_GUISetIcon()_Icon_Clear()/_Icon_Set()_IdleTime()_InetGet()_InetGetGUI()_InetGetProgress()_IPDetails()_IsFileOlder()_IsGUID()_IsHex()_IsPalindrome()_IsRegKey()_IsStringRegExp()_IsSystemDrive()_IsUPX()_IsValidType()_IsWebColor()_Language()_Log()_MicrosoftInternetConnectivity()_MSDNDataType()_PathFull/GetRelative/Split()_PathSplitEx()_PrintFromArray()_ProgressSetMarquee()_ReDim()_RockPaperScissors()/_RockPaperScissorsLizardSpock()_ScrollingCredits_SelfDelete()_SelfRename()_SelfUpdate()_SendTo()_ShellAll()_ShellFile()_ShellFolder()_SingletonHWID()_SingletonPID()_Startup()_StringCompact()_StringIsValid()_StringRegExpMetaCharacters()_StringReplaceWholeWord()_StringStripChars()_Temperature()_TrialPeriod()_UKToUSDate()/_USToUKDate()_WinAPI_Create_CTL_CODE()_WinAPI_CreateGUID()_WMIDateStringToDate()/_DateToWMIDateString()Au3 script parsingAutoIt SearchAutoIt3 PortableAutoIt3WrapperToPragmaAutoItWinGetTitle()/AutoItWinSetTitle()CodingDirToHTML5FileInstallrFileReadLastChars()GeoIP databaseGUI - Only Close ButtonGUI ExamplesGUICtrlDeleteImage()GUICtrlGetBkColor()GUICtrlGetStyle()GUIEventsGUIGetBkColor()Int_Parse() & Int_TryParse()IsISBN()LockFile()Mapping CtrlIDsOOP in AutoItParseHeadersToSciTE()PasswordValidPasteBinPosts Per DayPreExpandProtect GlobalsQueue()Resource UpdateResourcesExSciTE JumpSettings INISHELLHOOKShunting-YardSignature CreatorStack()Stopwatch()StringAddLF()/StringStripLF()StringEOLToCRLF()VSCROLLWM_COPYDATAMore Examples...

Updated: 22/04/2018

Link to comment
Share on other sites

LOL. (I heard the hipsters now say "haha"). Yes, I love your music.  That said, do you mean something like this?

run('cmd.exe')
sleep(2000)
send('reg query "HKEY_CURRENT_USER\Keyboard Layout\Preload"')
send("{enter}")

You can also use shellexecute and run but the command line window won't stay open.

Edited by Jfish

Build your own poker game with AutoIt: pokerlogic.au3 | Learn To Program Using FREE Tools with AutoIt

Link to comment
Share on other sites

@Jfish Sorry. It shows keyboard list on the system. I want to get selected keyboard layout on a window. Like I gave example above.

kodevreni_1439942461__keyboard_layout.pn

#include <WinAPISys.au3>
#RequireAdmin
Global $hWnd, $bKey

Opt("TrayAutoPause", 0)

Run("notepad.exe")
$hWnd = WinWait("[CLASS:Notepad]")

OnAutoItExitRegister("closing")

While 1
    Sleep(100)

    $bNewKey = _WinAPI_GetKeyboardLayout($hWnd)

    ConsoleWrite("Current keyboard layout: " & $bNewKey & @CRLF)

    If $bKey AND $bNewKey AND $bNewKey <> $bKey Then
        MsgBox(64, "Warning", "The keyboard layout changes has been detected." & @CRLF & "The previous keyboard layout: "& $bKey & @CRLF & "The new keyboard layout: " & $bNewKey)
        Exit
    ElseIf Not $bNewKey Then
        Exit
    EndIf

    $bKey = $bNewKey
WEnd

Func closing()
    WinKill($hWnd)
EndFunc

This code detects when the user has changed the keyboard layout while Notepad is running. I use _WinAPI_GetKeyboardLayout() function here.  The problem is that; this function doesn't work on command prompt window.

Edited by Adele
Link to comment
Share on other sites

Okay, how about this?

#include <WinAPISys.au3>
Opt("WinTitleMatchMode", 2) ;1=start, 2=subStr, 3=exact, 4=advanced, -1 to -4=Nocase
$windowTitle="Command Prompt"
$windowHandle=WinActivate($windowTitle)
$keyboard=_WinAPI_GetKeyboardLayout ($windowHandle)
MsgBox(0,"Keyboard",$keyboard)

 

Edited by Jfish

Build your own poker game with AutoIt: pokerlogic.au3 | Learn To Program Using FREE Tools with AutoIt

Link to comment
Share on other sites

Okay, how about this?

#include <WinAPISys.au3>
Opt("WinTitleMatchMode", 2) ;1=start, 2=subStr, 3=exact, 4=advanced, -1 to -4=Nocase
$windowTitle="Command Prompt"
$windowHandle=WinActivate($windowTitle)
$keyboard=_WinAPI_GetKeyboardLayout ($windowHandle)
MsgBox(0,"Keyboard",$keyboard)

 

There isn't a problem this section. When you changed the keyboard layout, it still returns the same value. I've worked to tell with screenshots:


The function always returns the same value on Command Prompt. The problem is here.

kodevreni_1440198812__2015-08-22_020448.

kodevreni_1440198842__2015-08-22_020851.

......................

But the function can detect uptodate and true value on other programs like Notepad.


kodevreni_1440199348__2015-08-22_021640.

kodevreni_1440199379__2015-08-22_022002.

Edited by Adele
Link to comment
Share on other sites

Okay, this is untested - because I am not sure how you change the keyboard layout for the Command Prompt window.  However, I did notice a problem with the _WinAPI_GetKeyboardLayout function.  It seems to work intermittently and was having issues inside a loop.  I am not sure what I did but my code above stopped working.  I decided to switch functions and use the keyboard list.  I assume the first entry is the current keyboard (that may or may not be true as I only have 1).  Again, the part that detects the change is untested but let me know if something like this works for you ...

#include <WinAPISys.au3>
#include <Array.au3>
Opt("WinTitleMatchMode", 2) ;1=start, 2=subStr, 3=exact, 4=advanced, -1 to -4=Nocase

Global $currentKeyboard=_getKeyBoard()
;ConsoleWrite(@CRLF&$currentKeyboard&@CRLF)
Global $newKeyboard=$currentKeyboard
;ConsoleWrite(@CRLF&$newKeyboard&@CRLF)

func _getKeyBoard()
    $windowTitle="Command Prompt"
    $windowHandle=WinActivate($windowTitle)
    local $keyboardList=_WinAPI_GetKeyboardLayoutList ( )
    return $keyboardList[1]
EndFunc

while 1
    sleep(1000)
    $currentKeyboard=_getKeyBoard()
    If $currentKeyboard <> $newKeyboard Then
        MsgBox(0,"Change Detected","New Keyboard is: "&$currentKeyboard)
        $newKeyboard=$currentKeyboard
    Else
        ConsoleWrite(@CRLF&$currentKeyboard&@CRLF)
    EndIF
WEnd

 

Build your own poker game with AutoIt: pokerlogic.au3 | Learn To Program Using FREE Tools with AutoIt

Link to comment
Share on other sites

maybe a workaround could be to be able to read the status of the checked language in the tray menu or at least the text of the associated tooltip....
it seems that the Handle of the "language selector" control is this [CLASS:CiceroUIWndFrame] but I have not idea on how to grab his status or text.
once we can get the text of that control, we could activate the cmd window and check his active language by reading the status of the "language selector" control. (indeed the status of this control changes any time you select a new window, showing his associated language.)

EDIT:

to try this behaviour do this:
1) open 2 cmd windows
2) activate one of those cmd and change his keyb language on the "language selector" in the tray bar
3) then alternately click on both cmd windows ant see the "text" changing on the keyb language tray control

EDIT 2:

other weirdness
if you type this 2 commands within a cmd promt:
chcp
or
mode con cp
the result is the active table code
but the result is always the same even when you change the keyboard language on the "language selector" tollbar control or by the chcp or the mode con cp commands... :think:

Edited by Chimp

 

image.jpeg.9f1a974c98e9f77d824b358729b089b0.jpeg Chimp

small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....

Link to comment
Share on other sites

I have been researching this a bit.  This may be a problem with the console vs. other windows.  I did not verify the way the user32.dll works - but this may explain it:

GetKeyboardLayout works with applications running in the WINDOWS subsystem (it's a user32.dll export). Command line applications run in the CONSOLE subsystem.

Cite: http://stackoverflow.com/questions/29217501/getkeyboardlayout-doesnt-work-properly-in-some-cases

I can detect the changes this way ... NOTE: not sure why I can't get it to work with the standard function - mine is basically the same except the way I open the DLL call (should not make a difference).

Func _WinAPI_GetKeyboardLayout2($hWnd)
Local $hDLL = DllOpen("user32.dll")
Local $aRet = DllCall('user32.dll', 'DWORD', 'GetWindowThreadProcessId', 'hwnd', $hWnd, 'ptr', 0)
$aRet = DllCall('user32.dll', 'handle', 'GetKeyboardLayout', 'DWORD', $aRet[0])
DllClose($hDLL)
Return $aRet[0]
EndFunc   ;==>_WinAPI_GetKeyboardLayout
$parentPID=run("conhost.exe")
$key=_WinAPI_GetKeyboardLayout2($parentPID)
MsgBox(0,"",$key)

 

Edited by Jfish

Build your own poker game with AutoIt: pokerlogic.au3 | Learn To Program Using FREE Tools with AutoIt

Link to comment
Share on other sites

@Adele - you need to hook the parent process of the console window.  I was using "conhost.exe" to do this with the command prompt open and it worked.  Then I switched keyboards and ran it again and it picked up the change.  Did you use my exact code?  I have tried it on two different machines and it worked on both.

Edited by Jfish

Build your own poker game with AutoIt: pokerlogic.au3 | Learn To Program Using FREE Tools with AutoIt

Link to comment
Share on other sites

Just an FYI to the post in #15, the DLLClose is in the wrong place, it needs to be before the Return statement.

If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Link to comment
Share on other sites

@Adele - you need to hook the parent process of the console window.  I was using "conhost.exe" to do this with the command prompt open and it worked.  Then I switched keyboards and ran it again and it picked up the change.  Did you use my exact code?  I have tried it on two different machines and it worked on both.

Yes, I did. I run exactly you've given code without modify. Only a MsgBox opens. Command Line window doesn't come. When I changed conhost.exe being cmd.exe, it opens but this time the same issue happens. I use Windows 7 (x64). I can show the issue with Teamviewer or capturing a video.

Func _WinAPI_GetKeyboardLayout2($hWnd)
    Local $hDLL = DllOpen("user32.dll")
    Local $aRet = DllCall('user32.dll', 'DWORD', 'GetWindowThreadProcessId', 'hwnd', $hWnd, 'ptr', 0)
    $aRet = DllCall('user32.dll', 'handle', 'GetKeyboardLayout', 'DWORD', $aRet[0])

    DllClose($hDLL)
    Return $aRet[0]
EndFunc   ;==>_WinAPI_GetKeyboardLayout

$parentPID=run("conhost.exe")
$key=_WinAPI_GetKeyboardLayout2($parentPID)
MsgBox(0,"",$key)
Edited by Adele
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...