LightWeight HotKey 는 윈도우용 단축키 프로그램입니다.

AutoHotKey 보다는 단순한 기능만을 제공하지만, GUI를 통해 간단하게 설정할 수 있습니다.

App 제작 동기

AutoHotKey 를 사용하여 여러가지 단축키를 등록하여 사용하였으나, 새 단축키 등록이나 기능 변경시 매번 스크립트를 작성해야하는 번거로움이 있어서 제작하게 되었습니다.

스크립트 작성 후 Ahk2Exe 를 이용하여 Binary로 제작 후에는, Anti-Virus 프로그램에서 오탐을 하는 경우도 있었습니다.

지원 기능

  • 창 활성화
    • 창 찾기 조건: WindowTitle, ClassName, ProcessName 지원
    • 찾기 조건: 문자열 및 Regular Expression 지원
      • 창 찾기 툴은 WinSpy 를 권장합니다.
  • 앱 실행 (무결성 수준 선택 가능: 현재 상속, 높은 권한, 보통, 낮음)
  • 창 크기 변경 및 이동
  • 마우스 이동 (대상 창 기준으로 가능)
  • 키보드 마우스 입력
  • 이미지 매핑을 통한 마우스 이동
    • 단, 아래 조건을 충족해야 함
      • (스크린과 이미지의) DPI 가 같아야 함
      • (스크린과 이미지의) 유사도가 90% 이상이어야 함
    • OpenCV 첫 로드시에 지연이 발생할 수 있음
  • 텍스트 입력 (클립보드 사용, 장문 가능)
  • ChainRule 지원(다른 규칙을 연결해서 사용 가능)
  • DPI 조건: 화면 배율 조건 지원
  • (다른 프로세스의) CListCtrl(SysListView32) 아이템 복사
    • 단, 260자를 초과하는 아이템 복사 불가능
    • Owner Data 를 사용하는 경우 복사 불가능
  • Windows의 TrayIcon(Shell_TrayWnd)의 아이콘 클릭/더블클릭, 마우스 이동 지원
    • 현재는 숨겨진 아이콘은 지원하지 않음
    • Click, Double Click 이 동작하지 않는 경우, Emulate Click, Emulate Double Click 기능으로 대체 가능

AutoHotKey와의 장단점 비교

  LightWeight HotKey AutoHotKey
설정 난이도 보통 어려움 (스크립트 작성)
다양한 기능 지원 X (일부 단축키 기능만 지원) O
GUI O X
정규표현식 지원 O O
실행 대상 Integrity Level 지정 O X
Anti-Virus 탐지 X (안전) O
윈도우 시작 시 스케쥴 등록 O X
구동 방식 Hook Hook
DLL Injection X X

지원 연산자

이름 설명
RCT_Always항상 실행
RCT_ActiveWindow_FullScreen현재 창이 FullScreen
RCT_ActiveWindow_TitleMatch(찾을 창의) 제목 일치
RCT_ActiveWindow_TitleBegin(찾을 창의) 제목 시작
RCT_ActiveWindow_TitleEnd(찾을 창의) 제목 종료
RCT_ActiveWindow_TitleContains(찾을 창의) 제목 포함
RCT_ActiveWindow_TitleRegexMatch(찾을 창의) 제목 정규표현식
RCT_ActiveWindow_ClassNameMatch(찾을 창의) 클래스 이름 일치
RCT_ActiveWindow_ClassNameBegin(찾을 창의) 클래스 이름 시작
RCT_ActiveWindow_ClassNameEnd(찾을 창의) 클래스 이름 종료
RCT_ActiveWindow_ClassNameContains(찾을 창의) 클래스 이름 포함
RCT_ActiveWindow_ClassNameRegexMatch(찾을 창의) 클래스 이름 정규표현식
RCT_ActiveWindow_ProcessNameMatch(찾을 창의) 프로세스 이름 일치
RCT_ActiveWindow_ProcessNameBegin(찾을 창의) 프로세스 이름 시작
RCT_ActiveWindow_ProcessNameEnd(찾을 창의) 프로세스 이름 종료
RCT_ActiveWindow_ProcessNameContains(찾을 창의) 프로세스 이름 포함
RCT_ActiveWindow_ProcessNameRegexMatch(찾을 창의) 프로세스 이름 정규표현식
RCT_ActiveWindow_ProcessPathMatch(찾을 창의) 프로세스 경로 일치
RCT_MouseCursorChildWindow_TitleMatch(찾을 창의) 제목 일치
RCT_MouseCursorChildWindow_TitleBegin(찾을 창의) 제목 시작
RCT_MouseCursorChildWindow_TitleEnd(찾을 창의) 제목 종료
RCT_MouseCursorChildWindow_TitleContains(찾을 창의) 제목 포함
RCT_MouseCursorChildWindow_TitleRegexMatch(찾을 창의) 제목 정규표현식
RCT_MouseCursorChildWindow_ClassNameMatch(찾을 창의) 클래스 이름 일치
RCT_MouseCursorChildWindow_ClassNameBegin(찾을 창의) 클래스 이름 시작
RCT_MouseCursorChildWindow_ClassNameEnd(찾을 창의) 클래스 이름 종료
RCT_MouseCursorChildWindow_ClassNameContains(찾을 창의) 클래스 이름 포함
RCT_MouseCursorChildWindow_ClassNameRegexMatch(찾을 창의) 클래스 이름 정규표현식
RCT_MouseCursorChildWindow_ProcessNameMatch(찾을 창의) 프로세스 이름 일치
RCT_MouseCursorChildWindow_ProcessNameBegin(찾을 창의) 프로세스 이름 시작
RCT_MouseCursorChildWindow_ProcessNameEnd(찾을 창의) 프로세스 이름 종료
RCT_MouseCursorChildWindow_ProcessNameContains(찾을 창의) 프로세스 이름 포함
RCT_MouseCursorChildWindow_ProcessNameRegexMatch(찾을 창의) 프로세스 이름 정규표현식
RCT_MouseCursorChildWindow_ProcessPathMatch(찾을 창의) 프로세스 경로 일치
RCT_FindWindow_TitleMatch(찾을 창의) 제목 일치
RCT_FindWindow_TitleBegin(찾을 창의) 제목 시작
RCT_FindWindow_TitleEnd(찾을 창의) 제목 종료
RCT_FindWindow_TitleContains(찾을 창의) 제목 포함
RCT_FindWindow_TitleRegexMatch(찾을 창의) 제목 정규표현식
RCT_FindWindow_ClassNameMatch(찾을 창의) 클래스 이름 일치
RCT_FindWindow_ClassNameBegin(찾을 창의) 클래스 이름 시작
RCT_FindWindow_ClassNameEnd(찾을 창의) 클래스 이름 종료
RCT_FindWindow_ClassNameContains(찾을 창의) 클래스 이름 포함
RCT_FindWindow_ClassNameRegexMatch(찾을 창의) 클래스 이름 정규표현식
RCT_FindWindow_ProcessNameMatch(찾을 창의) 프로세스 이름 일치
RCT_FindWindow_ProcessNameBegin(찾을 창의) 프로세스 이름 시작
RCT_FindWindow_ProcessNameEnd(찾을 창의) 프로세스 이름 종료
RCT_FindWindow_ProcessNameContains(찾을 창의) 프로세스 이름 포함
RCT_FindWindow_ProcessNameRegexMatch(찾을 창의) 프로세스 이름 정규표현식
RCT_FindWindow_ProcessPathMatch(찾을 창의) 프로세스 경로 일치
RCT_Global_FindWindow_TitleMatch(찾을 창의) 제목 일치
RCT_Global_FindWindow_TitleBegin(찾을 창의) 제목 시작
RCT_Global_FindWindow_TitleEnd(찾을 창의) 제목 종료
RCT_Global_FindWindow_TitleContains(찾을 창의) 제목 포함
RCT_Global_FindWindow_TitleRegexMatch(찾을 창의) 제목 정규표현식
RCT_Global_FindWindow_ClassNameMatch(찾을 창의) 클래스 이름 일치
RCT_Global_FindWindow_ClassNameBegin(찾을 창의) 클래스 이름 시작
RCT_Global_FindWindow_ClassNameEnd(찾을 창의) 클래스 이름 종료
RCT_Global_FindWindow_ClassNameContains(찾을 창의) 클래스 이름 포함
RCT_Global_FindWindow_ClassNameRegexMatch(찾을 창의) 클래스 이름 정규표현식
RCT_Global_FindWindow_ProcessNameMatch(찾을 창의) 프로세스 이름 일치
RCT_Global_FindWindow_ProcessNameBegin(찾을 창의) 프로세스 이름 시작
RCT_Global_FindWindow_ProcessNameEnd(찾을 창의) 프로세스 이름 종료
RCT_Global_FindWindow_ProcessNameContains(찾을 창의) 프로세스 이름 포함
RCT_Global_FindWindow_ProcessNameRegexMatch(찾을 창의) 프로세스 이름 정규표현식
RCT_Global_FindWindow_ProcessPathMatch(찾을 창의) 프로세스 경로 일치
RCT_IME_EnglishIME 상태가 영문인 경우 (Negative 옵션으로, 영문이 아닌 경우도 가능)
RCT_TrayIconProcessNameMatchForWin10OrLower(윈 10 전용) TrayIcon 프로세스 찾기
RCT_TrayIconTitleMatch(윈 11 전용) TrayIcon 텍스트 찾기
RCT_TrayIconTitleRegexMatch(윈 11 전용) TrayIcon 텍스트 찾기
RCT_Desktop_ImageMatch바탕화면과 Image와 비교하기
RCT_ActiveWindow_ImageMatch현재 활성 윈도우를 Image와 비교하기
RCT_IsScale_100_Percent_Ratio_96DPI is 100% (Ratio: 96)
RCT_IsScale_125_Percent_Ratio_120DPI is 125% (Ratio: 120)
RCT_IsScale_150_Percent_Ratio_144DPI is 150% (Ratio: 144)
RCT_IsScale_175_Percent_Ratio_168DPI is 175% (Ratio: 168)
RCT_IsScale_200_Percent_Ratio_192DPI is 200% (Ratio: 192)

지원 기능

이름 설명
RET_Activate창 활상화 하기
RET_Activate_Next_Window창 활상화 하기 (그냥 Z-Order 상 다음 윈도우)
RET_Activate_Last_Window창 활상화 하기 (그냥 Z-Order 상 이전 윈도우)
RET_Activate_Same_ProcessName_Next_Window창 활상화 하기 (같은 프로세스의 윈도우 다음 창)
RET_Activate_Same_ProcessName_Last_Window창 활상화 하기 (같은 프로세스의 윈도우 마지막 창, 다음 창 하면 Z-Order 가 꼬여서 2번했을 때 서로 번갈아서 활성화 되기 때문에 이것도 추가함)
RET_Activate_Same_ProcessPath_Next_Window창 활상화 하기 (같은경로 프로세스의 윈도우 다음 창)
RET_Activate_Same_ProcessPath_Last_Window창 활상화 하기 (같은경로 프로세스의 윈도우 마지막 창, 다음 창 하면 Z-Order 가 꼬여서 2번했을 때 서로 번갈아서 활성화 되기 때문에 이것도 추가함)
RET_Activate_Or_Same_ProcessName_Next_Window(활성화 되지 않았음) 창 활상화 하기 | 아니면 이전/다음 창 (같은 프로세스의 윈도우 다음 창)
RET_Activate_Or_Same_ProcessName_Last_Window(활성화 되지 않았음) 창 활상화 하기 | 아니면 이전/다음 창 (같은 프로세스의 윈도우 마지막 창, 다음 창 하면 Z-Order 가 꼬여서 2번했을 때 서로 번갈아서 활성화 되기 때문에 이것도 추가함)
RET_Activate_Or_Same_ProcessPath_Next_Window(활성화 되지 않았음) 창 활상화 하기 | 아니면 이전/다음 창 (같은경로 프로세스의 윈도우 다음 창)
RET_Activate_Or_Same_ProcessPath_Last_Window(활성화 되지 않았음) 창 활상화 하기 | 아니면 이전/다음 창 (같은경로 프로세스의 윈도우 마지막 창, 다음 창 하면 Z-Order 가 꼬여서 2번했을 때 서로 번갈아서 활성화 되기 때문에 이것도 추가함)
RET_Activate_All_Same_ProcessName_Window_Tile창 활상화 하기 (같은 프로세스의 모든 윈도우 가로 바둑판식)
RET_Activate_All_Same_Class_Window_Tile창 활상화 하기 (같은 클래스의 모든 윈도우 가로 바둑판식)
RET_Activate_All_Same_ProcessId_Class_Window_Tile창 활상화 하기 (같은 프로세스 클래스의 모든 윈도우 가로 바둑판식)
RET_Show_All_Same_ProcessName창 보이기 (같은 프로세스 이름)
RET_Show_All_Same_Class창 보이기 (같은 클래스)
RET_Show_All_Same_ProcessId창 보이기 (같은 프로세스)
RET_ExecuteApp앱 실행하기
RET_ExecuteApp_HighIntegrity앱 실행하기 (High Integrity Level)
RET_ExecuteApp_MediumIntegrity앱 실행하기 (Normal Integrity Level)
RET_ExecuteApp_LowIntegrity앱 실행하기 (Low Integrity Level)
RET_Size_Fixed창 크기 변경 (지정)
RET_Size_Percent창 크기 변경 (지정)
RET_SizeUp창 크기 변경 (키우기)
RET_SizeDown창 크기 변경 (줄이기)
RET_Move창 이동 (지정)
RET_MoveTo창 이동 (지정 만큼 이동)
RET_MoveToCurrentMonitor_Left창 이동 (현재 모니터 왼쪽)
RET_MoveToCurrentMonitor_Right창 이동 (현재 모니터 오른쪽 위)
RET_MoveToCurrentMonitor_Top창 이동 (현재 모니터 왼쪽)
RET_MoveToCurrentMonitor_Bottom창 이동 (현재 모니터 왼쪽)
RET_MoveToCurrentMonitor_LeftTop창 이동 (현재 모니터 왼쪽 위)
RET_MoveToCurrentMonitor_LeftBottom창 이동 (현재 모니터 왼쪽 아래)
RET_MoveToCurrentMonitor_RightTop창 이동 (현재 모니터 오른쪽 위)
RET_MoveToCurrentMonitor_RightBottom창 이동 (현재 모니터 오른쪽 아래)
RET_MoveToCurrentMonitor_Center창 이동 (현재 모니터 중앙)
RET_MoveToCurrentMonitor_Horizontal_Center창 이동 (현재 모니터 가로 중앙)
RET_MoveToCurrentMonitor_Vertical_Center창 이동 (현재 모니터 세로 중앙)
RET_MoveToCurrentMonitor_Left_Percent창 이동 (현재 모니터 위에서 Percent)
RET_MoveToCurrentMonitor_Top_Percent창 이동 (현재 모니터 왼쪽에서 Percent)
RET_MoveToCurrentMonitor_Right_Percent창 이동 (현재 모니터 오른쪽에서 Percent)
RET_MoveToCurrentMonitor_Bottom_Percent창 이동 (현재 모니터 아래에서 Percent)
RET_MoveToCurrentMonitor_LeftTop_Percent창 이동 (현재 모니터 LeftTop 에서 Percent)
RET_MoveToCurrentMonitor_LeftBottom_Percent창 이동 (현재 모니터 LeftBottom 에서 Percent)
RET_MoveToCurrentMonitor_RightTop_Percent창 이동 (현재 모니터 RightTop 에서 Percent)
RET_MoveToCurrentMonitor_RightBottom_Percent창 이동 (현재 모니터 RightBottom 에서 Percent)
RET_Window_Maximize창 최대화
RET_Window_Minimize창 최소화
RET_Window_Restore(창 최대화, 최소화 상태에서...) 복원
RET_Window_Restore_And_Minimize창 최소화
RET_Sleep실행 지연 (1/1000 초 milliseconds)
RET_KeyInput_ReplaceAndRollback키 변경하여 실행 (기존 Modifier 상태에: 취소 -> 입력 -> 복원)
RET_KeyInput_AppendAndRollback키 변경하여 실행 (기존 Modifier 상태에: 덮덮 -> 복원)
RET_KeyDown키 누름
RET_KeyUp키 뗌
RET_KeyInput_CapsLock_On캡스락 끄기
RET_KeyInput_CapsLock_Off캡스락 끄기
RET_TextInput텍스트 입력하기 (keybd_event)
RET_TextInput_UsingClipBoard텍스트 입력하기 (ClipBoard 로 복붙하기)
RET_MouseMove_Absolute마우스 이동 (지정)
RET_MouseMove_Relative마우스 이동 (상대)
RET_MouseMove_FromTarget_TopLeft마우스 이동 (From Target)
RET_MouseMove_FromTarget_TopRight마우스 이동 (From Target)
RET_MouseMove_FromTarget_BottomLeft마우스 이동 (From Target)
RET_MouseMove_FromTarget_BottomRight마우스 이동 (From Target)
RET_MouseMove_FromTarget_Center마우스 이동 (From Target)
RET_MouseMove_PrevMonitor_Center마우스 이동 (이전 모니터)
RET_MouseMove_NextMonitor_Center마우스 이동 (다음 모니터)
RET_MouseMove_From_Desktop_ImageMatch_TopLeft마우스 이동 (Desktop 이미지 매칭)
RET_MouseMove_From_Desktop_ImageMatch_TopRight마우스 이동 (Desktop 이미지 매칭)
RET_MouseMove_From_Desktop_ImageMatch_BottomLeft마우스 이동 (Desktop 이미지 매칭)
RET_MouseMove_From_Desktop_ImageMatch_BottomRight마우스 이동 (Desktop 이미지 매칭)
RET_MouseMove_From_ActiveWindow_ImageMatch_TopLeft마우스 이동 (ActiveWindow 이미지 매칭)
RET_MouseMove_From_ActiveWindow_ImageMatch_TopRight마우스 이동 (ActiveWindow 이미지 매칭)
RET_MouseMove_From_ActiveWindow_ImageMatch_BottomLeft마우스 이동 (ActiveWindow 이미지 매칭)
RET_MouseMove_From_ActiveWindow_ImageMatch_BottomRight마우스 이동 (ActiveWindow 이미지 매칭)
RET_MouseClick마우스 입력
RET_MouseDoubleClick마우스 입력
RET_MousePositionSave_ExecutionContext마우스 좌표 저장 - 이번 실행 컨텍스트에 한함
RET_MousePositionLoad_ExecutionContext마우스 좌표 로드 - 이번 실행 컨텍스트에 한함
RET_MatchTrayIcon_ClickRCT_TrayIconProcessNameMatch 에서 매칭된 TrayIcon 클릭!
RET_MatchTrayIcon_DoubleClickRCT_TrayIconProcessNameMatch 에서 매칭된 TrayIcon 더블클릭!
RET_MatchTrayIcon_EmulateClickRCT_TrayIconProcessNameMatch 에서 매칭된 TrayIcon 클릭!
RET_MatchTrayIcon_EmulateDoubleClickRCT_TrayIconProcessNameMatch 에서 매칭된 TrayIcon 더블클릭!
RET_MatchTrayIcon_MouseMove_FromTarget_TopLeftRCT_TrayIconProcessNameMatch 에서 매칭된 TrayIcon 위치 기준으로 이동
RET_MatchTrayIcon_MouseMove_FromTarget_CenterRCT_TrayIconProcessNameMatch 에서 매칭된 TrayIcon 위치 기준으로 이동
RET_CopyCurrentMousePointerSelItem_SysListView현재 마우스 포인터 SysListView32의 선택된 아이템 복사
RET_CopyCurrentMousePointerAllItem_SysListView현재 마우스 포인터 SysListView32의 모든 아이템 복사
RET_CopyCurrentMousePointerCursorItemText_SysListView현재 마우스 포인터 SysListView32의 모든 아이템 복사
RET_Reset_Keyboard_Modifier_ContextContext 초기화 (이상 동작할때 사용)
RET_Pause_LightWeightHotKeyLWHK 비활성화
RET_ChainRule_With_CheckConditionChain Rule (조건 실행)
RET_ChainRule_Skip_Condition_AlwaysExecuteChain Rule (조건 없이 실행)

Demo

  • 아래 영상은 Ctrl + Win + C 를 누르면, SysListView32(=CListCtrl)의 목록을 클립보드에 복사하는 기능입니다.

  • 아래 영상은 Win + S + E 를 누르면, 우측 하단의 "Steam" TrayIcon을 클릭하여 창을 활성화 하는 기능입니다.

  • 아래 영상은 Win + F1 을 누르면, 같은 프로세스의 다른 창이 활성화 되는 기능입니다.

요구 사양

  • Windows 10, 11
  • 64bit (AMD64)
  • Visual C++ Runtime (2015-2022)
  • DirectX 9.0 or above

기반 기술

  • Windows Hook

알려진 문제

  • (Hook API 를 사용하기 때문에) Anti-Virus 에서 자신들의 DLL 을 Injection 하여 감시하는 경우가 다수 있고, 성능 저하가 발생할 수 있습니다.
    • LightWeight HotKey 는 Windows 가 제공하는 Hook Callback에서 (사용자가 입력한 Rule 체크 등의) 단순한 작업만을 진행하기 때문에, 시스템 성능을 저하시킬 이유가 없습니다.
    • 확인된 Anti-Virus 제품
      • ESET
      • COMODO
      *특히 Enterprise용 Anti-Virus 제품에서 의미 없는 강력한 검사를 수행하기 때문에, 다수의 파일을 읽거나, 생성하는 랜섬웨어같은 동작을 하는 Visual Studio, Intellij 등의 IDE 및 Compiler 제품이 느려지는 것과 유사한 케이스라고 볼 수 있습니다.
  • nProtect GameGuard 와 충돌
    • nProtect GameGuard에서 Key Emulation 등의 동작을 차단하기 때문에 비정상 동작할 수 있습니다.
    • 확인된 앱
      • GranSaga

설치 방법

  1. 다운로드 한 파일의 압축 해제
  2. LWHK.exe 실행
  3. (원하는) 규칙 입력
  4. 윈도우 시작시 자동으로 실행되기를 원하는 경우
    1. Options 진입
    2. Install 실행

문제 해결

  • HighIntegrity Level 의 앱에서 동작하지 않는 경우
    1. (관리자 권한으로) LWHK.exe 실행
  • 앱이 느려지거나, (처음 사용시 보다)윈도우에서 성능이 저하되는 경우
    • 앱을 재시작하여 Anti-Virus 가 주입한 DLL 을 초기화 합니다.
      • Anti-Virus 가 다시 DLL을 주입하기 때문에, 시간이 경과되면 또 느려질 수 있습니다.
    • 또는, Anti-Virus 에서 Shell Code Injection 등의 감시에서 LWHK.exe 프로세스를 제외합니다.
  • 삭제
    1. Options 진입
    2. Uninstall 실행