4) 가상 키보드 만들기

윈도우즈 폼 응용 프로젝트를 추가한 후에 키보드 이벤트와 마우스 이벤트 처리를 위한 WrapNative 클래스를 추가하세요. 이 부분은 앞에서 설명한 부분이라 별도의 설명은 생략할게요. 아래의 소스 코드를 참고하세요.

[소스 8.11] WrapNative.cs

이번 작업에서는 논리적인 처리외에도 키보드 인터페이스 부분이 있어서 과도한 중복 작업이 존재합니다. 먼저 폼의 자식 컨트롤을 배치하세요.

[그림 8.07] 가상 키보드 폼의 자식 컨트롤 배치
[그림 8.07] 가상 키보드 폼의 자식 컨트롤 배치

다음은 자식 컨트롤에 배치한 컨트롤 형식과 컨트롤 이름입니다. 그림에는 보이지 않지만 좌측 상단에 정보를 표시할 레이블(Label lb_text)을 하나 배치하세요.

 

이제 폼의 코드를 작성합시다. 먼저 현재 쉬프트 키를 눌렀는지 확인할 수 있는 멤버 필드를 선언하세요.

한글 모드인지 확인할 수 있는 멤버 필드를 선언하세요.

자동화 요소의 초점 변경 이벤트 개체를 기억할 멤버를 선언하세요.

현재 초점을 소유한 자동화 요소 개체와 값 패턴의 개체를 기억할 멤버를 선언합니다.

한글 개체를 기억할 멤버도 선업합니다.

폼의 Load 이벤트 핸들러를 추가하세요.

초점 변경 이벤트 핸들러를 생성하여 등록합니다.

 

초점이 바뀌었을 때 AutomationElement 클래스의 정적 멤버인 FocusedElement를 이용하여 초점을 소유한 자동화 요소 개체를 참조합니다.

만약 멤버 필드로 기억하고 있는 타겟 요소와 같으면 이벤트 처리기를 끝냅니다.

만약 초점을 소유한 개체의 프로세스 ID가 현재 프로세스 ID와 같을 때도 이벤트 처리기를 끝냅니다.

자동화 요소 개체가 활성화 상태인지 확인합니다.

활성화 상태이면 Value 패턴인지 확인합니다.

Value 패턴이면 타겟을 설정합니다. 이 부분은 크로스 스레드 문제가 발생할 수 있으므로 별도의 메서드를 만들게요.

Value 패턴이 아니면 타겟 자동화 요소와 타겟 Value 패턴을 null로 설정합니다.

활성화 상태가 아니면 타겟 자동화 요소와 타겟 Value 패턴을 null로 설정합니다.

 

SetTarget 메서드를 정의합시다. 이 부분에서는 크로스 스레드 문제가 발생할 수 있어서 이를 처리하기 위한 대리자를 정의합니다.

수행하고 있는 스레드가 폼을 소유하는 스레드인지 확인합니다.

만약 폼을 소유하는 스레드가 아니면 Invoke 메서드를 호출하여 .NET 프레임워크를 통해 폼을 소유한 스레드가 SetTarget 메서드를 호출할 수 있게 합니다.

전달받은 타겟을 Value 패턴으로 참조 연산합니다.

타겟 자동화 개체도 설정합니다.

새로운 타겟을 설정하였으니 해당 개체에 한글 처리를 위한 한글 개체를 생성합니다.

타겟의 값을 가져와 한글 개체의 Text 속성에 설정합니다.

정보를 표시할 레이블의 Text 속성도 설정합니다.

래핑한 API 정적 클래스 WrapNative의 IsPress 메서드를 호출하여 CapsLock 버튼을 누른 상태인지 얻어와서 cb_cabs의 Checked 속성을 설정합니다.

이에 따라 키보드 UI 부분을 설정합니다. 이 부분은 ButtonSet 메서드로 구현합시다.

이벤트 정보를 표시할 리스트 박스에 항목을 추가합니다.

키보드 버튼 상태에 따라 키보드 UI를 설정하는 ButtonSet 메서드를 정의합시다. 이 부분은 특별한 연산은 없지만 많은 키의 Text 속성을 설정하므로 작업량이 많습니다.

쉬프트 키를 눌렀을 때 버튼의 Text 속성을 설정합시다.

쉬프트 키를 누르지 않을 때의 버튼 Text 속성을 설정합시다.

한글 모드인지 여부에 따라서 키보드 UI를 설정하는 부분도 필요합니다.

한글 모드에서 쉬프트 키를 눌렀을 때의 버튼 Text 속성을 설정하세요.

 

한글 모드에서 쉬프트 키를 누르지 않았을 때의 버튼 Text 속성을 설정하세요.

한글 모드에서 쉬프트 키에 관계없는 버튼의 Text 속성을 설정하세요.

한글 모드가 아닐 때의 처리입니다.

쉬프트 키를 눌렀거나 CapsLock이 눌렀거나 둘 중에 하나가 참일 때의 처리입니다.

쉬프트 키를 누르고 CapsLock도 눌러진 상태이거나 둘 다 누른 상태가 아닐 때의 처리입니다.

 

cb_cabs 체크 박스의 체크 상태 변경 이벤트 핸들러를 등록하세요.

체크 상태에 따라 체크 박스의 배경 색을 다르게 지정하여 쉽게 알 수 있게 합시다.

cb_with_shift 체크 박스의 체크 상태 변경 이벤트 핸들러를 등록하세요.

is_press_shift에 현재 체크 상태로 설정하고 키보드 버튼의 UI 정보를 설정합니다.

폼의 FormClosed 이벤트 핸들러를 등록합니다.

폼 Load할 때 등록했던 초점 변경 이벤트 핸들러를 해제합니다.

모든 버튼의 클릭 이벤트는 Button_Click으로 추가하세요.

 

먼저 어느 버튼인지 sender를 Button 형식으로 참조합니다.

만약 값 패턴 개체인 target이 존재하는지 확인합니다.

target이 존재하면 타겟에 초점을 설정합니다.

내부 처리 속도로 SetFocus를 호출해도 바로 초점을 잡지 않아 약간의 시간을 지연합니다.

이제 버튼에 따라 처리를 합니다.

다음은 래핑한 API 정적 클래스인 WrapNative의 KeyClick 메서드를 호출하여 프로그램 방식으로 키 이벤트를 발생할 키에 관한 처리입니다.

캡션 키를 눌렀을 때는 체크 박스의 체크 상태를 토글합니다.

캡션에 따라 키보드 UI 인터페이스의 내용이 바뀌어야 하므로 ButtonSet 메서드를 호출합니다.

한/영 변환 버튼을 눌렀을 때도 한글 모드를 기억하는 check 멤버를 토클합니다.

그리고 키보드 UI 인터페이스의 내용을 바꾸어야 하므로 ButtonSet 메서드를 호출합니다.

Space 버튼을 누렀을 때는 별도의 메서드를 통해 문자를 누른 것처럼 처리할 PressKey 메서드를 이용하여 처리할게요.

<- 버튼을 눌렀을 때도 PressKey 메서드를 호출합시다.

나머지 키는 버튼의 Text 속성의 첫번째 문자를 인자로 PressKey 메서드를 호출합니다.

키보드 이벤트를 보여줄 리스트 박스에 항목을 추가합니다.

그리고 추가한 항목을 화면에 보일 수 있게 선택 항목으로 설정합니다.

래핑한 API 정적 클래스 WrapNative의 KeyClick 메서드를 이용해 End 키를 누른 이벤트를 발생합니다. 이를 통해 캐럿이 맨 뒤로 이동합니다.

만약 타겟 개체가 없으면 메서드를 종료합니다.

만약 한글 모드이면 hangul 개체의 Input 메서드를 호출합니다.

그렇지 않다면 한글 개체의 InputNoKorea 메서드를 호출합니다.

정보를 표시할 레이블의 Text 속성을 한글의 Text 속성으로 설정합니다.

Value 패턴인 타겟의 SetValue 메서드를 이용하여 한글의 Text 속성으로 설정합니다.

 

[소스 8.12] Form1.cs