summaryrefslogtreecommitdiff
path: root/usr/src/cmd/kbd/kbd.c
diff options
context:
space:
mode:
authorqz150045 <none@none>2006-01-16 01:03:19 -0800
committerqz150045 <none@none>2006-01-16 01:03:19 -0800
commit7db6e34e0974b29ab599ed5dbc95a2f71810f321 (patch)
tree4d5487def416b3e2d42529edb44f5fc9396891d1 /usr/src/cmd/kbd/kbd.c
parent21d7f835c9bac5f9e80c72fc972ee5b288845983 (diff)
downloadillumos-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.c238
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);
}