2016년 11월 15일 화요일

[macOS] 광역(?) 마우스 및 키보드 이벤트 인식

제목이 약간의 오해가 있을 수도 있어서 좀 더 자세히 적어보자면, 앱 내부의 마우스나 키 입력을 받는게 아니라 앱 윈도우에 포커스가 없는 상태에서 마우스나 키보드 이벤트를 받기 위한 내용이다. 흔히 쓰이는 윈도우의 '키보드 후킹'이라는 표현이 많이 비슷하기도 하다.

OS X 10.6 Snow Leopard 부터 추가된 NSEvent의 addGlobalMonitorForEvents(matching:handler:) 메소드를 이용하면 상당수의 컨트롤러 이벤트를 받는 것이 가능하다.

아래는 마우스 움직임을 핸들링 하기 위한 예제이다.
let eventMonitor = NSEvent.addGlobalMonitorForEvents(
  matching: [.mouseMoved, .keyDown]) {

  (event) in
  print("event: \(event)")
}
위 예제는 NSEvent 클래스를 이용해 글로벌 모니터를 붙여서 마우스 움직임과 키 입력을 감지하는 코드이다.

이 코드에서 matching 에 넘겨지는 값은 굉장히 많이 정의되어 있다. 예를 들자면 키가 떼어질 때의 이벤트 타입인 .keyUp 같은 것 말이다. 필요하다면 NSEventMask 정의를 찾아보자.

사용이 끝나면 NSEvent의 removeMonitor: 메소드를 이용해 핸들러를 제거해 주는 것을 잊지 말자.
NSEvent.removeMonitor(eventHandler)
당연하겠지만, 이 모니터가 앱이 종료될 때 까지 쓰여야 한다면 딱히 제거할 필요는 없을 것이다.

참고로 위의 NSEvent.addGlobalMonitorForEvents(...)를 호출하면 리턴되는 값이 Any 이다. 별도의 타입이 정해져 있지 않은데 미래에는 바뀔 여지가 있을지도 모르겠다. (심지어 이전에는 AnyObject 였는데 Swift 3 로 오면서 Any 로 바뀌었다는 것도 기억하자)

잡설(?)

macOS Sierra 부터인지 아닌지 잘 모르겠지만, 이상하게도 앱 윈도우에 포커스가 가 있으면 오히려 모니터가 동작하지 않는 이상증상을 발견했다. 물론 내 착오일지도 모르겠지만 뭔가 변화가 있었을지도 모르겠다.

하여간 이런 기능은 잘 쓰면 사용자에게 편리함을 줄 수도 있겠지만, 나쁜 의도로 쓰면 무서운 기능이 된다. 다행히도 macOS 에서는 이런 글로벌 이벤트를 받는 것만 가능하지 변경하거나 가로채어서 없애버리는 것은 불가능하다. 그리고 글로벌 이벤트를 핸들링 하는 앱은 Accessibility 를 통해 제어하는 것이 가능하기에 보안 문제도 윈도우에 비해서는 유연하다는 점은 정말 다행이다.

댓글 없음 :