Jump to content
Sign in to follow this  
WoodGrain

How to detect Qwerty vs Dvorak layout?

Recommended Posts

Hi guys,

I've seen the @kblayout macro, but the information I'm after is the keyboard layout (aka "Input Method") so I can detect if I'm using "US Keyboard" or "United States-Dvorak Keyboard" rather than 00000c09 or 00000409 which relate to languages such as EN AU or EN US for example.

For example I have 1 language set up (English Australia) in my regional settings, but then under the language I have "US Keyboard" and "United States-Dvorak Keyboard" setup, so that when I press WIN+SPACE I can toggle between them.

Effectively I want a way of determining if I'm running qwerty or dvorak.

Thanks guys!!

Share this post


Link to post
Share on other sites

I think @kblayout macro calls GetKeyboardLayout API, but it retrieves only low order byte, so it gets only the language identifier, you need the device identifier (also known as device handle or physical layout) too that's contained in high order bytes.

 

EDIT: On second thought, @kblayout macro calls GetKeyboardLayoutName function, which retrieves by default only language ID.

Edited by j0kky

Share this post


Link to post
Share on other sites

Don't you like GetKeyboardLayout?

#include <WinAPI.au3>

HotKeySet("{SPACE}", _GetKeyboardLayout)
HotKeySet("{ESC}", _Exit)

While 1
    Sleep(100)
WEnd

Func _GetKeyboardLayout()
    Local $aRet = DllCall("user32.dll", "HANDLE", "GetKeyboardLayout", "DWORD", 0)
    If @error Then
        ConsoleWrite("ERROR!" & @CRLF)
        Return
    EndIf
    ConsoleWrite("Language Identifier: " & Hex(_WinAPI_LoWord($aRet[0]), 4) & @CRLF & _
        "Device Identifier: " & Hex(_WinAPI_HiWord($aRet[0]), 4) & @CRLF & @CRLF)
EndFunc

Func _Exit()
    Exit
EndFunc

 

Edited by j0kky

Share this post


Link to post
Share on other sites

Result while in Qwerty:

Language Identifier: 0C09
Device Identifier: 0409

Result when using Dvorak:

Language Identifier: 0C09
Device Identifier: 0409

 

Share this post


Link to post
Share on other sites

That's really strange... Try this switching between the two keyboard setup without closing the application (and mantaining it on the top level). 

#include <WinAPI.au3>

Global Const $WM_INPUTLANGCHANGE = 0x0051
$hGUI = GUICreate("My GUI")
GUIRegisterMsg($WM_INPUTLANGCHANGE, "_WM_INPUTLANGCHANGE")
GUISetState(@SW_SHOW)
HotKeySet("{ESC}", _Exit)
WinActivate($hGUI)

While 1
    Sleep(100)
WEnd

Func _WM_INPUTLANGCHANGE($hWnd, $iMsg, $wParam, $lParam)
    Local $aRet = DllCall("user32.dll", "HANDLE", "GetKeyboardLayout", "DWORD", 0)
    If @error Then
        ConsoleWrite("ERROR!" & @CRLF)
        Return
    EndIf
    ConsoleWrite("Handle: " & $aRet[0]  & @CRLF & _
        "Language Identifier: " & Hex(_WinAPI_LoWord($aRet[0]), 4) & @CRLF & _
        "Device Identifier: " & Hex(_WinAPI_HiWord($aRet[0]), 4) & @CRLF & _
        "wParam: " & $wParam & @CRLF & _
        "lParam: " & $lParam & @CRLF & @CRLF)
    Return 'GUI_RUNDEFMSG'
EndFunc

Func _Exit()
    Exit
EndFunc

Then post here full console output.

Edited by j0kky

Share this post


Link to post
Share on other sites

Sorry about the delay!

Here's the output from the script, changing to EN-AU Dvorak first, then changing back to EN-AU Qwerty.

Quote

Handle: 0xF0020C09
Language Identifier: 0C09
Device Identifier: F002
wParam: 0x00000000
lParam: 0xF0020C09

Handle: 0x04090C09
Language Identifier: 0C09
Device Identifier: 0409
wParam: 0x00000000
lParam: 0x04090C09

Looks like the device identifier has picked it up while running the gui! I tried a truncated version of your script without the gui in a loop and it doesn't return the same result.

Edited by WoodGrain

Share this post


Link to post
Share on other sites

Is it possible to do this without a GUI?
I'm want to use it to display an icon so I can see at a glance which layout it's in.

Cheers

Share this post


Link to post
Share on other sites

What did you do to remove the GUI? You shouldn't need it for the code to run, you can start it and have it run in the tray with a hotkey or something.

EDIT: Upon further inspection it seems we need GuiRegisterMsg for this to work, so alternatively you could just try to make the GUI invisible in the background. I don't know if there is a non-GUI alternative to this function.

Edited by anthonyjr2

UHJvZmVzc2lvbmFsIENvbXB1dGVyZXI=

Share this post


Link to post
Share on other sites

Hehe, an invisible gui. I guess if there's not another option it's the best available way.

I've really done nothing with the gui before, does this create much overhead in the script?
I'm wanting to check the state of the keyboard layout every second.

Thanks.

Share this post


Link to post
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
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By Colduction
      Hi AutoIt Programmers!, I just looking for a way to change entered keys in English to Russian keys and reverse, i must clear for you to understand. For example:
       
      I write keys on keyboard and i forgot to change input language and then the result will be: Dkflbvbh (Thing we write in fact) ====> Владимир (Thing we want)
       
      And reverse: Владимир  ====> Dkflbvbh

      Is there any solution without writing constant for each words? for example dlls or WinAPIs.
    • By matwachich
      DEPRECATED: see this new UDF
       
    • By Fenzik
      Hello,
      i searched the forum for something near, but with no success...
      I have Combobox control with $CBS_DROPDOWNLIST style with some items (for example (one, two, nine).
      When i want to select the item, using keyboard, the items are selected only on First letter base (for example when i type "on", Nine is selected).
      Is there some trick to force the combobox with $CBS_DROPDOWNLIST style to accept more than the First letter during selecting the items from the list?
      Mi wanted result is the same as for example - when you type "fir" on the desktop, Firefox is automatically selected.
      Thank you so much.
      Fenzik
    • By WoodGrain
      Hi All,
      I've bought a Ergodox EZ programmable keyboard with layers of key maps (eg, layer 0 = dvorak, layer 1 = numberpad & nav, layer 2 = qwerty, etc), I've also got a small USB screen that can pull information from the registry. What I would like to determine is a way to pull the value of each current key from the keyboard, I can then write the values to the registry and pull them into my USB screen so I can see the keyboard key layout.
      I'm stuck with retrieving the key values, I've looked at _IsPressed(), _WinAPI_GetKeyState(), _WinAPI_GetKeyboardState(), _WinAPI_GetKeyboardType(), _WinAPI_GetKeyNameText(), but none of them appear to be able to pull the keyboard key values without user interaction.
      The idea being, in pseudo code, bear in mind no error checking etc in this code, "GetKeyValue()" is what I'm needing help with and is a made up function, as is "HardwareKey1" etc:
      $keyOnePrev = "" $numOfKeys = 76 While 1 $keyOneCurrent = GetKeyValue(HardwareKey1) If $keyOneCurrent <> $keyOnePrev Then For $key = 1 To $numOfKeys $keyToWrite = GetKeyValue(HardwareKey & $key) RegWrite("HKEY_CURRENT_USER\Software\myKeyboard", "key" & $key, "REG_SZ", $keyToWrite) Next EndIf $keyOnePrev = $keyOneCurrent Sleep(5000) WEnd Thanks guys!
    • By Bilgus
      Example of Subclassing listviews using setwindowSubclass in order to intercept WM_KEYUP events
      Also pops context menu on  Shift + F10
      #include <Misc.au3> #include <ListViewConstants.au3> #include <GUIConstants.au3> #include <GuiMenu.au3> #include <WinAPIShellEx.au3> Global $g_hCB, $g_pCB, $g_ahProc[2][2] ;Stores the Data for subclassing listview Global $g_LVKEYUP = 0xFE00, $g_LVKEYDN = 0xFD00 ;Our Own Custom messages (Key Up/Dn) Global $g_iDummyData Global $g_hGui = GUICreate("test") Global $g_hList1 = GUICtrlCreateListView("#|x|y", 5, 24, 161, 70, $LVS_SHOWSELALWAYS Or $LVS_SINGLESEL) GUICtrlCreateListViewItem("text", $g_hList1) Global $g_hList1_LVN = GUICtrlCreateDummy() ;Recieves Messages from the callback Global $g_hContext1 = GUICtrlCreateContextMenu($g_hList1) GUICtrlCreateMenuItem("1", $g_hContext1) GUICtrlCreateMenuItem("2", $g_hContext1) Global $g_hList2 = GUICtrlCreateListView("#|x|y", 5, 100, 161, 70, $LVS_SHOWSELALWAYS Or $LVS_SINGLESEL) GUICtrlCreateListViewItem("text", $g_hList2) Global $g_hList2_LVN = GUICtrlCreateDummy() ;Recieves Messages from the callback Global $g_hContext2 = GUICtrlCreateContextMenu($g_hList2) GUICtrlCreateMenuItem("3", $g_hContext2) GUICtrlCreateMenuItem("4", $g_hContext2) GUISetState(@SW_SHOW) SubClassListView() ;Creates our subclass Func SubClassListView() OnAutoItExitRegister("Cleanup") ;to remove our subclass $g_hCB = DllCallbackRegister('_SubclassProc', 'lresult', 'hwnd;uint;wparam;lparam;uint_ptr;dword_ptr') $g_pCB = DllCallbackGetPtr($g_hCB) $g_ahProc[0][0] = $g_hList1 ;Add the Ids of the controls we'd like to subclass $g_ahProc[1][0] = $g_hList2 ;Set up the subclass _WinAPI_SetWindowSubclass ( $hWnd, $pSubclassProc, $idSubClass [, $pData = 0] ) $g_ahProc[0][1] = _WinAPI_SetWindowSubclass(GUICtrlGetHandle($g_ahProc[0][0]), $g_pCB, $g_ahProc[0][0], $g_hList1_LVN) $g_ahProc[1][1] = _WinAPI_SetWindowSubclass(GUICtrlGetHandle($g_ahProc[1][0]), $g_pCB, $g_ahProc[1][0], $g_hList2_LVN) EndFunc ;==>SubClassListView Func _SubclassProc($hWnd, $iMsg, $wParam, $lParam, $iID, $pData) #forceref $iID Local $iRtnMsg = 0 ;Events we'd like to intercept If $iMsg = $WM_KEYUP Or $iMsg = $WM_SYSKEYUP Then $iRtnMsg = $g_LVKEYUP ElseIf $iMsg = $WM_KEYDOWN Or $iMsg = $WM_SYSKEYDOWN Then $iRtnMsg = $g_LVKEYDN EndIf ;We Recieve the Id of the dummy through $pData and pass our RtnMsg to the dummy control If $iRtnMsg Then GUICtrlSendToDummy($pData, BitOR($iRtnMsg, $wParam)) ;Pass messages on to the default handler Return _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) EndFunc ;==>_SubclassProc Func Cleanup() For $i = 0 To UBound($g_ahProc) - 1 ;Remove Our Subclass' by setting it back to the original proc _WinAPI_RemoveWindowSubclass(GUICtrlGetHandle($g_ahProc[$i][0]), DllCallbackGetPtr($g_ahProc[$i][1]), $g_ahProc[$i][0]) Next DllCallbackFree($g_hCB) EndFunc ;==>Cleanup While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE Exit Case $g_hList1_LVN ;This is just a dummy it only recieves events ConsoleWrite("LV1 EVENT 0x" & Hex($g_iDummyData, 4) & @CRLF) $g_iDummyData = GUICtrlRead($g_hList1_LVN) ;Retrieve the code that was sent Switch BitAND($g_iDummyData, 0xFF00) ;Get the keyup/dn status Case $g_LVKEYDN If BitAND($g_iDummyData, 0x00FF) = 0x79 And (_IsPressed("A0") Or _IsPressed("A1")) Then ;Right/ Left Shift & F10 ShowMenu($g_hGui, $g_hList1, $g_hContext1) Else ConsoleWrite("Lv1 KeyDn Vk: 0x" & Hex(BitAND($g_iDummyData, 0x00FF), 2) & @CRLF) ;Get the Virtual keycode EndIf Case $g_LVKEYUP ConsoleWrite("Lv1 KeyUp Vk: 0x" & Hex(BitAND($g_iDummyData, 0x00FF), 2) & @CRLF) ;Get the Virtual keycode EndSwitch Case $g_hList2_LVN $g_iDummyData = GUICtrlRead($g_hList2_LVN) ;Retrieve the code that was sent ConsoleWrite("LV2 EVENT 0x" & Hex($g_iDummyData, 4) & @CRLF) Switch BitAND($g_iDummyData, 0xFF00) ;Get the keyup/dn status Case $g_LVKEYDN ConsoleWrite("Lv2 KeyDn Vk: 0x" & Hex(BitAND($g_iDummyData, 0x00FF), 2) & @CRLF) ;Get the Virtual keycode Case $g_LVKEYUP ConsoleWrite("Lv2 KeyUp Vk: 0x" & Hex(BitAND($g_iDummyData, 0x00FF), 2) & @CRLF) ;Get the Virtual keycode EndSwitch EndSwitch WEnd Func ShowMenu($hWnd, $idCtrl, $idContext) Local $aPos, $iX, $iY Local $hMenu = GUICtrlGetHandle($idContext) $aPos = ControlGetPos($hWnd, "", $idCtrl) $iX = $aPos[0] $iY = $aPos[1] + $aPos[3] ClientToScreen($hWnd, $iX, $iY) ; Show at the given coordinates (x, y) the popup menu (hMenu) which belongs to a given GUI window (hWnd) _GUICtrlMenu_TrackPopupMenu($hMenu, $hWnd, $iX, $iY) EndFunc ;==>ShowMenu ; Convert the client (GUI) coordinates to screen (desktop) coordinates Func ClientToScreen($hWnd, ByRef $iX, ByRef $iY) Local $tPoint = DllStructCreate("int;int") DllStructSetData($tPoint, 1, $iX) DllStructSetData($tPoint, 2, $iY) DllCall("user32.dll", "int", "ClientToScreen", "hwnd", $hWnd, "struct*", $tPoint) $iX = DllStructGetData($tPoint, 1) $iY = DllStructGetData($tPoint, 2) ; release Struct not really needed as it is a local $tPoint = 0 EndFunc ;==>ClientToScreen  
      Old Code Using setWindowLong
       
×
×
  • Create New...