diff options
| author | qz150045 <none@none> | 2006-01-16 01:03:19 -0800 |
|---|---|---|
| committer | qz150045 <none@none> | 2006-01-16 01:03:19 -0800 |
| commit | 7db6e34e0974b29ab599ed5dbc95a2f71810f321 (patch) | |
| tree | 4d5487def416b3e2d42529edb44f5fc9396891d1 /usr/src/cmd/kbd/kbd.c | |
| parent | 21d7f835c9bac5f9e80c72fc972ee5b288845983 (diff) | |
| download | illumos-joyent-7db6e34e0974b29ab599ed5dbc95a2f71810f321.tar.gz | |
PSARC 2005/535 zero-CountryCode keyboard layout support
6265017 low cost PC keyboards don't send correct bCountryCode byte
Diffstat (limited to 'usr/src/cmd/kbd/kbd.c')
| -rw-r--r-- | usr/src/cmd/kbd/kbd.c | 238 |
1 files changed, 224 insertions, 14 deletions
diff --git a/usr/src/cmd/kbd/kbd.c b/usr/src/cmd/kbd/kbd.c index 9d99182f34..8aa297ba74 100644 --- a/usr/src/cmd/kbd/kbd.c +++ b/usr/src/cmd/kbd/kbd.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -40,6 +40,7 @@ * -D autorepeat delay sets autorepeat dealy, unit in ms * -R autorepeat rate sets autorepeat rate, unit in ms * -d keyboard device chooses the kbd device, default /dev/kbd. + * -s keyboard layout sets keyboard layout */ #include <sys/types.h> @@ -60,6 +61,17 @@ #define DEF_CLICK "KEYCLICK=" #define DEF_RPTDELAY "REPEAT_DELAY=" #define DEF_RPTRATE "REPEAT_RATE=" +#define DEF_LAYOUT "LAYOUT=" + +#define KBD_LAYOUT_FILE "/usr/share/lib/keytables/type_6/kbd_layouts" +#define MAX_LAYOUT_NUM 128 +#define MAX_LINE_SIZE 256 +#define DEFAULT_KBD_LAYOUT 33 + +char *layout_names[MAX_LAYOUT_NUM]; +int layout_numbers[MAX_LAYOUT_NUM]; +static int layout_count; +static int default_layout_number = 0; static void reset(int); static void get_type(int); @@ -72,23 +84,28 @@ static int abort_enable(char *, int); static int set_repeat_delay(char *, int); static int set_repeat_rate(char *, int); +static int get_layout_number(char *); +static int set_layout(int, int); +static int get_layouts(void); +static int set_kbd_layout(int, char *); + int main(int argc, char **argv) { int c, error; int rflag, tflag, lflag, cflag, dflag, aflag, iflag, errflag, - Dflag, Rflag, rtlacDRflag; - char *copt, *aopt, *delay, *rate; + Dflag, Rflag, rtlacDRflag, sflag; + char *copt, *aopt, *delay, *rate, *layout_name; char *kbdname = KBD_DEVICE; int kbd; extern char *optarg; extern int optind; rflag = tflag = cflag = dflag = aflag = iflag = errflag = lflag = - Dflag = Rflag = 0; + Dflag = Rflag = sflag = 0; copt = aopt = (char *)0; - while ((c = getopt(argc, argv, "rtlic:a:d:D:R:")) != EOF) { + while ((c = getopt(argc, argv, "rtlisc:a:d:D:R:")) != EOF) { switch (c) { case 'r': rflag++; @@ -102,6 +119,9 @@ main(int argc, char **argv) case 'i': iflag++; break; + case 's': + sflag++; + break; case 'c': copt = optarg; cflag++; @@ -132,20 +152,22 @@ main(int argc, char **argv) * Check for valid arguments: * * If argument parsing failed or if there are left-over - * command line arguments, then we're done now. + * command line arguments(except -s option), then we're done now. */ - if (errflag != 0 || argc != optind) { + if (errflag != 0 || ((sflag == 0) && (argc != optind))) { usage(); exit(1); } + /* - * kbd requires that the user specify either "-i" or at least one of - * -[rtlacDR]. The "-d" option is, well, optional. We don't - * care if it's there or not. + * kbd requires that the user specify either "-i" or "-s" or at + * least one of -[rtlacDR]. The "-d" option is, well, optional. + * We don't care if it's there or not. */ rtlacDRflag = rflag + tflag + lflag + aflag + cflag + Dflag + Rflag; - if ((iflag != 0 && rtlacDRflag != 0) || - (iflag == 0 && rtlacDRflag == 0)) { + if (!((iflag != 0 && sflag == 0 && rtlacDRflag == 0) || + (iflag == 0 && sflag != 0 && dflag == 0 && rtlacDRflag == 0) || + (iflag == 0 && sflag == 0 && rtlacDRflag != 0))) { usage(); exit(1); } @@ -198,6 +220,107 @@ main(int argc, char **argv) if (Rflag && (error = set_repeat_rate(rate, kbd)) != 0) exit(error); + if (sflag) { + if (argc == optind) { + layout_name = NULL; + } else if (argc == (optind + 1)) { + layout_name = argv[optind]; + } else { + usage(); + exit(1); + } + + if ((error = set_kbd_layout(kbd, layout_name)) != 0) + exit(error); + } + + return (0); +} + +/* + * this routine gets the type of the keyboard being used + */ +static int +set_kbd_layout(int kbd, char *layout_name) +{ + int layout_num; + int error = 1; + + /* get the language info from the layouts file */ + if (get_layouts() != 0) + return (error); + + if (layout_name != NULL) { + if ((layout_num = get_layout_number(layout_name)) == -1) { + (void) fprintf(stderr, "%s: unknown layout name\n" + "Please refer to 'kbd -s' to get the " + "supported layouts.\n", layout_name); + return (error); + } + } else { + int i, j, print_cnt, input_num; + boolean_t input_right = B_TRUE; + boolean_t default_input = B_FALSE; + char input[8]; /* 8 chars is enough for numbers */ + + print_cnt = (layout_count % 2) ? + layout_count/2+1 : layout_count/2; + + for (i = 1; i <= print_cnt; i++) { + (void) printf("%2d. %-30s", i, + layout_names[i-1]); + j = i + print_cnt; + if (j <= layout_count) { + (void) printf("%-2d. %-30s\n", j, + layout_names[j-1]); + } + } + (void) printf("\nTo select the keyboard layout, enter" + " a number [default %d]:", + default_layout_number+1); + + for (;;) { + if (input_right == B_FALSE) + (void) printf("Invalid input. Please " + "input a number (1,2,...):"); + (void) memset(input, 0, 8); + (void) fflush(stdin); + (void) fgets(input, 8, stdin); + if (strlen(input) > 4) { + input_right = B_FALSE; + continue; + } + if (input[0] == '\n') { + default_input = B_TRUE; + break; + } + input_right = B_TRUE; + /* check if the inputs are numbers 0~9 */ + for (i = 0; i < (strlen(input) - 1); i++) { + if ((input[i] < '0') || + (input[i] > '9')) { + input_right = B_FALSE; + break; + } + } + if (input_right == B_FALSE) + continue; + input_num = atoi(input); + if ((input_num > 0) && + (input_num <= layout_count)) + break; + else + input_right = B_FALSE; + } + if (default_input == B_TRUE) + layout_num = DEFAULT_KBD_LAYOUT; + else + layout_num = layout_numbers[--input_num]; + } + + if ((error = set_layout(kbd, layout_num)) != 0) + return (error); + return (0); } @@ -412,6 +535,7 @@ static void kbd_defaults(int kbd) { char *p; + int layout_num; if (defopen(DEF_FILE) != 0) { (void) fprintf(stderr, "Can't open default file: %s\n", @@ -464,15 +588,101 @@ kbd_defaults(int kbd) else (void) fprintf(stderr, BAD_DEFAULT, DEF_RPTRATE, p); } + + p = defread(DEF_LAYOUT); + if (p != NULL) { + /* + * LAYOUT must be one of the layouts supported in kbd_layouts + */ + if (get_layouts() != 0) + return; + + if ((layout_num = get_layout_number(p)) == -1) { + (void) fprintf(stderr, BAD_DEFAULT, DEF_LAYOUT, p); + return; + } + + (void) set_layout(kbd, layout_num); + } +} + +static int +get_layout_number(char *layout) +{ + int i; + int layout_number = -1; + + for (i = 0; i < layout_count; i ++) { + if (strcmp(layout, layout_names[i]) == 0) { + layout_number = layout_numbers[i]; + break; + } + } + + return (layout_number); +} + +static int +get_layouts() +{ + FILE *stream; + char buffer[MAX_LINE_SIZE]; + char *result = NULL; + int i = 0; + char *tmpbuf; + + if ((stream = fopen(KBD_LAYOUT_FILE, "r")) == 0) { + perror(KBD_LAYOUT_FILE); + return (1); + } + + while ((fgets(buffer, MAX_LINE_SIZE, stream) != NULL) && + (i < MAX_LAYOUT_NUM)) { + if (buffer[0] == '#') + continue; + if ((result = strtok(buffer, "=")) == NULL) + continue; + if ((tmpbuf = strdup(result)) != NULL) { + layout_names[i] = tmpbuf; + } else { + perror("out of memory getting layout names"); + return (1); + } + if ((result = strtok(NULL, "\n")) == NULL) + continue; + layout_numbers[i] = atoi(result); + if (strcmp(tmpbuf, "US-English") == 0) + default_layout_number = i; + i++; + } + layout_count = i; + + return (0); +} + +/* + * this routine sets the layout of the keyboard being used + */ +static int +set_layout(int kbd, int layout_num) +{ + + if (ioctl(kbd, KIOCSLAYOUT, layout_num)) { + perror("ioctl (set kbd layout)"); + return (1); + } + + return (0); } static char *usage1 = "kbd [-r] [-t] [-l] [-a enable|disable|alternate]"; static char *usage2 = " [-c on|off][-D delay][-R rate][-d keyboard device]"; static char *usage3 = "kbd -i [-d keyboard device]"; +static char *usage4 = "kbd -s [language]"; static void usage(void) { - (void) fprintf(stderr, "Usage:\t%s\n\t%s\n\t%s\n", usage1, usage2, - usage3); + (void) fprintf(stderr, "Usage:\t%s\n\t%s\n\t%s\n\t%s\n", usage1, usage2, + usage3, usage4); } |
