搬运一个键盘记录脚本[留档]

原贴链接:https://www.autohotkey.com/boards/viewtopic.php?f=6&t=26059

在原贴代码改了一些操作和窗口显示,基本上没怎么动。有点小bug不过不影响使用!

搬运一个键盘记录脚本[留档]

;@Ahk2Exe-SetMainIcon tool.ico
;@Ahk2Exe-AddResource tool.ico, 160
;@Ahk2Exe-AddResource Pause.png, 207
;@Ahk2Exe-AddResource Pause.png, 208
;@Ahk2Exe-ExeName %A_ScriptDir%\KeyHistoryTool.exe
;@Ahk2Exe-SetDescription key history tool
;@Ahk2Exe-SetFileVersion 1.0.0.0
;@Ahk2Exe-SetInternalName key history tool
;@Ahk2Exe-SetLanguage 0x0804
;@Ahk2Exe-SetName key history tool
;@Ahk2Exe-SetProductName key history tool
;@Ahk2Exe-SetProductVersion 1.0.0.0
;@Ahk2Exe-SetVersion 1.0.0.0

#NoEnv
#Persistent
#InstallKeybdHook
hHookKeybd := DllCall("SetWindowsHookEx", "int", 13 ; WH_KEYBOARD_LL = 13
	, "ptr", RegisterCallback("Keyboard")
	; hMod is not required on Win 7, but seems to be required on XP even
	; though this type of hook is never injected into other processes:
	, "ptr", DllCall("GetModuleHandle", "ptr", 0, "ptr")
	, "uint", 0, "ptr") ; dwThreadId
#KeyHistory(15)

OnMessage(0x200, "WM_MOUSEMOVE")
OnMessage(0x201, "WM_LBUTTONDOWN")
OnMessage(0x0203, "WM_LBUTTONDBLCLK")
OnMessage(0x100, "WM_KEYDOWN")
Gui +LastFound
DllCall( "RegisterShellHookWindow", "UInt",A_ScriptHwnd)
OnMessage( DllCall( "RegisterWindowMessage", "Str","SHELLHOOK" ), "ShellIMEMessage")

Menu, Tray, NoStandard
Menu, Tray,Color,ffffff
Menu, Tray, Add, Show, MenuHandler
Menu, Tray, Add
Menu, Tray, Add, Pause, MenuHandler
Menu, Tray, Add
Menu, Tray, Add, reload, MenuHandler
Menu, Tray, Add
Menu, Tray, Add, exit, MenuHandler
Menu, Tray, Default, Show
Gosub GetlockhBitmap
SysGet,SM_CYHSCROLL,3
Global text:=""
; WS_EX_COMPOSITED = E0x02000000 & WS_EX_LAYERED = E0x00080000 -> Double Buffer
Gui, +LastFound +AlwaysOnTop +E0x02000000 +E0x00080000 +HwndhGui
Gui, Margin, 10, 10
Gui,Color,000000,000000
Gui, Font,ffffff, Lucida Console
Gui, Add, Text,xm+5 ym+6 vKHT +0x100 +0x200 -E0x200 +BackgroundTrans cffffff Section, % Format("{:-4}{:-5}{:-7}{:-9}{:-19}{:-1}", "VK", "SC", "Flags", "Elapsed", "Key", "Extra")
Gui, Add, Edit,xm+5 y+20 vKH cffffff ReadOnly +Multi -E0x200 -Tabstop HWNDhedit, % Format("{:-4}{:-5}{:-7}{:-9}{:-19}{:-30}", "00", "000", "ea!u", "1000.00", "Browser_Favorites", "KEY_IGNORE_ALL_EXCEPT_MODIFIER")
GuiControlGet, KHT, Pos
GuiControlGet, KH, Pos
Gui, Add,Pic,% "xm ys-5 w" KHTW+SM_CYHSCROLL " h" KHTH*2,% "HBITMAP:" Gradient(KHTW+SM_CYHSCROLL, KHTH*2,[0xe6e6e6, 0x1e1e1e])
Gui, Add,Text,% "xm+" KHTW+SM_CYHSCROLL+5 " w" (KHW-KHTW-SM_CYHSCROLL)/2 " yp+5 BackgroundTrans cffffff Center",Clear All
Gui, Add,Pic,% "xp yp-5 w" (KHW-KHTW-SM_CYHSCROLL-10)/2 " h" KHTH*2 " gclearall",% "HBITMAP:" Gradient((KHW-KHTW-SM_CYHSCROLL-10)/2, KHTH*2,[0xe6e6e6, 0x1e1e1e])
Gui, Add,Text,% "x+3 yp+5 w" (KHW-KHTW-SM_CYHSCROLL-10)/2 " BackgroundTrans cffffff Center",Copy All
Gui, Add,Pic,% "xp yp-5 w" (KHW-KHTW-SM_CYHSCROLL-10)/2 " h" KHTH*2 " gcopyall",% "HBITMAP:" Gradient((KHW-KHTW-SM_CYHSCROLL-10)/2, KHTH*2,[0xe6e6e6, 0x1e1e1e])

GuiControl,, KH  ; clear dummy sizing text
GuiControlGet,KHTEXT,, KHT,text
gosub Resize
EmptyMem()
Return

#MaxThreadsBuffer, On
!WheelUp::
!WheelDown::
	#MaxThreadsBuffer, Off
	history_size := #KeyHistory() + ((A_ThisHotkey="!WheelUp") ? +1 : -1)
	#KeyHistory(history_size>0 ? history_size : 1)
	; Delay resize to improve hotkey responsiveness.
	SetTimer, Resize, -10
return

Copyall:
	GuiControlGet,KHVAULE,, KH,text
	Clipboard:=KHVAULE
	TrayTip,,copy successful!

Return

clearall:
	buf_size := #KeyHistory()
	#KeyHistory(0)
	GuiControl,, KH,
	Text:=""
	#KeyHistory(buf_size)
Return

Resize:
	; Resize label to fit key history.
	gui_h := KHH*#KeyHistory()
	GuiControl, Move, KH,% "h" gui_h " w" KHW
	gui_h += KHY + 15

	Gui, +LastFound
	; Determine visibility.
	WinGet, style, Style
	gui_visible := style & 0x10000000
	
	;Gui, Show, % "AutoSize NA " (gui_visible ? "" : "Hide")
	;** Not used because we need to know the previous height,
	;   and its simpler to resize manually.
	
	; Determine current position and height.
	WinGetPos, gui_x, gui_y, gui_w_old, gui_h_old
	; Use old height to determine if we should reposition, *only when shrinking*.
	; This way we can move the GUI somewhere else, and the script won't reposition it.
	;if (gui_h_old < gui_h)
	;	gui_h_old := gui_h
	; Determine working area (primary screen size minus taskbar.)
	SysGet, wa_, MonitorWorkArea
	
	SysGet, twc_h, 51 ; SM_CYSMCAPTION
	SysGet, bdr_h, 8  ; SM_CYFIXEDFRAME
	if (!gui_visible)
	{
		gui_x = 72 ; Initially on the left side.
		gui_y := wa_bottom-(gui_h+twc_h+bdr_h*2+10)
	}
	else
	{   ; Move relative to bottom edge when closer to the bottom.
		if (gui_y+gui_h//2 > (wa_bottom-wa_top)//2)
			gui_y += gui_h_old-(gui_h+twc_h+bdr_h*2)
	}

	GuiControl,, KHT,%KHTEXT%
	Gui, Show, % "x" (A_ScreenWidth-KHTW-30)/2 " y" (A_ScreenHeight-gui_h)/2 " h" gui_h+KHH-10 " w" KHW+SM_CYHSCROLL+5 " NA",% (A_IsAdmin?"[Admin]":"") "Key History"
	;OnMessage(0x20, Func("WM_SETCURSOR").Bind(hGui))
return

GuiSize:
	if (A_EventInfo = 1){
		Gui, Hide
		EmptyMem()
	}
return

MenuHandler:
	switch A_ThisMenuItem
	{
		case "Pause":
			if (A_IsPaused)
			{
				WinSetTitle, ahk_id %hGui%, ,% (A_IsAdmin?"[Admin]":"") "Key History"
				try {
					Menu, Tray, UnCheck, Pause
					Menu Tray, Icon, % A_IsCompiled?A_ScriptFullPath:A_AhkPath,,1
				}
			}
			else
			{
				WinSetTitle, ahk_id %hGui%, ,% (A_IsAdmin?"[Admin]":"") "Key History - Freezed"
				try {
					Gosub GetlockhBitmap
					Menu, Tray, Check, Pause
					Menu Tray, Icon, HBITMAP:*%lockhBitmap%,,1
				}
			}
			Pause Toggle
		
		case "Show":
			Gui, Show, ,% (A_IsAdmin?"[Admin]":"") "Key History - Freezed"
			if (!A_IsPaused)
			{
				WinSetTitle, ahk_id %hGui%, ,% (A_IsAdmin?"[Admin]":"") "Key History - Freezed"
				try {
					Gosub GetlockhBitmap
					Menu Tray, Icon, HBITMAP:*%lockhBitmap%,,1
					Menu, Tray, Check, Pause
				}
				Pause On
			}Else{
				WinSetTitle, ahk_id %hGui%, ,% (A_IsAdmin?"[Admin]":"") "Key History"
				try {
					Gosub GetlockhBitmap
					Menu, Tray, UnCheck, Pause
					Menu Tray, Icon, % A_IsCompiled?A_ScriptFullPath:A_AhkPath,,1
					Pause Toggle
				}
			}
		case "reload":
			Reload
		
		case "exit":
			ExitApp
	}
return

Keyboard(nCode, wParam, lParam) {
	global KeyBuffer
	static sz := 16+A_PtrSize
	
	Critical
	
	if KeyHistory(1, vk, sc, flags)
		&& NumGet(lParam+0, "uint") = vk
		&& NumGet(lParam+4, "uint") = sc
		&& NumGet(lParam+8, "uint") = flags
		buf_max := 0 ; Don't Show key-repeat.
	else
		buf_max := #KeyHistory()
	
	if (buf_max > 0)
	{
		; Push older key events to the back.
		if (buf_max > 1)
			DllCall("RtlMoveMemory", "ptr", &KeyBuffer+sz, "ptr", &KeyBuffer, "ptr", buf_max*sz)
		; Copy current key event to the buffer.
		DllCall("RtlMoveMemory", "ptr", &KeyBuffer, "ptr", lParam, "ptr", sz)
		
		; "gosub Show" slows down the keyboard hook and causes problems, so use a timer.		
		SetTimer, Show, -20
	}
	
	return DllCall("CallNextHookEx", "ptr", 0, "int", nCode, "ptr", wParam, "ptr", lParam, "ptr")
}

KeyHistory(N, ByRef vk, ByRef sc, ByRef flags:=0, ByRef time:=0, ByRef elapsed:=0, ByRef info:=0)
{
	global KeyBuffer
	static sz := 16+A_PtrSize
	
	if N is not integer
		return false
	buf_max := #KeyHistory()
	if (N < 0)
		N += buf_max + 1
	if (N < 1 or N > buf_max)
		return false
	
	vk	:= NumGet(KeyBuffer, (N-1)*sz, "uint")
	sc	:= NumGet(KeyBuffer, (N-1)*sz+4, "uint")
	flags := NumGet(KeyBuffer, (N-1)*sz+8, "uint")
	time  := NumGet(KeyBuffer, (N-1)*sz+12, "uint")
	info  := NumGet(KeyBuffer, (N-1)*sz+16)
	elapsed := time - ((time2 := NumGet(KeyBuffer, N*sz+12, "uint")) ? time2 : time)
	
	switch info
	{
		case 0xFFC3D44F: info := "KEY_IGNORE"
		case 0xFFC3D44E: info := "KEY_PHYS_IGNORE"
		case 0xFFC3D44D: info := "KEY_IGNORE_ALL_EXCEPT_MODIFIER"
	}
	
	return (vk or sc)
}

#KeyHistory(NewSize="")
{
	global KeyBuffer
	static sz := 16+A_PtrSize
	; Get current history length.
	if (NewSize="")
		return (cap:=VarSetCapacity(KeyBuffer)//sz)>0 ? cap-1 : 0
	if (NewSize)
	{
		new_cap := (NewSize+1)*sz
		cap := VarSetCapacity(KeyBuffer)
		if (cap > new_cap)
			cap := new_cap
		VarSetCapacity(old_buffer, cap)
		; Back up previous history.
		DllCall("RtlMoveMemory", "ptr", &old_buffer, "ptr", &KeyBuffer, "ptr", cap)
		
		; Set new history length.
		VarSetCapacity(KeyBuffer, 0) ; FORCE SHRINK
		VarSetCapacity(KeyBuffer, new_cap, 0)
		
		; Restore previous history.
		DllCall("RtlMoveMemory", "ptr", &KeyBuffer, "ptr", &old_buffer, "ptr", cap)
		
		; (Remember N+1 key events to simplify calculation of the Nth key event's elapsed time.)
		; Put tick count so the initial key event has a meaningful value for "elapsed".
		NumPut(A_TickCount, KeyBuffer, 12, "uint")
	}
	else
	{   ; Clear history entirely.
		VarSetCapacity(KeyBuffer, 0)
	}
}

GetKeyFlagText(flags)
{
	return ((flags & 0x1) ? "e" : "") ; LLKHF_EXTENDED
		. ((flags & 0x10) ? "a" : "") ; LLKHF_INJECTED (artificial)
		. ((flags & 0x20) ? "!" : "") ; LLKHF_ALTDOWN
		. ((flags & 0x80) ? "u" : "") ; LLKHF_UP (key up)
}

; Gets readable key name, usually identical to the name in KeyHistory.
GetKeyNameText(vkCode, scanCode, isExtendedKey)
{
	return GetKeyName(format("vk{1:02x}sc{3}{2:02x}", vkCode, scanCode, isExtendedKey))
	/* ; For older versions of AutoHotkey:
	; My Right Shift key Shows as vk161 sc54 isExtendedKey=true.  For some
	; reason GetKeyNameText only returns a name for it if isExtendedKey=false.
	if vkCode = 161
		return "Right Shift"
	
	VarSetCapacity(buffer, 32, 0)
	DllCall("GetKeyNameText"
		, "UInt", (scanCode & 0xFF) << 16 | (isExtendedKey ? 1<<24 : 0) ;| 1<<25
		, "Str", buffer
		, "Int", 32)
	
	return buffer
	*/
}

Show:
	SetFormat, FloatFast, .2
	SetFormat, IntegerFast, H
	text_ :=""
	buf_size := #KeyHistory()
	Loop, % buf_size
	{
		if (KeyHistory(buf_size+1-A_Index, vk, sc, flags, time, elapsed, info))
		{
			keytext := GetKeyNameText(vk, sc, flags & 0x1)
			
			if (elapsed < 0)
				elapsed := "#err#"
			else
				dt := elapsed/1000.0
			
			; AHK-style SC
			sc_a := sc
			if (flags & 1)
				sc_a |= 0x100, flags &= ~1
			sc_a := SubStr("000" SubStr(sc_a, 3), -2)
			vk_a := SubStr(vk+0, 3)
			if (StrLen(vk_a)<2)
				vk_a = 0%vk_a%
			StringUpper, vk_a, vk_a
			StringUpper, sc_a, sc_a
			
			flags := GetKeyFlagText(flags & ~0x1)
			text_:=Format("{:-4}{:-5}{:-7}{:-9}{:-19}{:-30}`n", vk_a, sc_a, flags, dt, keytext, info) (InStr(flags,"u")||(info,"KEY_IGNORE")?"··········································································`n":"")
			if InStr(text,text_)
				Continue
			text .= text_
		}
	}
	GuiControl,, KH, % Text  ;Trim(RegExReplace(Text "`n","m)(.+\n)(([^\r\n]+\n){25}\n*$)","$2"),"`n")
	SendMessage, 0xB1, -2, -1,, ahk_id %hedit%
	SendMessage, 0xB7,,,, ahk_id %hedit%
Return

GuiClose:
ExitApp
Return

GetlockhBitmap:
base64Code=
(join`r`n LTrim
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
SUVORK5CYII=
)
lockhBitmap:=hBitmapFromBase64(base64Code)
Return

WM_KEYDOWN()
{
	if A_Gui
		return true
}

WM_MOUSEMOVE(wParam, lParam, uMsg, hWnd)
{
	if (A_GuiControl="KHT")
		ToolTip In Flags`ne%A_Tab%=%A_Tab%Extended`na%A_Tab%=%A_Tab%Artificial`n!%A_Tab%=%A_Tab%Alt-Down`nu%A_Tab%=%A_Tab%Key-Up`nAlt+WheelDown/WheelUp to adjust the window size
	else
		ToolTip
}

WM_LBUTTONDOWN(wParam, lParam, uMsg, hWnd){
	Global hGui,lockhBitmap

	DllCall("user32.dll\PostMessage", "ptr", hWnd, "uint", 0x00A1, "ptr", 2, "ptr", 0)
}

ShellIMEMessage( wParam,lParam ) {
	Global hGui,lockhBitmap
	WinGet, MinMax, MinMax , ahk_id %hGui%
	if (MinMax<>0){
		EmptyMem()
		if !A_IsPaused
		{
			WinSetTitle, ahk_id %hGui%, ,% (A_IsAdmin?"[Admin]":"") "Key History - Freezed"
			try {
				Gosub GetlockhBitmap
				Menu, Tray, Check, Pause
				Menu Tray, Icon, HBITMAP:*%lockhBitmap%,,1
			}
			Pause Toggle
		}
	}
}
WM_SETCURSOR(hPic, wp) {
	static hCursor, flags := (LR_DEFAULTSIZE := 0x40) | (LR_SHARED := 0x8000)
		, params := [ "Ptr", 0, "UInt", OCR_HAND := 32649
			, "UInt", IMAGE_CURSOR := 2
			, "Int", 0, "Int", 0, "UInt", flags, "Ptr" ]
	(!hCursor && hCursor := DllCall("LoadImage", params*))
	if (wp = hPic)
		Return DllCall("SetCursor", "Ptr", hCursor)
}

hBitmapFromBase64(ByRef base64) {
	hBitmap := 0
	VarSetCapacity(B64, StrLen(base64) << !!A_IsUnicode)
	B64 := base64
	If !DllCall("Crypt32.dll\CryptStringToBinary", "Ptr", &B64, "UInt", 0, "UInt", 0x01, "Ptr", 0, "UIntP", DecLen, "Ptr", 0, "Ptr", 0)
		Return False
	VarSetCapacity(Dec, DecLen, 0)
	If !DllCall("Crypt32.dll\CryptStringToBinary", "Ptr", &B64, "UInt", 0, "UInt", 0x01, "Ptr", &Dec, "UIntP", DecLen, "Ptr", 0, "Ptr", 0)
		Return False
	; Bitmap creation adopted from "How to convert Image data (JPEG/PNG/GIF) to hBITMAP?" by SKAN
	; -> http://www.autohotkey.com/board/topic/21213-how-to-convert-image-data-jpegpnggif-to-hbitmap/?p=139257
	hData := DllCall("Kernel32.dll\GlobalAlloc", "UInt", 2, "UPtr", DecLen, "UPtr")
	pData := DllCall("Kernel32.dll\GlobalLock", "Ptr", hData, "UPtr")
	DllCall("Kernel32.dll\RtlMoveMemory", "Ptr", pData, "Ptr", &Dec, "UPtr", DecLen)
	DllCall("Kernel32.dll\GlobalUnlock", "Ptr", hData)
	DllCall("Ole32.dll\CreateStreamOnHGlobal", "Ptr", hData, "Int", True, "PtrP", pStream)
	hGdip := DllCall("Kernel32.dll\LoadLibrary", "Str", "Gdiplus.dll", "UPtr")
	VarSetCapacity(SI, 16, 0), NumPut(1, SI, 0, "UChar")
	DllCall("Gdiplus.dll\GdiplusStartup", "PtrP", pToken, "Ptr", &SI, "Ptr", 0)
	DllCall("Gdiplus.dll\GdipCreateBitmapFromStream",  "Ptr", pStream, "PtrP", pBitmap)
	DllCall("Gdiplus.dll\GdipCreateHBITMAPFromBitmap", "Ptr", pBitmap, "PtrP", hBitmap, "UInt", 0)
	DllCall("Gdiplus.dll\GdipDisposeImage", "Ptr", pBitmap)
	DllCall("Gdiplus.dll\GdiplusShutdown", "Ptr", pToken)
	DllCall("Kernel32.dll\FreeLibrary", "Ptr", hGdip)
	DllCall(NumGet(NumGet(pStream + 0, 0, "UPtr") + (A_PtrSize * 2), 0, "UPtr"), "Ptr", pStream)
	Return hBitmap
}

EmptyMem(PID=""){
	pid:=!PID ? DllCall("GetCurrentProcessId") : pid
	h:=DllCall("OpenProcess", "UInt", 0x001F0FFF, "Int", 0, "Int", pid)
	DllCall("SetProcessWorkingSetSize", "UInt", h, "Int", -1, "Int", -1)
	DllCall("CloseHandle", "Int", h)
}

; https://www.autohotkey.com/boards/viewtopic.php?f=6&t=91899

CreateGradient(W, H, V, aColors) {
    Local

    C := aColors.Length()

    xOFF := (X := V ? W : 0) ? 0 : Ceil(W / (C - 1))
    yOFF := (Y := V ? 0 : H) ? 0 : Ceil(H / (C - 1))

    VarSetCapacity(VERT, C * 16, 0)
    VarSetCapacity(MESH, C * 8,  0)

    Loop % (C, pVert := &VERT, pMesh := &MESH) {
        X :=   V ? (X == 0 ? W : X := 0) : X
        Y :=  !V ? (Y == 0 ? H : Y := 0) : Y
        Color :=  Format("{:06X}", aColors[A_Index] & 0xFFFFFF)
        Color :=  Format("0x{5:}{6:}00{3:}{4:}00{1:}{2:}00", StrSplit(Color)*)
        pVert :=  NumPut(Color, NumPut(Y, NumPut(X, pVert+0, "Int"), "Int"), "Int64")
        pMesh :=  NumPut(A_Index, NumPut(A_Index - 1, pMesh+0, "Int"), "Int")
        V ? (Y += yOFF) : (X += xOFF)
    }

    hBM := DllCall("Gdi32.dll\CreateBitmap", "Int", 1, "Int", 1, "Int", 0x1, "Int", 32, "Ptr*", 0, "Ptr")
    hBM := DllCall("User32.dll\CopyImage", "Ptr", hBM, "Int", 0x0, "Int", W, "Int", H, "Int", 0x8, "Ptr")
    mDC := DllCall("Gdi32.dll\CreateCompatibleDC", "Ptr", 0, "Ptr")
    DllCall("Gdi32.dll\SaveDC", "Ptr", mDC)
    DllCall("Gdi32.dll\SelectObject", "Ptr", mDC, "Ptr", hBM)
    DllCall("Msimg32.dll\GradientFill", "Ptr", mDC, "Ptr", &VERT, "Int", C, "Ptr", &MESH, "Int", C - 1, "Int", !!V)
    DllCall("Gdi32.dll\RestoreDC", "Ptr", mDC, "Int", -1)
    DllCall("Gdi32.dll\DeleteDC", "Ptr", mDC)

    Return hBM
}

DPIScale(x) {
    Return (x * A_ScreenDPI) // 96
}

Gradient(Width, Height,Color) {
    Return CreateGradient(DPIScale(Width), DPIScale(Height), 1,objlength(color)?Color: [0x3FBBE3, 0x008EBC])
}

https://wwt.lanzoul.com/b07ntrbxg 密码:8181

给TA捐赠
共{{data.count}}人
人已捐赠
其他

好物推荐 第4版 2022.05.29

2022-5-29 11:49:22

其他

在PotPlayer字幕悬停显示内容

2022-6-4 21:49:13

2 条回复 A文章作者 M管理员
  1. AHK中文社区

    就这几个单词还不直接汉化一下

    • 蜜獾哥

      菜单和提示我故意用英文的,中文搞不好就乱码,这几个字面意思应该难不到朝圣者

个人中心
购物车
优惠劵
有新私信 私信列表
搜索