get keyboard layout of active window (win 10) - autohotkey

I use this script to track the keyboard layout on Win 7, it works ok:
getactiveKL() {
active_hwnd := WinExist("A")
threadID := dllCall("GetWindowThreadProcessId", "uint", active_hwnd)
code := dllCall("GetKeyboardLayout", "uint", threadID, "uint") & 0xFFFF
return code
}
; 1049 - RU (hex: 419)
; 1033 - EN (hex: 409)
loop {
sleep, 600
KL := getactiveKL()
tooltip, %KL%
}
But it dooes not work on win 10. Namely it works only once - if I set the layout to RU, and then run this script, it detects correctly, but when I switch the layout - nothing changes.
Do you know how to make it work on windows 10?

The problem was in this line:
threadID := dllCall("GetWindowThreadProcessId", "uint", active_hwnd)
It should be:
threadID := dllCall("GetWindowThreadProcessId", "uint", active_hwnd, "uint", 0)
There are many examples in the web with different spelling of this dll call, so the latter works on windows 10 correctly.

Related

Switch keyboard layout Works but NOT Always

I'm a bit new to Autohotkey.
I have 3 Language installed, one of them I use very rarely. so I want to Toggle switch only between 2 languages (EN-RU) using WIN+Space.
I searched web found code which was short and logically close to my need, I done some modification to be more object like and personalised conditions.
Code: Select all - Expand View
#Space::
SetFormat, Integer, H
Lang := { "EN" : "0x4090409" , "RU" : "0x4190419", "HE": "0x40D040D" }
WinGet, WinID,, A
ThreadID:=DllCall("GetWindowThreadProcessId", "Int", WinID, "Int", "0")
InputLocaleID:=DllCall("GetKeyboardLayout", "Int", ThreadID)
if(InputLocaleID=Lang.RU OR InputLocaleID=Lang.HE)
SendMessage, 0x50,, % Lang.EN,, A
else if(InputLocaleID=Lang.EN)
SendMessage, 0x50,, % Lang.RU,, A
Exit
it works well with most of programs but with few of them it only get switch to RU.
Works Well: Chrome, notePad, notePad++, Notion, VScode, Android Studio, IntelliJ IDEA,
Doesn't Work: OneNote Windows 10 app (even so in Onenote 2016 it works fine)
If someone can help me with it I would Greatly appreciate it.
Thanks in Advance!
related answer Autohotkey Forum
#Space:: ; Switch keyboard (EN-RU)
Lang := { "EN": 0x4090409, "RU": 0x4190419 }
; For compatibility with UWP apps, get the thread of the focused
; control, not the active window. This is necessary because those
; apps are hosted within a window owned by a different process.
ControlGetFocus Focused, A
ControlGet CtrlID, Hwnd,, % Focused, A
; Using Ptr vs. Int vs. UInt won't matter in these cases
ThreadID := DllCall("GetWindowThreadProcessId", "Ptr", CtrlID, "Ptr", 0)
; HKL is a handle type (64-bit on x64)
InputLocaleID := DllCall("GetKeyboardLayout", "UInt", ThreadID, "Ptr")
if (InputLocaleID != Lang.EN)
SendMessage, 0x50,, % Lang.EN,, ahk_id %CtrlID%
else
SendMessage, 0x50,, % Lang.RU,, ahk_id %CtrlID%
Exit

Use AutoHotKey to switch to the most recently opened app in the ACTIVE monitor?

I've been using a short AutoHotKey script to simulate Alt Tab on Windows 10 using the middle mouse button, so that I can quickly open my most recently opened app, or toggle between two apps, with the click of a button. This is what I'm using
Mbutton::SendEvent {Alt Down}{Tab}{Alt Up}
But I've been using two monitors recently, and what I really want to do is switch to the most recently opened app ON THE ACTIVE MONITOR (or the monitor that the mouse is currently on). Alt Tab alone doesn't work obviously, because often the most recently opened app is on the other monitor and I only want to bring the window of the most recently used app forward if it is in the monitor I'm currently working in. Does anyone know if this is possible and how I might go about doing it?
I am pasting here my script. It is very ugly, but it works on my two-monitor setup as you described: switches to the previous (for the monitor where you click middle button) active window.
#WinActivateForce
#SingleInstance
#Persistent
CoordMode, Mouse, Screen
CoordMode, ToolTip, Screen
DetectHiddenWindows, On
SetTitleMatchMode , 2
SetBatchLines , -1
SetWorkingDir %A_ScriptDir%
Thread, interrupt, 0
SetTimer, UpdateCurrentWindow, 100
isDebug := true
SysGet, monitors_total, MonitorCount
SysGet, monitor_primary, MonitorPrimary
Hotkey, MButton, SwitchToLastWindow, On
return
SwitchToLastWindow:
WinGet, active_id, ID, A
Loop , %monitors_total%
{
if (A_Index != current_monitor)
continue
switch_to_window := (active_id = winlast%A_Index%)
? winprelast%A_Index%
: winlast%A_Index%
}
WinActivate , ahk_id %switch_to_window%
return
UpdateCurrentWindow:
WinGet, active_id, ID, A
monitor_index := GetMonitorIndexFromWindow(active_id)
current_monitor := GetMonitorIndexFromMouse()
if (monitor_index > monitors_total)
monitors_total := monitor_index
if (winlast%monitor_index% != active_id)
{
winprelast%monitor_index% := winlast%monitor_index%
winlast%monitor_index% := active_id
}
if isDebug
{
DebugToolTip := ""
Loop , %monitors_total%
{
DebugToolTip .= "Monitor # " . A_Index
. ":`n`nLast window: " . winlast%A_Index%
. "`nPre-last window: " . winprelast%A_Index% . "`n`n"
}
MouseGetPos, xpos, ypos
DebugToolTip .= "x: " . xpos . "`ny: " . ypos . "`ncurrent_monitor: " . current_monitor
. "`n`nA_ScreenHeight: " . A_ScreenHeight . "`nA_ScreenWidth: " . A_ScreenWidth
. "`n`nmonitors_total: " . monitors_total . "`nmonitor_primary: " . monitor_primary
ToolTip , %DebugToolTip%, 10, 10
}
return
; only done for one case: total 2 monitors, monitor to the left is primary
; need to redo for the generic case
GetMonitorIndexFromMouse()
{
SysGet, monitors_total, MonitorCount
SysGet, monitor_primary, MonitorPrimary
MouseGetPos, xpos, ypos
current_monitor := (xpos > A_ScreenWidth) ? 2 : 1
return current_monitor
}
; this function is from autohotkey.com/board/topic/69464-how-to-determine-a-window-is-in-which-monitor/?p=440355
GetMonitorIndexFromWindow(windowHandle)
{
; Starts with 1.
monitorIndex := 1
VarSetCapacity(monitorInfo, 40)
NumPut(40, monitorInfo)
if (monitorHandle := DllCall("MonitorFromWindow", "uint", windowHandle, "uint", 0x2))
&& DllCall("GetMonitorInfo", "uint", monitorHandle, "uint", &monitorInfo)
{
monitorLeft := NumGet(monitorInfo, 4, "Int")
monitorTop := NumGet(monitorInfo, 8, "Int")
monitorRight := NumGet(monitorInfo, 12, "Int")
monitorBottom := NumGet(monitorInfo, 16, "Int")
workLeft := NumGet(monitorInfo, 20, "Int")
workTop := NumGet(monitorInfo, 24, "Int")
workRight := NumGet(monitorInfo, 28, "Int")
workBottom := NumGet(monitorInfo, 32, "Int")
isPrimary := NumGet(monitorInfo, 36, "Int") & 1
SysGet, monitorCount, MonitorCount
Loop, %monitorCount%
{
SysGet, tempMon, Monitor, %A_Index%
; Compare location to determine the monitor index.
if ((monitorLeft = tempMonLeft) and (monitorTop = tempMonTop)
and (monitorRight = tempMonRight) and (monitorBottom = tempMonBottom))
{
monitorIndex := A_Index
break
}
}
}
return monitorIndex
}
One of the functions (GetMonitorIndexFromWindow(windowHandle)) is not mine, taken from here.
Note that I haven’t got time to work on generic case for my GetMonitorIndexFromMouse() function, so it’s just good for my specific case (2 monitors, with the left one as primary).
I have isDebug := true here, so that you could see the tooltip with variables − feel free to change it to isDebug := false of course, if the script works for you.

How to get value of ram address using module + base pointer + offsets?

I'm trying to use Autohotkey for reading out some RAM values. To do this I'm using the following library:
https://github.com/Kalamity/SC2-MacroTrainer/blob/master/Lib/classMemory.ahk
Documention on how this library works is clearly written on top of it, but it lacks any documentation on how to use this with a module.
My base pointer is: "jvm.dll"+00338E84
My offsets are (top to bottom): 0x8, 0x294, 0x4B8, 0x24, 0x20
My code so far is:
#include %a_scriptdir%/classMemory.ahk
java := new _ClassMemory("ahk_exe javaw.exe", "", hProcessCopy)
if !isObject(java)
msgbox failed to open a handle
myBase := java.getModuleBaseAddress("jvm.dll")
pointerBase := myBase + 0x00338E84
arrayPointerOffsets := [0x20, 0x24, 0x4B8, 0x294, 0x8]
value := java.read(pointerBase, "UInt", arrayPointerOffsets*)
msgbox %value%
Unfortunately this is not working. Obviously the pointerBase calculation is wrong. Been trying to use all kinds of variations for 2 days now without success. Could anyone explain me what I'm doing wrong and how to fix it?
I don't really have time to check the library you are using, but here are some tips:
If your target process runs as admin your program will have to, too. Also you might wanna set SeDebugPrivileges (if the lib isn't doing it on it's own).
If !A_IsAdmin {
Run *RunAs "%A_ScriptFullPath%"
ExitApp
}
SetSeDebugPrivilege()
SetSeDebugPrivilege(enable := True)
{
h := DllCall("OpenProcess", "UInt", 0x0400, "Int", false, "UInt", DllCall("GetCurrentProcessId"), "Ptr")
; Open an adjustable access token with this process (TOKEN_ADJUST_PRIVILEGES = 32)
DllCall("Advapi32.dll\OpenProcessToken", "Ptr", h, "UInt", 32, "PtrP", t)
VarSetCapacity(ti, 16, 0) ; structure of privileges
NumPut(1, ti, 0, "UInt") ; one entry in the privileges array...
; Retrieves the locally unique identifier of the debug privilege:
DllCall("Advapi32.dll\LookupPrivilegeValue", "Ptr", 0, "Str", "SeDebugPrivilege", "Int64P", luid)
NumPut(luid, ti, 4, "Int64")
if enable
NumPut(2, ti, 12, "UInt") ; enable this privilege: SE_PRIVILEGE_ENABLED = 2
; Update the privileges of this process with the new access token:
r := DllCall("Advapi32.dll\AdjustTokenPrivileges", "Ptr", t, "Int", false, "Ptr", &ti, "UInt", 0, "Ptr", 0, "Ptr", 0)
DllCall("CloseHandle", "Ptr", t) ; close this access token handle to save memory
DllCall("CloseHandle", "Ptr", h) ; close this process handle to save memory
return r
}
To read offsets you simply have to add them to your address.
So let's pretend you are memory reading a game. And you wanna read the health of player one which is always stored in ["example.dll"+0x01088450]+0x4 (as float value). Then you would have to go like this (if you work with raw ReadProcessMemory or similar):
player1moduleOffset := 0x01088450
healthOffset := 0x4
moduleBaseAddress := GetModuleAddr("example.dll")
player1BaseAddress := moduleBaseAddress+player1moduleOffset
player1Base := MemoryReasAsInt(player1BaseAddress)
player1HealthAddress := player1Base+healthOffset
player1Health := MemoryReasAsFloat(player1HealthAddress)
With the help of the library developer I managed to fix the issue. This is the working code:
#include %a_scriptdir%/classMemory.ahk
java := new _ClassMemory("ahk_exe javaw.exe")
if !isObject(java)
msgbox failed to open a handle
baseAddress := java.getModuleBaseAddress("jvm.dll")
arrayPointerOffsets := [0x20, 0x24, 0x4B8, 0x294, 0x8]
value := java.read(baseAddress + 0x00338E84, "UInt", arrayPointerOffsets*)
msgbox %value%

Autohotkey: How can I get the positions of win 7 desktop icons

I want to implement a poor mans "Windows Fences" (by stardock software) using autohotkey.
It can be as ineffective as it can as far as programming goes. I just want to get the positions of each desktop icon upon running a ahk code snippet and using another code snippet, I'd like to put them back to where they were.
I looked at the ahk code contributions and didn't see anything like this. But again, my search terms might be a little off. Assuming no such code exists, is there a way to get the screen positions of each icon and their identifying information in autohotkey ? This will at least help me start. I am sure more questions will come.
Example
Try the following with the function posted below :
icons := getDeskIconsPos()
chromePos := icons["Google Chrome"]
for k, pos in chromePos
{
msgbox % "Google Chrome.lnk is at X: " pos.x " Y: " pos.y
}
Description
The function returns an object (thanks to MCL) with each item being identified by name. Under each name item is an array of all occurring instances. Each array item will have an X and Y containing the corresponding coordinates.
See code for THE_ITEMNAME, THE_X_COORD and THE_Y_COORD.
I have used these names to clarify where the information is stored.
The Function
getDeskIconsPos() {
Critical
static MEM_COMMIT := 0x1000, PAGE_READWRITE := 0x04, MEM_RELEASE := 0x8000
static LVM_GETITEMPOSITION := 0x00001010, LVM_SETITEMPOSITION := 0x0000100F, WM_SETREDRAW := 0x000B
ControlGet, hwWindow, HWND,, SysListView321, ahk_class Progman
if !hwWindow ; #D mode
ControlGet, hwWindow, HWND,, SysListView321, A
IfWinExist ahk_id %hwWindow% ; last-found window set
WinGet, iProcessID, PID
hProcess := DllCall("OpenProcess" , "UInt", 0x438 ; PROCESS-OPERATION|READ|WRITE|QUERY_INFORMATION
, "Int", FALSE ; inherit = false
, "ptr", iProcessID)
ret := {}
if hwWindow and hProcess
{
ControlGet, list, list,Col1
VarSetCapacity(iCoord, 8)
pItemCoord := DllCall("VirtualAllocEx", "ptr", hProcess, "ptr", 0, "UInt", 8, "UInt", MEM_COMMIT, "UInt", PAGE_READWRITE)
Loop, Parse, list, `n ;Loop through items in list and get the information from the POINT structures
{
SendMessage, %LVM_GETITEMPOSITION%, % A_Index-1, %pItemCoord%
DllCall("ReadProcessMemory", "ptr", hProcess, "ptr", pItemCoord, "UInt", &iCoord, "UInt", 8, "UIntP", cbReadWritten)
;<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>
THE_ITEMNAME := A_LoopField
THE_X_COORD := NumGet(iCoord,"Int")
THE_Y_COORD := Numget(iCoord, 4,"Int")
;<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>
if(!ret.HasKey(THE_ITEMNAME))
{
ret[THE_ITEMNAME] := []
}
ret[THE_ITEMNAME].Insert({x: THE_X_COORD, y: THE_Y_COORD})
}
DllCall("VirtualFreeEx", "ptr", hProcess, "ptr", pItemCoord, "ptr", 0, "UInt", MEM_RELEASE)
}
DllCall("CloseHandle", "ptr", hProcess)
return ret
}
Extra
If you simply want to save and restore the desktop icon positions, you may try DeskIcons() here :
http://ahkscript.org/boards/viewtopic.php?f=6&t=3529
Example usage of DeskIcons() :
; save positions
coords := DeskIcons()
MsgBox now move the icons around yourself
; load positions
DeskIcons(coords)
I don't think there's an easy way to achieche this. But ImageSearch should work quite well if performance isn't an issue (even if it is: for smaller numbers of icons, it should still perform acceptably). The only problem I see is the desktop background: If it changes, ImageSearch will most likely fail, except for perfectly quadratic/nontransparent icons. There are three workarounds for that:
Never change your desktop background. The easiest way but most likely not an option if you are a frequent desktop restyler.
Take new screenshots of the icons every time you change the background. Very high maintenance depending on your need to change the desktop.
Let the script change the desktop background to a default color before it runs ImageSearch. My favorite since it's easy to implement and you won't have to worry about anything.
After you've found the position of the respective icon, the rest is pretty trivial: MouseClickDrag it from its old position to the target position.
References:
ImageSearch
docs
MouseClickDrag docs
Changing the desktop background with AHK

What to do when ControlSend or Send doesn't work?

I recently upgraded to Windows 8.1 x64, now script that i was using doesn't work anymore. That script would right click tray icon of a certain program than navigate to one of its options then click that option.
Here is the script:::
;#NoTrayIcon
DetectHiddenWindows, On
;Outlook on the Desktop--------------------------------------------------------------------------------------------------------------------------------
^1:: ;25,000$ Fine Tuned
Info := TrayIcons("OutlookDesktop.exe") ; OutlookDesktop.exe is the prog i tested with
StringSplit, TrayInfo, Info,|
PostMessage, TrayInfo1, TrayInfo2, 0x0205,, ahk_id %TrayInfo3% ; this is the right-click
Sleep 500
Send {Down 3}{Right}{Down 7}{Right}{Down 4}{Enter}
return
^2:: ;Projects
Info := TrayIcons("OutlookDesktop.exe") ; OutlookDesktop.exe is the prog i tested with
StringSplit, TrayInfo, Info,|
PostMessage, TrayInfo1, TrayInfo2, 0x0205,, ahk_id %TrayInfo3% ; this is the right-click
Sleep 500
Send {Down 3}{Right}{Down 7}{Right}{Down 1 4}{Enter}
return
^3:: ;Due This Week - unfinished
Info := TrayIcons("OutlookDesktop.exe") ; OutlookDesktop.exe is the prog i tested with
StringSplit, TrayInfo, Info,|
PostMessage, TrayInfo1, TrayInfo2, 0x0205,, ahk_id %TrayInfo3% ; this is the right-click
Sleep 500
Send {Down 3}{Right}{Down 7}{Right}{Down 2 4}{Enter}
return
^4:: ;To-do Bar Calendar View
Info := TrayIcons("OutlookDesktop.exe") ; OutlookDesktop.exe is the prog i tested with
StringSplit, TrayInfo, Info,|
PostMessage, TrayInfo1, TrayInfo2, 0x0205,, ahk_id %TrayInfo3% ; this is the right-click
Sleep 500
Send {Down 3}{Right}{Down 7}{Right}{Down 7 4}{Enter}
return
; Found and abused from
; http://www.autohotkey.com/forum/topic17314.html
; thx, Sean ... GREAT WORK!
TrayIcons(sExeName = "OutlookDesktop.exe")
{
WinGet, pidTaskbar, PID, ahk_class Shell_TrayWnd
hProc := DllCall("OpenProcess", "Uint", 0x38, "int", 0, "Uint", pidTaskbar)
pRB := DllCall("VirtualAllocEx", "Uint", hProc, "Uint", 0
, "Uint", 20, "Uint", 0x1000, "Uint", 0x4)
VarSetCapacity(btn, 20)
VarSetCapacity(nfo, 24)
VarSetCapacity(sTooltip, 128)
VarSetCapacity(wTooltip, 128 * 2)
SendMessage, 0x418, 0, 0, ToolbarWindow32, ahk_class Shell_TrayWnd
Loop, %ErrorLevel%
{
SendMessage, 0x417, A_Index - 1, pRB, ToolbarWindow32, ahk_class Shell_TrayWnd
DllCall("ReadProcessMemory", "Uint", hProc, "Uint", pRB, "Uint", &btn, "Uint", 20, "Uint", 0)
iBitmap := NumGet(btn, 0), idn := NumGet(btn, 4), Statyle := NumGet(btn, 8)
dwData := NumGet(btn,12), iString := NumGet(btn,16)
DllCall("ReadProcessMemory", "Uint", hProc, "Uint", dwData, "Uint", &nfo, "Uint", 24, "Uint", 0)
hWnd := NumGet(nfo, 0), uID := NumGet(nfo, 4)
nMsg := NumGet(nfo, 8)
WinGet, pid, PID, ahk_id %hWnd%
WinGet, sProcess, ProcessName, ahk_id %hWnd%
WinGetClass, sClass, ahk_id %hWnd%
If !sExeName || (sExeName = sProcess) || (sExeName = pid)
{
DllCall("ReadProcessMemory", "Uint", hProc, "Uint", iString
, "Uint", &wTooltip, "Uint", 128 * 2, "Uint", 0)
DllCall("WideCharToMultiByte", "Uint", 0, "Uint", 0, "str", wTooltip
, "int", -1, "str", sTooltip, "int", 128, "Uint", 0, "Uint", 0)
sTrayIcons .= nMsg "|" uID "|" hWnd
}
}
DllCall("VirtualFreeEx", "Uint", hProc, "Uint", pRB, "Uint", 0, "Uint", 0x8000)
DllCall("CloseHandle", "Uint", hProc)
Return sTrayIcons
}
;Outlook on the Desktop-----------------------END OF SCRIPT------------------------------------------------------------------------------
Now i googled some more and found this script:::
BlockInput, on
pos := Tray_Define("CCC.exe", "i")
Tray_Click(pos, "R")
WinWait, ahk_class #32768
; WinHide, ahk_class #32768 ;this and next line are to hide the menu.
; WinKill, ahk_class SysShadow
ControlSend,,{Down}{Down}{Down}{Down}{Down}{ENTER},ahk_class #32768
BlockInput, off
ExitApp
Interestingly enough, script is working perfectly on Catalyst Control Centar (CCC.exe) but not on that program i want it to work on, it successfully right clicks but sending control commands is not working. (Also have tried with just Send instead of ControlSend)
What do you guys think is the problem here, why are ControlSend and Send commands not working? What do you suggest that i try?
This is an partial answer:
Since Windows 7, AHK must be always run as administrator, otherwise it shows strange behavior (sometimes not listening to hotkeys, sometimes not sending keys).
Please post your point with BlockIntput into another answer.