🚀 오늘의 작업 요약
- 전역 감지: Windows Low-Level Hook을 이용해 백그라운드에서도 키보드/마우스 입력을 감지.
- 스레드 안전성: OS 스레드와 Unity 메인 스레드 간의 충돌 방지를 위한 이벤트 큐 시스템 구축.
- 상호작용: 글로벌 핫키(Ctrl+Shift+H) 및 햄초 스택 자동 증가 로직 연동.
햄초 위젯의 핵심 기믹은 사용자가 열심히 일(타이핑/클릭)하는 만큼 스택이 쌓이는 것이다. 이를 위해 앱이 비활성 상태일 때도 입력을 감지할 수 있는 Global Input Hook 시스템을 구현했다.
🛠 구현 상세
오늘은 Unity의 샌드박스를 벗어나 Windows 운영체제 레벨의 이벤트를 다루는 작업을 진행했다.
1. Global Input Hook 시스템 (GlobalInputHook.cs)
User32.dll의 SetWindowsHookEx를 사용하여 WH_KEYBOARD_LL(13과 WH_MOUSE_LL(14) 훅을 설치했다.
- 구현 내용:
- 백그라운드 감지: 앱이 포커스를 잃어도 OS 차원에서 넘어오는 입력 메시지를 가로챈다.
- 입력 필터링: 키를 꾹 누르고 있을 때 발생하는 반복 입력(Repeat)을 HashSet으로 필터링하여 스택이 비정상적으로 쌓이는 것을 방지했다.
- 이벤트 큐(Event Queue): 훅 프로시저에서 들어온 데이터를 즉시 처리하지 않고 큐에 담은 뒤, Unity의 Update()에서 소비하는 구조로 설계했다.
2. 기능 연동 및 핫키
감지된 입력을 실제 게임 로직과 연결했다.
- 햄초 스택: 유효한 키 입력이나 클릭 발생 시 HamchoWidget.AddStack()을 호출하여 애니메이션 트리거 조건을 채운다.
- 글로벌 핫키: Ctrl + Shift + H 조합을 감지하여, 어떤 작업을 하던 중이라도 위젯을 즉시 켜고 끌 수 있게 만들었다.
🔥 트러블슈팅: 스레드, 메모리, 그리고 셧다운
Windows API를 직접 다루다 보니 예상치 못한 크래시와 씨름해야 했다.
1. Unity API Thread Violation
문제 상황: 훅 프로시저(콜백) 내에서 Debug.Log나 HamchoWidget 함수를 호출하자마자 Unity가 강제 종료(Crash)되었다.
원인: Windows Hook 콜백은 OS가 관리하는 별도의 스레드(혹은 인터럽트 컨텍스트)에서 실행되는데, Unity API는 오직 메인 스레드에서만 접근 가능하다.
해결: '생산자-소비자 패턴'을 적용했다.
// 1. Hook 스레드 (OS): 데이터만 큐에 넣고 즉시 리턴
private static IntPtr HookCallback(...) {
inputQueue.Enqueue(new InputEvent(...));
return CallNextHookEx(...);
}
// 2. Unity 메인 스레드: 쌓인 데이터를 안전하게 처리
void Update() {
while (inputQueue.TryDequeue(out var data)) {
ProcessInput(data); // 여기서 Unity API 호출
}
}
2. "CallbackOnCollectedDelegate" 오류
문제 상황: 실행 후 몇 초 뒤 혹은 GC가 돌 때마다 ExecutionEngineException이 발생하며 셧다운 되었다.
원인: C#의 델리게이트(Delegate)를 네이티브 API(SetWindowsHookEx)에 넘겨주었는데, C# 가비지 컬렉터가 "이거 안 쓰는 변수네?" 하고 치워버려서 발생한 문제다. 네이티브 쪽에서는 이미 사라진 메모 주소를 호출하려 하니 터지는 것.
해결: 델리게이트를 클래스 멤버 변수(static)로 선언하여 GC가 수거해가지 못하도록 참조를 유지했다.
// GC 방지용 정적 참조 유지
private static LowLevelKeyboardProc _keyboardProc;
void Start() {
_keyboardProc = HookCallback; // 참조 저장
SetWindowsHookEx(..., _keyboardProc, ...);
}
3. 앱 종료 후 마우스 먹통 현상
문제 상황: 에디터에서 플레이를 중지했는데 마우스가 움직이지 않았다.
원인: UnhookWindowsHookEx를 호출하지 않고 앱이 꺼지면, OS는 여전히 죽어버린 훅 체인을 통과하려고 시도하다가 타임아웃이 걸린다.
해결: OnDestroy뿐만 아니라 OnApplicationQuit에서도 이중으로 체크하여 반드시 훅을 해제하도록 안전장치를 걸었다.
🔮 다음 계획
기반 시스템은 거의 완성되었다. 가장 걱정되는 점프 차례다.
- 스택 소모하여 점프 구현
'도토리도굴단 > Project: HoP 개발일지' 카테고리의 다른 글
| [🖥️Project: HoP] #5 무한 점프 시스템 (0) | 2025.12.13 |
|---|---|
| [🖥️Project: HoP] #3 애니메이션 시스템과 O(1) 최적화 (0) | 2025.12.08 |
| [🖥️Project: HoP] #2 위치 저장과 멀티 모니터 (0) | 2025.12.08 |
| [🖥️Project: HoP] #1 투명 윈도우와 위젯 시스템 구축 (0) | 2025.12.04 |
| [👾Project: PokeIdle] #1 투명 창 만들기 (0) | 2025.08.19 |