My) 아래부분의 1. 배경 지식: 스캔코드의 make와 break 이 제일 중요.



출처: http://900ift.tistory.com/45


ASCII Code Table

접어두기..


접어두기..

 
Virtual Key Code - http://msdn.microsoft.com/en-us/library/ms645540

접어두기..

가상키 코드
VK_LBUTTON 01  
VK_RBUTTON 02  
VK_CANCEL 03 Ctrl-Break
VK_MBUTTON 04  
VK_BACK 08 Backspace
VK_TAB 09 Tab
VK_CLEAR 0C NumLock이 꺼져 있을 때의 5
VK_RETURN 0D Enter
VK_SHIFT 10 Shift
VK_CONTROL 11 Ctrl
VK_MENU 12 Alt
VK_PAUSE 13 Pause
VK_CAPITAL 14 Caps Lock
VK_ESCAPE 1B Esc
VK_SPACE 20 스페이스
VK_PRIOR 21 PgUp
VK_NEXT 22 PgDn
VK_END 23 End
VK_HOME 24 Home
VK_LEFT 25 왼측 커서 이동키
VK_UP 26 위쪽 커서 이동키
VK_RIGHT 27 오른쪽 커서 이동키
VK_DOWN 28 아래쪽 커서 이동키
VK_SELECT 29  
VK_PRINT 2A  
VK_EXECUTE 2B  
VK_SNAPSHOT 2C Print Screen
VK_INSERT 2D Insert
VK_DELETE 2E Delete
VK_HELP 2F  
  30~39 숫자키 0~9
  41~5A 영문자 A~Z
VK_LWIN 5B 왼쪽 윈도우 키
VK_RWIN 5C 오른쪽 윈도우 키
VK_APP 5D Application 키
VK_NUMPAD0~VK_NUMPAD9 60~69 숫자 패드의 0~9
VK_MULTIPLY 6A 숫자 패드의 *
VK_ADD 6B 숫자 패드의 +
VK_SEPARATOR 6C  
VK_SUBTRACT 6D 숫자 패드의 -
VK_DECIMAL 6E 숫자 패드의 .
VK_DIVIDE 6F 숫자 패드의 /
VK_F1~VKF24 70~87 평션키 F1~F24
VK_NUMLOCK 90 Num Lock
VK_SCROLL 91 Scroll Lock

접어두기..

 
Scan Code - http://www.microsoft.com/whdc/archive/scancode.mspx

접어두기..


접어두기..


 한영키와 한자키 스캔코드의 비밀 - http://www.kbdmania.net/xe/tipandtech/1737860

접어두기..

key remapping에 관심이 많은 분들이 한영키와 한자키 때문에 많이 고생을 하시는 것 같습니다.

스캔코드가 상당히 이상하거든요. 어느 자료에서는 F2, F1이라고 하고, 어느 자료에서는 72, 71이라고 하고 있거든요.

저도 이것 때문에 여러번 고생을 했습니다. 그러다가 이제서야 한영키와 한자키 스캔코드가 왜 이리 이상한가 알았습니다.

컴퓨터 프로그래머나 하드웨어 전문가 분들은 알고 계실 것 같은 내용이지만, 이제 겨우 키보드 문제에 직면한 사람들은 고생하다가 포기하기 일쑤입니다. 저도 인터넷에서 한영키와 한자키의 스캔코드에 대해 설명된 글을 찾지 못했습니다. 그래서 이 글을 쓰게 됐습니다.

일단 결론부터 말하자면
한영키와 한자키의 실제 스캔코드는 F2, F1이 맞지만
실제로 컴퓨터에서는 72, 71인 것처럼 다뤄야 한다

입니다.

1. 배경 지식: 스캔코드의 make와 break

키보드의 각 키마다 각자 고유한 스캔코드가 부여돼 있습니다. 모든 키는 키를 누를 때 키보드에서 컴퓨터로 전송하는 스캔코드(이것을 make라고 합니다)를 가지고 있고, 그 중 거의 대부분의 키는 키를 뗄 때 전송하는 스캔코드(이것을 break라고 합니다)가 있습니다.

Pause/Break 키는 make 스캔코드만 있고 break 스캔코드는 없습니다. 한영키와 한자키도 PS/2 규격까지는 break가 없었다가 USB부터 break 스캔코드를 전송한다고 들었습니다.

만약 키를 눌렀다가 바로 떼지 않고 계속 누르고 있으면, 대부분의 키는 make 스캔코드만 반복적으로 계속 전송하도록 되어 있습니다. 그러나 Pause/Break, 그리고 PS/2 키보드의 한영키와 한자키 등의 소수의 키는 그렇게 반복적인 make 코드 전송을 하지 않습니다. 처음 눌렀을 때 1번만 make 코드를 전송합니다.

스캔코드의 규격은 사실 여러 종류가 있습니다. 컴퓨터 내부에서 사용하는 스캔코드는 스캔코드 집합 1입니다. 현재 나오는 거의 모든 PS/2 키보드는 스캔코드 집합 2를 써서 컴퓨터에 신호를 전달하고, 컴퓨터의 바이오스(BIOS)는 그것을 거기에 대응되는 스캔코드 집합 1로 변환을 해서 운영체제에 전달합니다(USB 키보드의 경우 USB 자체 규격에 따라 스캔코드를 컴퓨터에 전달, 컴퓨터가 그것을 스캔코드 집합 1로 변환하는 것 같습니다).

결국 컴퓨터 내부에서 처리하는 스캔코드는 스캔코드 집합 1이니, 이 글에서는 스캔코드 집합 1에 대해서만 말하겠습니다.

2. 배경 지식: 바이트(byte), 비트(bit), 2진수(binary), 16진수(hexademical)

스캔코드의 기초 단위는 1바이트(1 B)입니다. 1바이트의 크기는 상황에 따라서 다르나 대개 8비트(8 bit)로 구성됩니다. 스캔코드에서 사용하는 바이트의 개념도 1바이트=8비트를 따릅니다.

1비트란 0 또는 1을 저장하는 용량입니다. 아시다시피 컴퓨터는 모든 정보를 0과 1로만 처리합니다. 우리가 볼 수 있는 컴퓨터의 모든 동작은 전부 0과 1'만'으로 이루어지는 겁니다.

1바이트 = 8비트니까 1바이트는 2진수 00000000부터 111111111(10진수로 255, 16진수로 FF)까지의 256개의 수를 쓸 수가 있습니다.

그런데 모든 수를 00000000, 00000001, 00000002, ..., 111111111 식으로 써놓으면 우리 인간의 눈으로는 이게 얼마나 큰 수인지 가늠하기 힘듭니다. 화면이나 종이의 자릿수도 많이 차지하구요.

그래서 컴퓨터 프로그램에서는 2진수를 10진수나 16진수로 변환해서 써놓는 경우가 많습니다. 10진수는 우리 인간이 알아보기는 쉽지만 컴퓨터의 2진수와 깔끔하게 잘 맞아떨어지지 않습니다(이유는 잠시 뒤에 설명). 16진수는 10진수와 비슷하면서 2진수와 깨끗하게 호환이 됩니다. 그래서 프로그래머들은 주로 16진수를 쓰고, 컴퓨터와 관련된 여러 부분에서 16진수가 사용됩니다.

진법(進法)에 대해서 아는 내용을 복습해 봅시다.

2진수는 기본이 되는 수를 2개(0, 1)로 해서 써나가는 수 체계입니다.
10진수는 기본이 되는 수가 10개(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)입니다.

그렇다면 16진수는?
16진수는 기본이 되는 수가 16개가 돼야 하는데, 우리 인간이 쓰는 수에 관한 글자는 10개(0~9) 뿐입니다. 그래서 컴퓨터에서 쓰는 16진수 숫자는 0~9에다가 알파벳을 빌려와서 A, B, C, D, E, F, 다 합쳐 16개 문자를 기본이 되는 수로 씁니다.

예:
10진수 0 = 16진수 0
10진수 1 = 16진수 1
10진수 2 = 16진수 2
...
10진수 9 = 16진수 9
10진수 10 = 16진수 A
10진수 11 = 16진수 B
10진수 12 = 16진수 C
...
10진수 15 = 16진수 F
10진수 16 = 16진수 10
...
10진수 29 = 16진수 1D
...
10진수 255 = 16진수 FF

16진수를 쓰면 2진수 8자리의 수를 2자리로 줄일 수 있습니다. 10진수를 쓰면 자릿수가 깔끔하게 정리되지 않죠(255 식으로).

그래서 컴퓨터에서 관례적으로 16진수를 많이 쓰는 것입니다. 컴퓨터의 기계어(2진수)와 간편하게 왕복 변환이 되면서 인간 언어의 진법과 비슷하니까요.

보통 컴퓨터 관련 글을 보면 16진수를 0x12AB 식으로 적습니다. 0x12AB는 16진수 12AB(10진수로는 4779)를 가리킵니다. 관습이니까 참고로 알아두면 좋겠죠. 이 글에서도 0x를 앞세운 수는 16진법으로 적은 수입니다.

3. 배경 지식: 스캔코드의 make와 break의 관계

한 키의 make와 break는 코드 대응이 아주 일정합니다.

스캔코드 집합 1 규격에서는 make 코드에 16진수 80(10진수 128, 2진수 10000000)를 더하면 그 키의 break 코드가 됩니다.

예를 들면, A 키는 1E가 make 스캔코드인데, 16진수 80을 더한 9E가 break 스캔코드가 됩니다.

숫자키패드의 엔터 키(스캔코드 E0 1C)처럼 make 스캔코드가 2바이트인 경우에도 마찬가지로 80을 더하면 break가 됩니다(숫자키패드의 엔터키는 E0 9C).

[참고] 스캔코드의 숫자를 표기하는 방법

- 인간 언어의 관습에 따른 표기법(큰 자리에서 작은 자리로): 0xE01C의 경우 E0 1C 식으로 표기하는 것을 말합니다. 이런 방식을 컴퓨터 용어로 빅 엔디언(big endian)이라고 합니다.

- 인텔 x86 아키텍처에서 채택하는 표기법(작은 자리에서 큰 자리로): 0xE01C의 경우 1C E0 식으로 표기하는 것을 말합니다. 이런 방식을 컴퓨터 용어로 리틀 엔디언(little endian)이라고 합니다. 윈도 레지스트리에서 key remapping 설정을 할 때의 표기 방식입니다. 윈도 레지스트리에서는 절대 E0 1C로 적으면 안 됩니다.

엔디언이란 전문 용어가 나왔는데 혹시 이에 대한 자세한 설명을 읽고 싶으시다면
http://ko.wikipedia.org/wiki/%EC%97%94%EB%94%94%EC%96%B8을 보시기 바랍니다.

오토핫키의 경우 scNNN(NNN은 세 자리의 16진수) 식으로 표기를 하는데요, 1C처럼 1바이트의 스캔코드이면 sc01C식으로 적고, E01C처럼 앞에 E0을 앞세운 2바이트 스캔코드면 sc11C 식으로 첫 글자를 1로 씁니다.

참고로 E0는 스캔코드 집합 1과 집합 2 규격에서 특별한 키를 구분하는 용도로 쓰는 특수 코드입니다. 오토핫키에서는 빠르고 간편하게 스캔코드를 서술하기 위하여 E0을 1로 바꿔 쓰는 겁니다. 스캔코드 집합 1(오토핫키에서 사용), 2에서는 2바이트 스캔코드는 무조건 E0를 앞세운 것만 존재합니다.


break 코드는 이론적으로 80(2진수 10000000) ~ FF(2진수 11111111) 사이의 수만 가능합니다. 무조건 16진수 80을 더해야 하기 때문입니다.  16진수 80보다 작은 수인데 이것이 break가 되려면 그 make 코드가 음수가 돼야 하는데, 스캔코드에 음수는 없죠.

그리고 만약 80~FF의 수를 make로 처리할 경우 거기에 대응되는 break 코드를 만들 수가 없습니다. 예를 들어 F2라면 F2 + 80 = 172(2진수 101110010)이 돼서 1바이트도 아니고 2바이트도 아닌 게 됩니다. 스캔코드는 무조건 최소 단위가 1바이트(8비트, 즉 8자리의 2진수)여야 하는데 101110010는 9자리니까 애매하게 됩니다.

그래서 많은 컴퓨터 시스템들이 00~7F까지가 make 코드, 80~FF까지가 break 코드라는 전제하에 프로그램들이 만들어졌습니다.

바로 이런 특성 때문에 한영키와 한자키 문제가 생깁니다.

4. 그래서 도대체 한영키, 한자키 스캔코드가 뭐지?

당연한 이야기지만 키보드의 한영키와 한자키 스캔코드를 규정한 것은 한국인입니다. 아예 국가 표준으로 돼 있죠.

그런데 이 규격을 너무나 잘못 정한 것 같습니다(그렇다고 이제 와서 바꿀 수도 없는 노릇이죠).

F2와 F1을 make로 하고 break 코드는 없는 걸로 돼 있습니다(Pause/Break 키도 break 스캔코드를 만들지 않는 특수 키입니다). 방금 말했듯이 대개 80~FF까지가 break 코드로 인식하는데, 우리나라는 그 관례를 어기고 한영키와 한자키의 스캔코드를 제정했습니다.

따라서 원래 규격상으로는 한영키, 한자키의 스캔코드는 72, 71이 아니라 F2, F1이 맞습니다.

이 두 키에 break 코드가 없는 것까지는 좋습니다(물론 break 코드가 없으면 키 리매핑을 쉽게 못하지만, 원래 키보드가 키 리매핑을 염두해 두고 만드는 건 아니니까 문제가 되진 않습니다). 그러나 더 골치 아픈 문제는 대부분의 컴퓨터 프로그램에서 F2와 F1을 make가 아니라 break 코드라고 간주한다는 것입니다.

그래서 외국에서 만들어진 소프트웨어에서 종종 한영키와 한자키를 제대로 처리하지 못합니다. 원칙적으로 모든 키는 make 신호가 반드시 있어야 하고, break 신호는 있을 수도 있고 없을 수도 있습니다. 예를 들어 Esc를 눌렀다 떼면 Esc의 make 코드와 break 코드를 순서대로 보내고, Pause/Break 키를 눌렀다 떼면 Pause/Break의 make 코드 하나만 전송하는 식입니다. break만 전송하는 경우는 없습니다.

그런데 한영키나 한자키를 누르면 컴퓨터 프로그램은 자꾸 키보드에서 make 없이 break만 내보낸다고 착각합니다. 뭔가 에러가 나서 잘못된 신호가 들어온 걸로 보고 그냥 무시하게 되는 것이죠.


그리고 이런 문제는 윈도 레지스트리 편집이나 오토핫키 스크립트 작성시에도 적용이 됩니다.

윈도 레지스트리에서 키 매핑 변경하는 것이나 오토핫키에서 스캔코드를 사용하는 것은 전부 스캔코드 집합 1의 make 코드뿐입니다. F2와 F1처럼 80~FF 사이의 수는 break로 생각하니까 임의로 이들의 make 코드가 각각 72, 71인 걸로 간주하는 겁니다. 16진수에서 F2 - 80 = 72, F1 - 80 = 71이니까(break 스캔코드에서 80을 빼면 make 스캔코드) 컴퓨터가 잘못 유추해서 판단하는 것입니다.

그래서 많은 가이드에서 레지스트리나 오토핫키에서 다른 키를 강제로 한영키나 한자키로 변경할 때 그 코드를 F2, F1으로 적지 말고 72, 71로 하라고 하는 것입니다.

괜히 80~FF 사이의 것으로 make 코드를 만드는 바람에 사람 헷갈리게 하고 있습니다 ㅡㅡ;;

5. 한영키와 한자키를 다른 키로 매핑하는 방법은 없나?

USB는 모르겠고, PS/2 키보드는 윈도 레지스트리 수정을 통한 매핑은 불가능한 것 같습니다. 레지스트리를 통한 키 변경의 원리는 다음과 같습니다.

만약 레지스트리 수정을 통해서 A 키를 B 키로 바꿨다고 가정해 봅시다.
a. A 키를 누른다.
b. 키보드에서 A키의 make 스캔코드를 발생시킨다.
c. 컴퓨터로 전달. 바이오스가 적절한 변환을 거쳐서 운영체제로 전달함
d. 운영체제(드라이버까지 포함)가 그것을 받아서 A 키가 눌린 것을 알아차림.
e. 운영체제가 레지스트리를 참고하여 그것을 B 키의 make 스캔코드로 바꿈.
f. 운영체제가 B 키의 make 스캔코드에 해당하는 가상 키 코드(virtual key code)를 찾음.
g. 운영체제가 B 키의 make 스캔코드 및 가상 키코드를 운영체제 안에 깔린 응용프로그램으로 전달.

참고: 많은 운영체제에서 스캔코드를 그대로 컴퓨터 안에서 사용하지 않고, 자체적인 가상 키코드를 매치시켜서 사용하는 경우가 많습니다. 윈도의 경우, 한국어와 일본어 입력기가 어떤 자판 유형으로 되어 있느냐에 따라 각 스캔코드별 가상 키코드 대응이 달라집니다.

한글 키보드를 예로 들겠습니다.

사용하는 키보드 드라이버가 PC/AT 101키 호환 키보드/USB 키보드(종류 1)일 경우 오른쪽 Alt 스캔코드가 컴퓨터로 들어가면 한영 전환 가상 키코드를 발생시킵니다. (물론 한영키를 눌러도 한영 전환 가상 키코드를 발생시킵니다.)

그러나 PC/AT 101키 호환 키보드/USB 키보드(종류 3)일 경우, 오른쪽 Alt를 누르면 한영 전환 가상 키코드를 발생시키는 게 아니라 오른쪽 Alt의 가상 키코드를 만들어 냅니다. 이 드라이버에서 한영 전환 가상 키코드를 발생시키는 경우는 한영키를 누르거나 Shift+Space를 누르는 경우입니다(Shift 자체에 대해서는 그냥 Shift 키의 가상 키코드를 발생시키고, Shift를 누르고 있는 동안에 Space를 누르면 Space에 대해 한영전환 가상 키코드를 매칭시켜줍니다[Space를 단독으로 눌렀을 때 발생시키던 가상 키코드를 매칭시키지 않고 한영전환 키코드를 발생]).


키보드의 키 입력은 일단 make가 생겨야 뭔가 작동을 하는데 한영키와 한자키의 스캔코드 F2, F1을 break로 생각하니까 정상적인 리매핑이 잘 안 되는 겁니다(반대로 기존에 있던 다른 키를 한영키와 한자키로 인식시키는 건 대개 잘 됩니다).

오토핫키는 원리가 조금 다르긴 하지만 비슷한 이유로 한영키와 한자키를 다른 걸로 그냥은 못 바꿉니다.

(USB 키보드는 한영키와 한자키에 자체 스캔코드로 make와 break 코드를 모두 할당해서 레지스트리, 오토핫키 모두 키 리매핑이 가능한 모양이나 저는 그게 없어서 테스트해보지 못했습니다.)

다행히도 오토핫키에서 트릭을 이용하면 변칙적으로 PS/2 키보드에서 한영키 또는 한자키를 다른 키로 동작하게 바꿀 순 있습니다.

다음은 PS/2 키보드의 한영키를 a 키로 인식시키는 오토핫키 스크립트 입니다. 아마 USB 키보드도 정상작동할 것 같습니다.

vk15sc072::send {a}
sc072 Up::send {a}


첫번째 줄은 윈도에서 현재 한국어 IME를 사용 중일 때만 정상 작동합니다.
두번째 줄은 한국어 IME 이외의 외국어 IME(일본어 등)를 사용할 때 작동합니다.

제가 확인해 보니 한국어 이외의 외국어 IME를 사용 중일 때에서는 한영키, 한자키를 break 코드로 착각합니다. 참고로 오토핫키 문법에서 Up은 break 코드를 전송하는 시점에 맞춰서 :: 다음의 명령을 실행하라는 뜻입니다.

원래 오토핫키에서 키 리매핑을 할 경우 어떤 상황에서든 똑같이 키 리매핑이 이루어지게 하는 게 원칙인데, 한영키와 한자키에 대해서는 IME에 따라 이렇게 다르게 인식이 됩니다. 따라서 만약에 모든 IME에서 똑같이 한영키와 한자키가 다르게 동작하기 바란다면 이런 식으로 두 가지 설정을 해줘야 합니다.

다만 유의해야 할 것이 이렇게 해도 완전히 키 리매핑은 못합니다.

위와 같은 오토핫키 스크립트를 작성해 놓고 한영키를 누르고 있으면 aaaaaaaaaaaaaaaa나 ㅁㅁㅁㅁㅁㅁㅁㅁㅁㅁㅁ 식으로 계속 문자가 입력되는 게 아니라 a 이런 식으로 한 번만 입력이 됩니다. 앞서 말했듯이 PS/2 키보드의 한영키, 한자키는 반복적으로 make 코드를 전송해주지 않습니다. 한영 키로 aaaaaaaa나 ㅁㅁㅁㅁㅁㅁㅁㅁ를 입력하려면, 한영키를 눌렀다 뗐다를 반복해야 합니다.

따라서 한영키와 한자키를 Alt, Ctrl, Shift, Win 등으로 매핑하는 것도 안 됩니다. 이런 키들은 지금 키를 누르고 있는 것인지, 그리고 정확히 언제 키를 뗐는지 확인이 돼야 하는데, PS/2 키보드의 한영키와 한자키는 그렇게 할 수 없으니까요.

PS/2 키보드에서 한영키와 한자키를 리매핑하는 것은 이들 키를 일본어 변환, 무변환 등의 키를 할당할 때 유용하게 쓸 수 있다는 장점이 있습니다. 예를 들어 다음과 같은 코드가 있다고 칩시다.

sc071 Up::send {vk1D}
sc072 Up::send {vk1C}


한자키를 일본어 키보드의 무변환키, 한영키를 일본어의 변환키로 작동하게 하는 겁니다.

참고: 일부러 무변환/변환 키의 스캔코드가 아니라 가상 키코드만 썼습니다. 일본어 IME는 한글 키보드의 경우(101키보드 종류 1/종류 2/종류 3 또는 103키보드 드라이버가 각각 한영전환 및 한자변환 키가 달라짐)와 마찬가지로 현재의 키보드 드라이버가 무엇이냐에 따라 각 키의 대응을 달리하기 때문에(일본 표준 106/109 키보드, 미국 101/104 키보드, 일본의 구형 AX 키보드 등), 차라리 가상 키코드를 쓰는 것이 안전할 것 같습니다.

이미 말한대로 sc07x Up::을 통한 서술은은 한국어 IME 이외의 IME 상태에서만 동작합니다.
따라서 위 두 줄은 한국어 IME에는 영향을 끼치지 않으니까, 한영 전환과 한자 변환이 정상 작동됩니다.

그런데 무변환과 변환의 가상 키코드는 일본어에서만 사용하는 것입니다. 따라서 위 스크립트는 중국어나 프랑스어 등의 또 다른 외국어 IME 상태에서도 영향을 끼치지 않습니다.

결론적으로 위와 같이 무변환/변환 키 추가는 오로지 일본어 IME에서만 작동합니다.

무변환/변환 같은 일본어 키보드에만 있는 키가 아니라, 다른 언어 키보드에도 있는 키를 저런 식으로 매핑한다면, 한국어 IME를 뺀 나머지 모든 언어의 IME에 일괄 적용되니 주의해야 합니다.

일본어 키보드에만 있는 특수 키에 대한 설명은 추후에 시간이 있으면 별도의 글로 쓰겠습니다.


다음과 같이 코딩을 하면 한국어 IME 상태에서 한영키를 누르면 1이 입력되고, 일본어 IME 상태에서 한영키를 누르면 변환키로 작동합니다.

vk15sc072::1
sc072 Up::send {vk1C}

접어두기..

'Programming' 카테고리의 다른 글

삼성노트북 Fn key code  (0) 2013.11.29
코드 리뷰  (0) 2013.08.12
[펌] Winsock(소켓)설명_좋음  (0) 2013.08.09
Posted by 세모아
,