← Documents Documentation/userspace-api/media/rc/keytable.c.rst GitHub 원문 ↗

Linux 6.18.37 · Userspace API / Media / Remote Controller

keytable.c 예제

IR 입력 장치의 scan code와 key code 표를 조회하거나 교체하는 C 예제입니다.

Source pathDocumentation/userspace-api/media/rc/keytable.c.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약·해설

keytable.c.rst:1-176

이 예제는 단일 대응 설정, 파일 기반 전체 교체, 현재 표 조회를 명령행 인자에 따라 수행합니다. 모든 16-bit scan code 초기화와 symbolic key name 해석 과정을 실제 input ioctl 호출로 보여 줍니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 .. SPDX-License-Identifier: GPL-2.0 OR GFDL-1.1-no-invariants-or-later
2
3 file: uapi/v4l/keytable.c
4 =========================
5
6 .. code-block:: c
7
8 /* keytable.c - This program allows checking/replacing keys at IR
9
10 Copyright (C) 2006-2009 Mauro Carvalho Chehab <mchehab@kernel.org>
11
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation, version 2 of the License.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20 */
21
22 #include <ctype.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <linux/input.h>
29 #include <sys/ioctl.h>
30
31 #include "parse.h"
32
33 void prtcode (int *codes)
34 {
35 struct parse_key *p;
36
37 for (p=keynames;p->name!=NULL;p++) {
38 if (p->value == (unsigned)codes[1]) {
39 printf("scancode 0x%04x = %s (0x%02x)\\n", codes[0], p->name, codes[1]);
40 return;
41 }
42 }
43
44 if (isprint (codes[1]))
45 printf("scancode %d = '%c' (0x%02x)\\n", codes[0], codes[1], codes[1]);
46 else
47 printf("scancode %d = 0x%02x\\n", codes[0], codes[1]);
48 }
49
50 int parse_code(char *string)
51 {
52 struct parse_key *p;
53
54 for (p=keynames;p->name!=NULL;p++) {
55 if (!strcasecmp(p->name, string)) {
56 return p->value;
57 }
58 }
59 return -1;
60 }
61
62 int main (int argc, char *argv[])
63 {
64 int fd;
65 unsigned int i, j;
66 int codes[2];
67
68 if (argc<2 || argc>4) {
69 printf ("usage: %s <device> to get table; or\\n"
70 " %s <device> <scancode> <keycode>\\n"
71 " %s <device> <keycode_file>n",*argv,*argv,*argv);
72 return -1;
73 }
74
75 if ((fd = open(argv[1], O_RDONLY)) < 0) {
76 perror("Couldn't open input device");
77 return(-1);
78 }
79
80 if (argc==4) {
81 int value;
82
83 value=parse_code(argv[3]);
84
85 if (value==-1) {
86 value = strtol(argv[3], NULL, 0);
87 if (errno)
88 perror("value");
89 }
90
91 codes [0] = (unsigned) strtol(argv[2], NULL, 0);
92 codes [1] = (unsigned) value;
93
94 if(ioctl(fd, EVIOCSKEYCODE, codes))
95 perror ("EVIOCSKEYCODE");
96
97 if(ioctl(fd, EVIOCGKEYCODE, codes)==0)
98 prtcode(codes);
99 return 0;
100 }
101
102 if (argc==3) {
103 FILE *fin;
104 int value;
105 char *scancode, *keycode, s[2048];
106
107 fin=fopen(argv[2],"r");
108 if (fin==NULL) {
109 perror ("opening keycode file");
110 return -1;
111 }
112
113 /* Clears old table */
114 for (j = 0; j < 256; j++) {
115 for (i = 0; i < 256; i++) {
116 codes[0] = (j << 8) | i;
117 codes[1] = KEY_RESERVED;
118 ioctl(fd, EVIOCSKEYCODE, codes);
119 }
120 }
121
122 while (fgets(s,sizeof(s),fin)) {
123 scancode=strtok(s,"\\n\\t =:");
124 if (!scancode) {
125 perror ("parsing input file scancode");
126 return -1;
127 }
128 if (!strcasecmp(scancode, "scancode")) {
129 scancode = strtok(NULL,"\\n\\t =:");
130 if (!scancode) {
131 perror ("parsing input file scancode");
132 return -1;
133 }
134 }
135
136 keycode=strtok(NULL,"\\n\\t =:(");
137 if (!keycode) {
138 perror ("parsing input file keycode");
139 return -1;
140 }
141
142 // printf ("parsing %s=%s:", scancode, keycode);
143 value=parse_code(keycode);
144 // printf ("\\tvalue=%d\\n",value);
145
146 if (value==-1) {
147 value = strtol(keycode, NULL, 0);
148 if (errno)
149 perror("value");
150 }
151
152 codes [0] = (unsigned) strtol(scancode, NULL, 0);
153 codes [1] = (unsigned) value;
154
155 // printf("\\t%04x=%04x\\n",codes[0], codes[1]);
156 if(ioctl(fd, EVIOCSKEYCODE, codes)) {
157 fprintf(stderr, "Setting scancode 0x%04x with 0x%04x via ",codes[0], codes[1]);
158 perror ("EVIOCSKEYCODE");
159 }
160
161 if(ioctl(fd, EVIOCGKEYCODE, codes)==0)
162 prtcode(codes);
163 }
164 return 0;
165 }
166
167 /* Get scancode table */
168 for (j = 0; j < 256; j++) {
169 for (i = 0; i < 256; i++) {
170 codes[0] = (j << 8) | i;
171 if (!ioctl(fd, EVIOCGKEYCODE, codes) && codes[1] != KEY_RESERVED)
172 prtcode(codes);
173 }
174 }
175 return 0;
176 }
177

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

파일 목적과 사용 허가

1-20

이 문서는 `uapi/v4l/keytable.c` 예제 프로그램의 전체 소스를 싣습니다. 프로그램은 IR 입력 장치의 scan code와 key code 대응표를 조회하거나 교체합니다.

저작권은 Mauro Carvalho Chehab에게 있으며 GPL 버전 2 조건으로 재배포하거나 수정할 수 있습니다. 유용성을 기대해 제공하지만 상품성이나 특정 목적 적합성에 대한 보증은 없습니다.

keytable 예제의 역할
항목설명
장치만 지정현재 등록된 scan code 표 조회
scan code와 key code 지정대응 하나를 설정한 뒤 다시 읽어 확인
key code 파일 지정기존 표를 비우고 파일의 대응 전체 적용

명령행 인자 수에 따라 같은 프로그램이 세 가지 작업을 수행합니다.

.. SPDX-License-Identifier: GPL-2.0 OR GFDL-1.1-no-invariants-or-later

file: uapi/v4l/keytable.c
=========================

.. code-block:: c

    /* keytable.c - This program allows checking/replacing keys at IR

       Copyright (C) 2006-2009 Mauro Carvalho Chehab <mchehab@kernel.org>

       This program is free software; you can redistribute it and/or modify
       it under the terms of the GNU General Public License as published by
       the Free Software Foundation, version 2 of the License.

       This program is distributed in the hope that it will be useful,
       but WITHOUT ANY WARRANTY; without even the implied warranty of
       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       GNU General Public License for more details.
     */

헤더, 출력 함수와 key code 해석

21-60

프로그램은 문자 분류, 오류, 파일 입출력, 문자열 처리, Linux input event 정의와 `ioctl()` 선언을 포함합니다. `parse.h`는 이름과 값의 대응인 `keynames` 및 `struct parse_key`를 제공합니다.

`prtcode()`는 `codes[1]`과 같은 값을 가진 이름을 `keynames`에서 찾습니다. 찾으면 scan code, symbolic key name과 16진 key code를 출력하고, 찾지 못하면 인쇄 가능한 문자는 문자와 16진 값을 함께, 그 밖의 값은 16진수만 출력합니다.

`parse_code()`는 대소문자를 구분하지 않고 주어진 문자열과 key name을 비교해 값을 반환합니다. 알려지지 않은 이름이면 `-1`을 반환하여 호출자가 숫자 문자열로 다시 해석하게 합니다.

Key code 문자열 해석
keynames를 처음부터 순회strcasecmp()가 일치하면 대응 value 반환이름이 없으면 -1 반환호출자가 strtol(..., 0)로 10진수 또는 16진수 해석

Symbolic name을 우선하고 필요할 때 숫자로 전환합니다.


    #include <ctype.h>
    #include <errno.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <linux/input.h>
    #include <sys/ioctl.h>

    #include "parse.h"

    void prtcode (int *codes)
    {
	    struct parse_key *p;

	    for (p=keynames;p->name!=NULL;p++) {
		    if (p->value == (unsigned)codes[1]) {
			    printf("scancode 0x%04x = %s (0x%02x)\\n", codes[0], p->name, codes[1]);
			    return;
		    }
	    }

	    if (isprint (codes[1]))
		    printf("scancode %d = '%c' (0x%02x)\\n", codes[0], codes[1], codes[1]);
	    else
		    printf("scancode %d = 0x%02x\\n", codes[0], codes[1]);
    }

    int parse_code(char *string)
    {
	    struct parse_key *p;

	    for (p=keynames;p->name!=NULL;p++) {
		    if (!strcasecmp(p->name, string)) {
			    return p->value;
		    }
	    }
	    return -1;
    }

명령행 검사와 단일 대응 설정

61-100

`main()`은 device 인자에 더해 선택적으로 scan code와 key code 또는 key code 파일을 받습니다. 전체 인자 수가 2~4가 아니면 세 가지 사용 형식을 출력하고 실패로 끝냅니다. 원문의 세 번째 usage 문자열에 있는 `n`도 예제 그대로 보존됩니다.

입력 장치는 `O_RDONLY`로 열며 실패하면 `perror()`로 이유를 출력합니다. 인자가 네 개이면 세 번째 사용자 인자를 symbolic key name으로 먼저 해석하고, 이름이 없으면 `strtol()`로 숫자 값을 읽습니다.

`codes[0]`에는 scan code, `codes[1]`에는 key code를 넣습니다. `EVIOCSKEYCODE`로 대응을 설정하고 `EVIOCGKEYCODE`로 같은 scan code를 다시 조회해 성공 시 `prtcode()`로 실제 값을 보여 줍니다.

단일 대응 설정에서 쓰는 input ioctl
항목설명
codes[0]설정하거나 조회할 scan code
codes[1]설정할 key code 또는 조회 결과
EVIOCSKEYCODEscan code에 key code 설정
EVIOCGKEYCODE현재 대응을 읽어 설정 결과 확인

두 정수 배열은 scan code와 key code를 전달합니다.


    int main (int argc, char *argv[])
    {
	    int fd;
	    unsigned int i, j;
	    int codes[2];

	    if (argc<2 || argc>4) {
		    printf ("usage: %s <device> to get table; or\\n"
			    "       %s <device> <scancode> <keycode>\\n"
			    "       %s <device> <keycode_file>n",*argv,*argv,*argv);
		    return -1;
	    }

	    if ((fd = open(argv[1], O_RDONLY)) < 0) {
		    perror("Couldn't open input device");
		    return(-1);
	    }

	    if (argc==4) {
		    int value;

		    value=parse_code(argv[3]);

		    if (value==-1) {
			    value = strtol(argv[3], NULL, 0);
			    if (errno)
				    perror("value");
		    }

		    codes [0] = (unsigned) strtol(argv[2], NULL, 0);
		    codes [1] = (unsigned) value;

		    if(ioctl(fd, EVIOCSKEYCODE, codes))
			    perror ("EVIOCSKEYCODE");

		    if(ioctl(fd, EVIOCGKEYCODE, codes)==0)
			    prtcode(codes);
		    return 0;
	    }

파일에서 전체 표 교체

101-165

인자가 세 개이면 두 번째 인자를 key code 파일로 열고, 열 수 없으면 오류를 보고합니다. 새 표를 적용하기 전에 0x0000부터 0xffff까지 모든 16-bit scan code에 `KEY_RESERVED`를 설정해 예전 표를 지웁니다.

각 입력 줄은 줄바꿈, 탭, 공백, 등호와 콜론을 구분자로 나눕니다. 첫 token이 `scancode`이면 다음 token을 실제 scan code로 사용하고, 이어지는 key code는 여는 괄호도 구분자에 포함해 읽습니다. 필요한 token이 없으면 즉시 parsing 오류로 종료합니다.

Key code는 `parse_code()`로 symbolic name을 먼저 찾고, 찾지 못하면 숫자로 해석합니다. Scan code도 `strtol()`로 읽어 `codes` 배열을 만들고 `EVIOCSKEYCODE`를 호출합니다. 설정 오류에는 두 값을 포함한 문맥을 출력하며, 성공 여부와 관계없이 조회가 가능하면 현재 대응을 출력합니다.

Key code 파일 적용
입력 파일 열기65,536개 scan code를 KEY_RESERVED로 초기화한 줄씩 scan code와 key code token 추출Symbolic key name 또는 숫자 key code 해석EVIOCSKEYCODE로 설정EVIOCGKEYCODE로 읽어 결과 출력

기존 표를 완전히 교체한 뒤 각 줄을 검증하며 반영합니다.


	    if (argc==3) {
		    FILE *fin;
		    int value;
		    char *scancode, *keycode, s[2048];

		    fin=fopen(argv[2],"r");
		    if (fin==NULL) {
			    perror ("opening keycode file");
			    return -1;
		    }

		    /* Clears old table */
		    for (j = 0; j < 256; j++) {
			    for (i = 0; i < 256; i++) {
				    codes[0] = (j << 8) | i;
				    codes[1] = KEY_RESERVED;
				    ioctl(fd, EVIOCSKEYCODE, codes);
			    }
		    }

		    while (fgets(s,sizeof(s),fin)) {
			    scancode=strtok(s,"\\n\\t =:");
			    if (!scancode) {
				    perror ("parsing input file scancode");
				    return -1;
			    }
			    if (!strcasecmp(scancode, "scancode")) {
				    scancode = strtok(NULL,"\\n\\t =:");
				    if (!scancode) {
					    perror ("parsing input file scancode");
					    return -1;
				    }
			    }

			    keycode=strtok(NULL,"\\n\\t =:(");
			    if (!keycode) {
				    perror ("parsing input file keycode");
				    return -1;
			    }

			    // printf ("parsing %s=%s:", scancode, keycode);
			    value=parse_code(keycode);
			    // printf ("\\tvalue=%d\\n",value);

			    if (value==-1) {
				    value = strtol(keycode, NULL, 0);
				    if (errno)
					    perror("value");
			    }

			    codes [0] = (unsigned) strtol(scancode, NULL, 0);
			    codes [1] = (unsigned) value;

			    // printf("\\t%04x=%04x\\n",codes[0], codes[1]);
			    if(ioctl(fd, EVIOCSKEYCODE, codes)) {
				    fprintf(stderr, "Setting scancode 0x%04x with 0x%04x via ",codes[0], codes[1]);
				    perror ("EVIOCSKEYCODE");
			    }

			    if(ioctl(fd, EVIOCGKEYCODE, codes)==0)
				    prtcode(codes);
		    }
		    return 0;
	    }

현재 scan code 표 조회

166-176

추가 인자가 없으면 프로그램은 모든 16-bit scan code를 순회하며 `EVIOCGKEYCODE`로 현재 대응을 조회합니다. 조회에 성공하고 key code가 `KEY_RESERVED`가 아닌 항목만 출력합니다.

따라서 출력은 실제로 배정된 대응만 포함합니다. 모든 scan code를 순회하므로 이 예제는 단순하고 명확하지만 장치가 더 효율적인 열거 방식을 제공하더라도 이를 사용하지 않습니다.


	    /* Get scancode table */
	    for (j = 0; j < 256; j++) {
		    for (i = 0; i < 256; i++) {
			    codes[0] = (j << 8) | i;
			    if (!ioctl(fd, EVIOCGKEYCODE, codes) && codes[1] != KEY_RESERVED)
				    prtcode(codes);
		    }
	    }
	    return 0;
    }