윈도우(Windows)에서 가상 키보드 입력, 기술적 난관과 해결 과정
AutoPTT 4.0.0은 FakerInput을 활용하여 가상 키보드 입력을 지원하며, 게임 및 앱과의 호환성을 높임
SendInput 방식의 문제점을 해결하기 위해 Low Level Hook 및 Raw Input을 활용, 입력 감지 우회 시도
FakerInput 장치 식별 및 제어를 위해 CreateFile, DeviceIoControl, WriteFile 등 윈도우 API 사용
Raw Input과 Low Level Hook 간의 상호 작용 문제 해결을 위해 Shared Memory Ringbuffer 기반의 IPC 구현
SendInput의 한계와 FakerInput 도입
AutoPTT는 초기 입력 시뮬레이션을 위해 SendInput을 사용했지만, 이는 Low Level Hook 또는 Raw Input Hook에 의해 쉽게 감지되어 무시될 수 있었다. 이러한 문제를 해결하기 위해 FakerInput 드라이버를 도입하여 가상 키보드 장치를 생성, 게임 및 앱과의 호환성을 확보했다. 특히, FakerInput은 물리적 장치 없이 소프트웨어적으로 키보드 입력을 시뮬레이션할 수 있다는 장점을 가진다.
Raw Input과 Low Level Hook의 상호 작용 문제
AutoPTT는 Raw Input과 Low Level Hook을 함께 사용하여 가상 키보드 입력을 처리하려 했지만, 두 기술 간의 상호 작용 문제에 직면했다. 특히, Raw Input을 활성화하면 Low Level Hook이 제대로 작동하지 않는 문제가 발생했다. 해결책으로, Raw Input 처리를 별도의 프로세스로 분리하고, Shared Memory Ringbuffer 기반의 IPC(Inter-Process Communication)를 통해 데이터를 주고받는 방식을 채택했다.
FakerInput 장치 식별 및 제어
FakerInput 장치를 식별하고 제어하기 위해, AutoPTT는 윈도우 API인 CreateFile, SetupDiEnumDeviceInterfaces, SetupDiGetDeviceInterfaceDetail, HidD_GetAttributes, HidP_GetCaps 등을 활용했다. 특히, CreateFile을 사용하여 FakerInput 장치에 연결하고, WriteFile을 통해 키보드 입력을 시뮬레이션하는 명령을 전송했다. 또한, DeviceIoControl을 사용하여 장치 정보를 획득했다.
Shared Memory Ringbuffer 기반 IPC 구현
AutoPTT는 Raw Input 처리를 위한 별도의 프로세스와 메인 프로세스 간의 통신을 위해 Shared Memory Ringbuffer를 사용한 IPC(Inter-Process Communication)를 구현했다. 이는 ZeroMQ의 TCP 소켓 기반 전송 방식의 성능 문제를 해결하기 위한 대안으로, Lock-free 방식으로 설계되어 높은 성능을 제공한다. 또한, Named Event Object를 사용하여 데이터 전송 시점을 동기화했다.
입력 이벤트 순서 문제와 해결
가상 키보드 입력과 물리적 키보드 입력 간의 이벤트 순서가 일관되지 않아, AutoPTT는 Voice Activity 및 Tap 모드에서 PTT 키가 계속 활성화되는 문제를 겪었다. 해결책으로, Low Level Hook에서 현재 Raw Input 키 상태를 확인하여, 가상 키보드 입력 이벤트를 차단하는 방식을 사용했다. 즉, is_part_of_active_ptt_key 함수를 통해 물리적 키보드의 상태를 확인하여, 가상 키보드 입력을 제어했다.