키보드 및 마우스 클래스 드라이버 구성

참고

이 항목은 키보드 및 마우스 클래스 드라이버를 구성하는 개발자를 위한 것입니다. 마우스 또는 키보드를 수정하려는 경우 다음을 참조하세요.

비 HID 키보드와 마우스는 여러 레거시 버스를 통해 연결할 수 있지만 여전히 동일한 클래스 드라이버를 사용합니다. 이 섹션에는 클래스 드라이버 자체에 대한 세부 정보가 포함되어 있습니다. 다음 섹션에서는 컨트롤러에 대해 자세히 설명합니다.

이 항목에서는 Microsoft Windows 2000 이상에서 키보드 및 마우스 디바이스의 일반적인 물리적 구성에 대해 설명합니다.

다음 그림에서는 단일 키보드와 단일 마우스를 사용하는 두 가지 일반적인 구성을 보여 줍니다.

단일 키보드와 단일 마우스를 사용하는 두 가지 구성을 보여 주는 다이어그램

왼쪽 그림은 독립 컨트롤러를 통해 시스템 버스에 연결된 키보드와 마우스를 보여줍니다. 일반적인 구성은 i8042 컨트롤러를 통해 작동하는 PS/2 스타일 키보드와 직렬 포트 컨트롤러를 통해 작동하는 직렬 스타일 마우스로 구성됩니다.

키보드 및 마우스 제조업체에는 다음과 같은 추가 정보가 중요합니다.

  • 키보드는 보안상의 이유로 운영 체제 스택에서 단독 모드로 열립니다.
  • Windows는 둘 이상의 키보드 및 마우스 디바이스의 동시 연결을 지원합니다.
  • Windows는 각 디바이스에 대한 클라이언트의 독립적인 액세스를 지원하지 않습니다.

클래스 드라이버 기능

이 항목에서는 다음 Microsoft Windows 2000 이상 시스템 클래스 드라이버의 기능에 대해 설명합니다.

  • GUID_CLASS_KEYBOARD 디바이스 클래스의 디바이스에 대한 클래스 드라이버인 Kbdclass

  • GUID_CLASS_MOUSE 디바이스 클래스의 디바이스에 대한 클래스 드라이버인 Mouclass

Kbdclass는 Kbdclass 서비스를 구현하고 실행 이미지가 kbdclass.sys.

Mouclass는 Mouclass 서비스를 구현하고 실행 이미지가 mouclass.sys.

Kbdclass 및 Mouclass 각 기능:

  • 디바이스 클래스의 일반 및 하드웨어 독립적 작업입니다.

  • 플러그 앤 플레이, 전원 관리 및 WMI(Windows Management Instrumentation).

  • 레거시 디바이스의 작업입니다.

  • 둘 이상의 디바이스를 동시에 작동합니다.

  • 함수 드라이버가 디바이스의 입력 데이터 버퍼에서 클래스 드라이버의 데이터 버퍼로 데이터를 전송하는 데 사용하는 클래스 서비스 콜백 루틴 의 연결입니다.

디바이스 개체 구성

다음 그림에서는 플러그 앤 플레이 PS/2 스타일 키보드 및 마우스 디바이스에 대한 디바이스 개체의 구성을 보여 줍니다. 각 클래스 드라이버는 선택적 상위 수준 디바이스 필터 DO를 통해 FDO(함수 디바이스 개체)에 연결된 상위 수준 클래스 필터 디바이스 개체(filter DO)를 만듭니다. 상위 수준 디바이스 필터 드라이버는 상위 수준 디바이스 필터 DO를 만듭니다. I8042prt는 DO 함수를 만들고 루트 버스 드라이버에서 만든 PDO(물리적 디바이스 개체)에 연결합니다.

플러그 앤 플레이 ps/2 스타일 키보드 및 마우스 디바이스에 대한 디바이스 개체의 구성을 보여 주는 다이어그램

PS/2 키보드

키보드 드라이버 스택은 다음으로 구성됩니다.

  • Kbdclass, 상위 수준 키보드 클래스 필터 드라이버
  • 하나 이상의 선택적 상위 수준 키보드 필터 드라이버
  • I8042prt, 함수 드라이버

PS/2 마우스

마우스 드라이버 스택은 다음으로 구성됩니다.

  • 상위 수준 마우스 클래스 필터 드라이버인 Mouclass
  • 하나 이상의 선택적 상위 수준 마우스 필터 드라이버
  • I8042prt, 함수 드라이버

KbdclassMouclass 는 두 가지 모드로 둘 이상의 디바이스를 지원할 수 있습니다. 일대일 모드에서는 각 디바이스에 독립적인 디바이스 스택이 있습니다. 클래스 드라이버는 각 디바이스 스택에 독립 클래스 DO를 만들고 연결합니다. 각 디바이스 스택에는 자체 제어 상태 및 입력 버퍼가 있습니다. Microsoft Win32 하위 시스템은 고유한 파일 개체를 통해 각 디바이스의 입력에 액세스합니다.

그랜드마스터 모드에서 클래스 드라이버는 다음과 같은 방식으로 모든 디바이스를 작동합니다.

  • 클래스 드라이버는 모든 디바이스를 나타내는 그랜드마스터 클래스 DO 와 각 디바이스에 대한 하위 클래스 DO 를 모두 만듭니다.

    클래스 드라이버는 각 디바이스 스택에 하위 클래스 DO를 연결합니다. 하위 클래스 DO 아래에서 디바이스 스택은 일대일 모드에서 만든 것과 동일합니다.

  • grandmaster 클래스 DO는 모든 하위 DO의 작업을 제어합니다.

  • Win32 하위 시스템은 grandmaster 클래스 디바이스를 나타내는 파일 개체를 통해 모든 디바이스 입력에 액세스합니다.

  • 모든 디바이스 입력은 그랜드마스터의 데이터 큐에 버퍼링됩니다.

  • 그랜드마스터는 단일 글로벌 디바이스 상태를 유지 관리합니다.

Kbdclass 및 Mouclass는 레지스트리 항목 값 ConnectMultiplePorts가 0x00(클래스 서비스가 Kbdclass 또는 Mouclass인 키 HKLM\Services\CurrentControlSet\<class service>\Parameters 아래)로 설정된 경우 일대일 모드에서 작동합니다. 그렇지 않으면 Kbdclass 및 Mouclass는 그랜드마스터 모드에서 작동합니다.

클래스 드라이버를 통해 열기 및 닫기

Microsoft Win32 하위 시스템은 단독으로 사용하기 위해 모든 키보드 및 마우스 장치를 엽니다. 각 디바이스 클래스에 대해 Win32 하위 시스템은 입력이 단일 입력 디바이스에서 온 것처럼 모든 디바이스의 입력을 처리합니다. 애플리케이션은 하나의 특정 디바이스에서만 입력을 받도록 요청할 수 없습니다.

Win32 하위 시스템은 플러그 앤 플레이 관리자로부터 GUID_CLASS_KEYBOARD 또는 GUID_CLASS_MOUSE 디바이스 인터페이스를 사용하도록 설정되었다는 알림을 받은 후 입력 디바이스에 플러그 앤 플레이 동적으로 열립니다. Win32 하위 시스템은 열린 인터페이스가 비활성화되었다는 알림을 받은 후 플러그 앤 플레이 디바이스를 닫습니다. Win32 하위 시스템은 이름별로 레거시 디바이스도 엽니다(예: "\Device\KeyboardLegacyClass0"). Win32 하위 시스템이 레거시 디바이스를 성공적으로 열면 디바이스가 나중에 물리적으로 제거되었는지 확인할 수 없습니다.

Kbdclass 및 Mouclass가 만들기 요청을 받은 후 플러그 앤 플레이 및 레거시 작업에 대해 다음을 수행합니다.

  • 플러그 앤 플레이 작업

    디바이스가 플러그 앤 플레이 시작 상태이면 클래스 드라이버는 드라이버 스택 아래로 IRP_MJ_CREATE 요청을 보냅니다. 그렇지 않으면 클래스 드라이버가 드라이버 스택 아래로 요청을 보내지 않고 요청을 완료합니다. 클래스 드라이버는 디바이스에 대한 읽기 권한이 있는 신뢰할 수 있는 파일을 설정합니다. grandmaster 디바이스가 있는 경우 클래스 드라이버는 하위 클래스 디바이스와 연결된 모든 포트에 만들기 요청을 보냅니다.

  • 레거시 작업

    클래스 드라이버는 디바이스를 사용하도록 설정하기 위해 포트 드라이버에 내부 디바이스 제어 요청을 보냅니다.

디바이스에 서비스 콜백 연결

클래스 드라이버는 디바이스를 열기 전에 클래스 서비스를 디바이스에 연결해야 합니다. 클래스 드라이버는 클래스 DO를 디바이스 스택에 연결한 후 클래스 서비스를 연결합니다. 함수 드라이버는 클래스 서비스 콜백을 사용하여 디바이스에서 디바이스의 클래스 데이터 큐로 입력 데이터를 전송합니다. 디바이스에 대한 함수 드라이버의 ISR 디스패치 완료 루틴은 클래스 서비스 콜백을 호출합니다. Kbdclass는 클래스 서비스 콜백 KeyboardClassServiceCallback을 제공하고, Mouclass는 클래스 서비스 콜백 MouseClassServiceCallback을 제공합니다.

공급업체는 디바이스에 대한 상위 수준 필터 드라이버를 설치하여 클래스 서비스 콜백의 작업을 수정할 수 있습니다. 샘플 키보드 필터 드라이버 KbfiltrKbFilter_ServiceCallback 콜백을 정의하고 샘플 마우스 필터 드라이버 MoufiltrMouFilter_ServiceCallback 콜백을 정의합니다. 샘플 필터 서비스 콜백은 디바이스의 포트 입력 버퍼에서 클래스 데이터 큐로 전송되는 입력 데이터를 수정하도록 구성할 수 있습니다. 예를 들어 필터 서비스 콜백은 데이터를 삭제, 변환 또는 삽입할 수 있습니다.

클래스 및 필터 서비스 콜백은 다음과 같은 방식으로 연결됩니다.

  • 클래스 드라이버는 디바이스 스택(IOCTL_INTERNAL_KEYBOARD_CONNECT 또는 IOCTL_INTERNAL_MOUSE_CONNECT)에서 내부 디바이스 연결 요청을 보냅니다. 클래스 연결 데이터는 클래스 디바이스 개체에 대한 포인터와 클래스 서비스 콜백에 대한 포인터를 포함하는 CONNECT_DATA 구조체에 의해 지정됩니다.

  • 필터 드라이버는 연결 요청을 받은 후 클래스 연결 데이터의 복사본을 저장하고 요청의 연결 데이터를 필터 연결 데이터로 바꿉니다. 필터 연결 데이터는 필터 디바이스 개체에 대한 포인터와 필터 드라이버 서비스 콜백에 대한 포인터를 지정합니다. 필터 드라이버는 필터링된 연결 요청을 함수 드라이버에 보냅니다.

클래스 및 필터 서비스 콜백은 다음과 같은 방식으로 호출됩니다.

  • 함수 드라이버는 필터 연결 데이터를 사용하여 필터 서비스 콜백에 대한 초기 콜백을 만듭니다.

  • 입력 데이터를 필터링한 후 필터 서비스 콜백은 저장한 클래스 연결 데이터를 사용하여 클래스 서비스 콜백에 대한 콜백을 만듭니다.

키보드 디바이스 쿼리 및 설정

I8042prt는 키보드 디바이스에 대한 정보를 쿼리하고 키보드 디바이스에서 매개 변수를 설정하는 다음과 같은 내부 디바이스 제어 요청을 지원합니다.

IOCTL_KEYBOARD_QUERY_ATTRIBUTES

IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION

IOCTL_KEYBOARD_QUERY_INDICATORS

IOCTL_KEYBOARD_QUERY_TYPEMATIC

IOCTL_KEYBOARD_SET_INDICATORS

IOCTL_KEYBOARD_SET_TYPEMATIC

모든 키보드 디바이스 제어 요청에 대한 자세한 내용은 휴먼 인터페이스 디바이스 참조를 참조하세요.

키보드에 대한 코드 매퍼 검사

Microsoft Windows 운영 체제에서 입력 디바이스에서 제공하는 PS/2 호환 검사 코드는 Windows 메시지 형식으로 시스템을 통해 전파되는 가상 키로 변환됩니다. 디바이스에서 특정 키에 대한 잘못된 검사 코드를 생성하는 경우 잘못된 가상 키 메시지가 전송됩니다. 이 문제는 펌웨어에서 생성된 검사 코드를 분석하고 잘못된 검사 코드를 시스템에서 이해하는 코드로 수정하는 필터 드라이버를 작성하여 해결할 수 있습니다. 그러나 이는 지루한 프로세스이며 커널 수준 필터 드라이버에 오류가 있는 경우 심각한 문제가 발생할 수 있습니다.

Windows 2000 및 Windows XP에는 스캔 코드 매핑을 허용하는 메서드를 제공하는 새로운 스캔 코드 매퍼가 포함되어 있습니다. Windows용 검사 코드 매핑은 다음 레지스트리 키에 저장됩니다.

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout

참고 컨트롤 키 아래에 키보드 레이아웃 키(복수형)도 있지만 해당 키는 수정해서는 안 됩니다.

키보드 레이아웃 키에서 스캔코드 맵 값을 추가해야 합니다. 이 값은 REG_BINARY 형식(little Endian 형식)이며 다음 표에 지정된 데이터 형식이 있습니다.

시작 오프셋(바이트) 크기(바이트) 데이터
0 4 헤더: 버전 정보
4 4 헤더: 플래그
8 4 헤더: 매핑 수
12 4 개별 매핑
... ... ...
마지막 4바이트 4 Null 종결자(0x00000000)

첫 번째 및 두 번째 DWORDS는 헤더 정보를 저장하고 현재 버전의 스캔 코드 매퍼에 대해 모든 0으로 설정해야 합니다. 세 번째 DWORD 항목에는 null 종료 매핑을 포함하여 다음에 나타나는 총 매핑 수가 포함됩니다. 따라서 최소 개수는 1(지정된 매핑 없음)입니다. 개별 매핑은 헤더를 따릅니다. 각 매핑은 길이가 하나의 DWORD이며 두 개의 WORD 길이 필드로 나뉩니다. 각 WORD 필드는 매핑할 키에 대한 검사 코드를 저장합니다.

맵이 레지스트리에 저장되면 매핑이 적용되려면 시스템을 다시 부팅해야 합니다. 키 프레스에 검사 코드 매핑이 필요한 경우 검사 코드가 가상 키로 변환되기 직전에 사용자 모드에서 단계가 수행됩니다. 사용자 모드에서 이 변환을 수행하면 터미널 서비스에서 실행할 때 매핑이 제대로 작동하지 않는 등의 특정 제한 사항이 있을 수 있습니다.

이러한 매핑을 제거하려면 스캔코드 맵 레지스트리 값을 제거하고 다시 부팅합니다.

예 1

다음은 예제를 제공합니다. 왼쪽 Ctrl 키를 CAPS LOCK 키로 교환하려면 레지스트리 편집기(가급적이면 Regedt32.exe)를 사용하여 스캔코드 맵 키를 다음 값으로 수정합니다.

00000000 00000000 03000000 3A001D00 1D003A00 00000000

다음 표에는 DWORD 필드와 교환된 바이트로 구분된 이러한 항목이 포함되어 있습니다.

: 해석

0x00000000: 헤더: 버전입니다. 모든 0으로 설정합니다.

0x00000000: 헤더: 플래그. 모든 0으로 설정합니다.

0x00000003: 맵에 있는 세 개의 항목(null 항목 포함).

0x001D003A: 왼쪽 CTRL 키 --> CAPS LOCK(0x1D -> 0x3A).

0x003A001D: CAPS LOCK --> 왼쪽 Ctrl 키(0x3A -> 0x1D).

0x00000000: Null 종결자입니다.

예 2

키보드에서 일반 공급되지 않는 키를 추가하거나 사용되지 않는 키를 제거할 수도 있습니다. 다음 예제에서는 오른쪽 CTRL 키를 제거하고 오른쪽 ALT 키의 기능을 변경하여 음소거 키로 작동하도록 스캔코드 맵 에 저장된 값을 보여 주세요.

00000000 00000000 03000000 00001DE0 20E038E0 00000000

다음 표에는 DWORD 필드와 교환된 바이트로 구분된 이러한 항목이 포함되어 있습니다.

: 해석

0x00000000: 헤더: 버전입니다. 모든 0으로 설정합니다.

0x00000000: 헤더: 플래그. 모든 0으로 설정합니다.

0x00000003: 맵에 있는 세 개의 항목(null 항목 포함).

0xE01D0000: 오른쪽 Ctrl 키(0xE01D --> 0x00)를 제거합니다.

0xE038E020: 오른쪽 ALT 키 --> 키 음소거(0xE038 -> 0xE020).

0x00000000: Null 종결자입니다.

필요한 데이터가 생성되면 여러 가지 방법으로 레지스트리에 삽입할 수 있습니다.

  • 레지스트리 편집기를 사용하여 시스템 레지스트리에 쉽게 통합할 수 있는 .reg 파일을 생성할 수 있습니다.
  • 추가할 레지스트리 정보가 포함된 [AddReg] 섹션을 사용하여 .inf 파일을 만들 수도 있습니다.
  • Regedt32.exe 레지스트리에 정보를 수동으로 추가하는 데 사용할 수 있습니다.

스캔 코드 매퍼에는 몇 가지 장점과 단점이 있습니다.

장점은 다음과 같습니다.

  • 매퍼를 사용하여 펌웨어 오류를 쉽게 수정할 수 있습니다.
  • 자주 사용하는 키는 레지스트리에서 맵을 수정하여 키보드에 추가할 수 있습니다. 자주 사용되지 않는 키(예: 오른쪽 Ctrl 키)는 null에 매핑(제거됨)하거나 다른 키로 교환할 수 있습니다.
  • 주요 위치를 쉽게 변경할 수 있습니다. 사용자는 혜택을 위해 자주 사용하는 키의 위치를 쉽게 사용자 지정할 수 있습니다.

다음과 같은 단점이 인식됩니다.

  • 맵이 레지스트리에 저장되면 활성화하려면 시스템 다시 부팅이 필요합니다.
  • 레지스트리에 저장된 매핑은 시스템 수준에서 작동하며 모든 사용자에게 적용됩니다. 이러한 매핑은 현재 사용자에 따라 다르게 작동하도록 설정할 수 없습니다.
  • 현재 구현은 매핑이 시스템에 연결된 모든 키보드에 항상 적용되도록 맵의 기능을 제한합니다. 현재 키보드별로 맵을 만들 수 없습니다.

마우스 디바이스 쿼리

I8042prt는 마우스 디바이스에 대한 정보를 쿼리하는 다음과 같은 내부 디바이스 제어 요청을 지원합니다.

IOCTL_MOUSE_QUERY_ATTRIBUTES

모든 마우스 디바이스 제어 요청에 대한 자세한 내용은 휴먼 인터페이스 디바이스 참조를 참조하세요.

마우스 클래스 드라이버와 연결된 레지스트리 설정

다음은 마우스 클래스 드라이버와 연결된 레지스트리 키 목록입니다.

[키: HKLM\SYSTEM\CurrentControlSet\Services\Mouclass\Parameters]

  • MaximumPortsServiced – Windows XP 이상에서는 사용되지 않습니다. Windows NT4에만 해당합니다.
  • PointerDeviceBaseName – 마우스 클래스 디바이스 드라이버에서 만든 디바이스 개체의 기본 이름을 지정합니다.
  • ConnectMultiplePorts – 각 클래스 디바이스 개체에 대해 하나 이상의 포트 디바이스 개체가 있는지 여부를 결정합니다. 이 항목은 주로 디바이스 드라이버에서 사용됩니다.
  • MouseDataQueueSize - 마우스 드라이버가 버퍼링하는 마우스 이벤트 수를 지정합니다. 또한 페이지가 없는 메모리 풀에서 마우스 드라이버의 내부 버퍼 크기를 계산하는 데도 사용됩니다.

절대 포인팅 디바이스

GUID_CLASS_MOUSE 유형의 디바이스의 경우 디바이스의 함수 드라이버는 다음과 같습니다.

  • 디바이스별 입력을 처리합니다.

  • MouseClassServiceCallback에 필요한 MOUSE_INPUT_DATA 구조를 만듭니다.

  • ISR 디스패치 완료 루틴에서 MouseClassServiceCallback 을 호출하여 MOUSE_INPUT_DATA 구조를 Mouclass 데이터 큐로 전송합니다.

절대 포인팅 디바이스의 경우 디바이스의 함수 드라이버는 다음과 같은 방식으로 MOUSE_INPUT_DATA 구조체의 LastX, LastYFlags 멤버를 설정해야 합니다.

  • 디바이스 입력 값을 디바이스의 최대 기능으로 나누는 것 외에도 드라이버는 디바이스 입력 값을 0xFFFF 크기 조정합니다.

    LastX = ((device input x value) * 0xFFFF ) / (Maximum x capability of the device)
    LastY = ((device input y value) * 0xFFFF ) / (Maximum y capability of the device)
    
  • 드라이버는 Flags에서 MOUSE_MOVE_ABSOLUTE 플래그를 설정합니다.

  • Windows 관리자가 입력을 전체 가상 데스크톱에 매핑해야 하는 경우 드라이버는 플래그에서 MOUSE_VIRTUAL_DESKTOP 플래그를 설정합니다. MOUSE_VIRTUAL_DESKTOP 플래그가 설정되지 않은 경우 Window Manager는 입력을 기본 모니터에만 매핑합니다.

다음은 절대 포인팅 디바이스에 대한 이러한 특수 요구 사항이 구현되는 방법을 디바이스 유형별로 지정합니다.

  • HID 디바이스:

    HID 마우스 디바이스용 Windows 함수 드라이버인 Mouhid는 이러한 특수 요구 사항을 자동으로 구현합니다.

  • PS/2 스타일 디바이스:

    상위 수준 필터 드라이버가 필요합니다. 필터 드라이버는 IsrHook 콜백 및 클래스 서비스 콜백을 제공합니다. I8042prt는 IsrHook를 호출하여 원시 디바이스 입력을 처리하고 필터 클래스 서비스 콜백을 호출하여 입력을 필터링합니다. 필터 클래스 서비스 콜백은 MouseClassServiceCallback을 차례로 호출합니다. IsrHook 콜백과 클래스 서비스 콜백의 조합은 디바이스별 입력을 처리하고, 필요한 MOUSE_INPUT_DATA 구조를 만들고, 디바이스 입력 데이터의 크기를 조정하고, MOUSE_MOVE_ABSOLUTE 플래그를 설정합니다.

  • 플러그 앤 플레이 Serenum으로 열거되는 COM 포트 디바이스:

    플러그 앤 플레이 함수 드라이버가 필요합니다. 함수 드라이버는 필요한 MOUSE_INPUT_DATA 구조를 만들고, 디바이스 입력 데이터의 크기를 조정하고, MouseClassServiceCallback을 호출하기 전에 MOUSE_MOVE_ABSOLUTE 플래그를 설정합니다.

  • 비 플러그 앤 플레이 COM 포트 디바이스:

    디바이스별 함수 드라이버가 필요합니다. 함수 드라이버는 필요한 MOUSE_INPUT_DATA 구조를 만들고, 디바이스 입력 데이터의 크기를 조정하고, MouseClassServiceCallback을 호출하기 전에 MOUSE_MOVE_ABSOLUTE 플래그를 설정합니다.

  • 지원되지 않는 버스의 디바이스:

    디바이스별 함수 드라이버가 필요합니다. 함수 드라이버는 필요한 MOUSE_INPUT_DATA 구조를 만들고, 디바이스 입력 데이터의 크기를 조정하고, MouseClassServiceCallback을 호출하기 전에 MOUSE_MOVE_ABSOLUTE 플래그를 설정합니다.