Obsidian/Recognition/Tools/Autohotkey/한영 마우스 툴팁.md

352 lines
8.6 KiB
Markdown

```ahk
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases
; Official repo:
; https://github.com/selfiens/KorTooltip
; References:
; IME state reader: https://iamaman.tistory.com/1805
; Persistent tooltip https://stackoverflow.com/questions/41598616/toggling-a-persistent-tooltip
; commands https://www.autohotkey.com/docs/commands/
; hotkeys https://www.autohotkey.com/docs/Hotkeys.
; # win
; ! alt
; ^ ctrl
; + shift
; ----------------------------------------------------------------
; Initializer >>>
isActive := True
lastX := 0
lastY := 0
lastImeState := 99
idlePollingCurrentSkip := 0
toolTipFlashIdx := 0
; preferences
IniRead, colorScheme, KorTooltip.ini, preferences, colorScheme, whiteOnBlack
IniRead, isEngTooltipDisplayed, KorTooltip.ini, preferences, isEngTooltipDisplayed, 0
; labels
IniRead, korTooltipLabel, KorTooltip.ini, labels, korTooltipLabel, KOR
IniRead, engUcaseTooltipLabel, KorTooltip.ini, labels, engUcaseTooltipLabel, ENG
; core
IniRead, idlePollingSkipMax, KorTooltip.ini, internal, idlePollingSkipMax, 15 ; 250ms/16ms = 15
IniRead, toolTipFlashIntervalMs, KorTooltip.ini, internal, toolTipFlashIntervalMs, 500
IniRead, toolTipOffsetX, KorTooltip.ini, internal, toolTipOffsetX, 20
IniRead, toolTipOffsetY, KorTooltip.ini, internal, toolTipOffsetY, -30
if(colorScheme = "whiteOnBlack"){
TooltipColorWhiteOnBlack()
}
else if(colorScheme = "blackOnWhite"){
TooltipColorBlackOnWhite()
}
else if(colorScheme = "whiteOnRed"){
TooltipColorWhiteOnRed()
}
else if(colorScheme = "flash"){
StartToolTipFlash()
}
else { ; default
TooltipColorWhiteOnBlack()
}
InitTrayMenu()
StartWatch()
return
; <<< Initializer
; ----------------------------------------------------------------
; ----------------------------------------------------------------
; toggle tooltip state
#ScrollLock:: ; win + scrolllock
If (isActive = False) {
StartWatch()
} Else {
StopWatch()
}
Return
StartWatch(){
global isActive
isActive := True
SetTimer, WatchCursor, 16 ; 1000ms/60fps =~ 16.7ms
}
StopWatch(){
global isActive
isActive := False
SetTimer, WatchCursor, Off
ToolTip ; removing tooltip
}
InitTrayMenu(){
Menu, Tray, NoStandard ; remove default tray menu entries
Menu, Tray, Add, White, ToolTipColorBlackOnWhite
Menu, Tray, Add, Black, ToolTipColorWhiteOnBlack
Menu, Tray, Add, Red, ToolTipColorWhiteOnRed
Menu, Tray, Add, Flash, StartToolTipFlash
Menu, Tray, Add
Menu, Tray, Add, toggle ENG, ToogleEngTooltip
Menu, Tray, Add
Menu, Tray, Add, Exit, Exit
}
SaveSettings(){
global
; preferences
IniWrite, %isEngTooltipDisplayed%, KorTooltip.ini, preferences, isEngTooltipDisplayed
IniWrite, %colorScheme%, KorTooltip.ini, preferences, colorScheme
; labels
IniWrite, %korTooltipLabel%, KorTooltip.ini, labels, korTooltipLabel
IniWrite, %engUcaseTooltipLabel%, KorTooltip.ini, labels, engUcaseTooltipLabel
; core
IniWrite, %idlePollingSkipMax%, KorTooltip.ini, internal, idlePollingSkipMax
IniWrite, %toolTipFlashIntervalMs%, KorTooltip.ini, internal, toolTipFlashIntervalMs
IniWrite, %toolTipOffsetX%, KorTooltip.ini, internal, toolTipOffsetX
IniWrite, %toolTipOffsetY%, KorTooltip.ini, internal, toolTipOffsetY
}
ToolTipColorBlackOnWhite(){
global colorScheme
colorScheme := "blackOnWhite"
StopToolTipFlash()
ToolTipColor("White","Black") ; background / foreground
}
ToolTipColorWhiteOnBlack(){
global colorScheme
colorScheme := "whiteOnBlack"
StopToolTipFlash()
ToolTipColor("Black","White")
}
ToolTipColorWhiteOnRed(){
global colorScheme
colorScheme := "whiteOnRed"
StopToolTipFlash()
ToolTipColor("Red","White")
}
StartToolTipFlash(){
global colorScheme
colorScheme := "flash"
global toolTipFlashIntervalMs
toolTipFlashIdx = 1
SetTimer, FlashToolTip, %toolTipFlashIntervalMs%
}
StopToolTipFlash(){
toolTipFlashIdx = 0
SetTimer, FlashToolTip, off
}
FlashToolTip(){
global toolTipFlashIdx
if(toolTipFlashIdx = 1){
ToolTipColor("Red","White")
}
if(toolTipFlashIdx = 2){
ToolTipColor("Black","White")
}
; capping
toolTipFlashIdx++
if(toolTipFlashIdx > 2){
toolTipFlashIdx := 1
}
}
ToogleEngTooltip(){
global isEngTooltipDisplayed
isEngTooltipDisplayed := !isEngTooltipDisplayed
SaveSettings()
; hide tooltip here in case IME is not KOR and/or not watching
if(!isEngTooltipDisplayed){
ToolTip
}
}
Exit(){
SaveSettings()
ExitApp
}
; ----------------------------------------------------------------
; main poller
WatchCursor:
MouseGetPos, x, y, winId, controlId
; hide tooltip when cursor is near the upper edge of the underlaying window
if(y < 50){
ToolTip
return
}
; slows down IME state check frequency when the cursor is idle
if (x = lastX and y = lastY and toolTipFlashIdx = 0){
idlePollingCurrentSkip += 1
if(idlePollingCurrentSkip < idlePollingSkipMax) {
return
}
; OutputDebug, idle %idlePollingCurrentSkip%
}
; reset idle polling skip
idlePollingCurrentSkip := 0
imeState := ReadImeState(winId)
; should show ENG label?
if(imeState = 0 and isEngTooltipDisplayed){
lastX := x
lastY := y
lastImeState := imeState
ToolTip, %engUcaseTooltipLabel%, x+toolTipOffsetX, y+toolTipOffsetY
return
}
; is IME=ENG?
if(imeState = 0) {
if(imeState != lastImeState){
ToolTip ; removing tooltip
}
lastImeState := imeState
return
}
if(x = lastX and y = lastY and imeState = lastImeState and toolTipFlashIdx = 0){
return
}
lastX := x
lastY := y
lastImeState := imeState
ToolTip, %korTooltipLabel%, x+20, y-30
return
; ----------------------------------------------------------------
; @returns int 0:inactive 1:active
ReadImeState(hWnd)
{
; WinGet,hWnd,ID,%WinTitle%
Return Send_ImeControl(ImmGetDefaultIMEWnd(hWnd),0x005,"")
}
Send_ImeControl(DefaultIMEWnd, wParam, lParam)
{
DetectSave := A_DetectHiddenWindows
DetectHiddenWindows,ON
SendMessage 0x283, wParam,lParam,,ahk_id %DefaultIMEWnd%
if (DetectSave <> A_DetectHiddenWindows)
DetectHiddenWindows,%DetectSave%
return ErrorLevel
}
ImmGetDefaultIMEWnd(hWnd)
{
return DllCall("imm32\ImmGetDefaultIMEWnd", Uint,hWnd, Uint)
}
; ------------------------------------------------------------------
; ToolTip font & color customizer
; from https://www.autohotkey.com/boards/viewtopic.php?t=4777
ToolTipFont(Options := "", Name := "", hwnd := "") {
static hfont := 0
if (hwnd = "")
hfont := Options="Default" ? 0 : _TTG("Font", Options, Name), _TTHook()
else
DllCall("SendMessage", "ptr", hwnd, "uint", 0x30, "ptr", hfont, "ptr", 0)
}
ToolTipColor(Background := "", Text := "", hwnd := "") {
static bc := "", tc := ""
if (hwnd = "") {
if (Background != "")
bc := Background="Default" ? "" : _TTG("Color", Background)
if (Text != "")
tc := Text="Default" ? "" : _TTG("Color", Text)
_TTHook()
}
else {
VarSetCapacity(empty, 2, 0)
DllCall("UxTheme.dll\SetWindowTheme", "ptr", hwnd, "ptr", 0
, "ptr", (bc != "" && tc != "") ? &empty : 0)
if (bc != "")
DllCall("SendMessage", "ptr", hwnd, "uint", 1043, "ptr", bc, "ptr", 0)
if (tc != "")
DllCall("SendMessage", "ptr", hwnd, "uint", 1044, "ptr", tc, "ptr", 0)
}
}
_TTHook() {
static hook := 0
if !hook
hook := DllCall("SetWindowsHookExW", "int", 4
, "ptr", RegisterCallback("_TTWndProc"), "ptr", 0
, "uint", DllCall("GetCurrentThreadId"), "ptr")
}
_TTWndProc(nCode, _wp, _lp) {
Critical 999
;lParam := NumGet(_lp+0*A_PtrSize)
;wParam := NumGet(_lp+1*A_PtrSize)
uMsg := NumGet(_lp+2*A_PtrSize, "uint")
hwnd := NumGet(_lp+3*A_PtrSize)
if (nCode >= 0 && (uMsg = 1081 || uMsg = 1036)) {
_hack_ = ahk_id %hwnd%
WinGetClass wclass, %_hack_%
if (wclass = "tooltips_class32") {
ToolTipColor(,, hwnd)
ToolTipFont(,, hwnd)
}
}
return DllCall("CallNextHookEx", "ptr", 0, "int", nCode, "ptr", _wp, "ptr", _lp, "ptr")
}
_TTG(Cmd, Arg1, Arg2 := "") {
static htext := 0, hgui := 0
if !htext {
Gui _TTG: Add, Text, +hwndhtext
Gui _TTG: +hwndhgui +0x40000000
}
Gui _TTG: %Cmd%, %Arg1%, %Arg2%
if (Cmd = "Font") {
GuiControl _TTG: Font, %htext%
SendMessage 0x31, 0, 0,, ahk_id %htext%
return ErrorLevel
}
if (Cmd = "Color") {
hdc := DllCall("GetDC", "ptr", htext, "ptr")
SendMessage 0x138, hdc, htext,, ahk_id %hgui%
clr := DllCall("GetBkColor", "ptr", hdc, "uint")
DllCall("ReleaseDC", "ptr", htext, "ptr", hdc)
return clr
}
}
```