jcs's openbsd hax
openbsd

Add fields for wsmouse/touchpad configuration.

bru d22ea701 fc8b88ee

+455 -9
+2 -2
sbin/wsconsctl/Makefile
··· 1 - # $OpenBSD: Makefile,v 1.43 2017/07/10 21:30:37 espie Exp $ 1 + # $OpenBSD: Makefile,v 1.44 2017/07/21 20:38:20 bru Exp $ 2 2 3 3 .if ${MACHINE} != "octeon" 4 4 5 5 PROG= wsconsctl 6 6 SRCS= display.c keyboard.c keysym.c map_parse.y map_scan.l \ 7 - mouse.c util.c wsconsctl.c 7 + mouse.c mousecfg.c util.c wsconsctl.c 8 8 9 9 CPPFLAGS+= -I${.CURDIR} -I. 10 10 CLEANFILES+= keysym.h
+63 -1
sbin/wsconsctl/mouse.c
··· 1 - /* $OpenBSD: mouse.c,v 1.13 2012/08/08 16:44:07 shadchin Exp $ */ 1 + /* $OpenBSD: mouse.c,v 1.14 2017/07/21 20:38:20 bru Exp $ */ 2 2 /* $NetBSD: mouse.c,v 1.3 1999/11/15 13:47:30 ad Exp $ */ 3 3 4 4 /*- ··· 38 38 #include <fcntl.h> 39 39 #include <stdio.h> 40 40 #include "wsconsctl.h" 41 + #include "mousecfg.h" 41 42 42 43 static u_int mstype; 43 44 static u_int resolution; ··· 52 53 { "type", &mstype, FMT_MSTYPE, FLG_RDONLY }, 53 54 { "rawmode", &rawmode, FMT_UINT, FLG_MODIFY|FLG_INIT}, 54 55 { "scale", &wmcoords, FMT_SCALE, FLG_MODIFY|FLG_INIT}, 56 + /* touchpad configuration (mousecfg): */ 57 + { "tp.tapping", &cfg_tapping, FMT_CFG, FLG_NORDBACK }, 58 + { "tp.scaling", &cfg_scaling, FMT_CFG, FLG_NORDBACK }, 59 + { "tp.swapsides", &cfg_swapsides, FMT_CFG, FLG_NORDBACK }, 60 + { "tp.disable", &cfg_disable, FMT_CFG, FLG_NORDBACK }, 61 + { "tp.param", &cfg_param, FMT_CFG, FLG_WRONLY }, 55 62 { NULL } 56 63 }; 57 64 65 + static int dev_index = -1; 66 + 67 + 68 + void 69 + mouse_init(int devfd, int devidx) { 70 + struct field *f; 71 + const char *errstr; 72 + int err; 73 + 74 + if (dev_index == devidx) 75 + return; 76 + 77 + if ((err = mousecfg_init(devfd, &errstr))) { 78 + devidx = -1; 79 + for (f = mouse_field_tab; f->name != NULL; f++) { 80 + if (f->format == FMT_CFG) 81 + f->flags |= FLG_DEAD; 82 + } 83 + if (errstr != NULL) 84 + warnx("mousecfg error: %s (%d)", errstr, err); 85 + } else if (dev_index > -1) { 86 + for (f = mouse_field_tab; f->name != NULL; f++) { 87 + if (f->format == FMT_CFG) 88 + f->flags &= ~FLG_DEAD; 89 + } 90 + } 91 + 92 + dev_index = devidx; 93 + } 94 + 58 95 void 59 96 mouse_get_values(int fd) 60 97 { 98 + struct field *f; 99 + 61 100 if (field_by_value(mouse_field_tab, &mstype)->flags & FLG_GET) 62 101 if (ioctl(fd, WSMOUSEIO_GTYPE, &mstype) < 0) 63 102 warn("WSMOUSEIO_GTYPE"); ··· 81 120 else 82 121 warn("WSMOUSEIO_GCALIBCOORDS"); 83 122 } 123 + 124 + for (f = mouse_field_tab; f->name != NULL; f++) { 125 + if (f->format != FMT_CFG || !(f->flags & FLG_GET)) 126 + continue; 127 + if (f->valp == &cfg_param) 128 + continue; 129 + if (mousecfg_get_field((struct wsmouse_parameters *) f->valp)) { 130 + f->flags |= FLG_DEAD; 131 + warnx("mousecfg: invalid key in '%s'", f->name); 132 + } 133 + } 84 134 } 85 135 86 136 int 87 137 mouse_put_values(int fd) 88 138 { 139 + struct field *f; 140 + 89 141 if (field_by_value(mouse_field_tab, &resolution)->flags & FLG_SET) { 90 142 if (ioctl(fd, WSMOUSEIO_SRES, &resolution) < 0) { 91 143 warn("WSMOUSEIO_SRES"); ··· 127 179 warn("WSMOUSEIO_SCALIBCOORDS"); 128 180 return 1; 129 181 } 182 + } 183 + } 184 + 185 + for (f = mouse_field_tab; f->name != NULL; f++) { 186 + if (f->format != FMT_CFG || !(f->flags & FLG_SET)) 187 + continue; 188 + if (mousecfg_put_field(fd, 189 + (struct wsmouse_parameters *) f->valp)) { 190 + warn("mousecfg error (%s)", f->name); 191 + return 1; 130 192 } 131 193 } 132 194
+339
sbin/wsconsctl/mousecfg.c
··· 1 + /* $OpenBSD: mousecfg.c,v 1.1 2017/07/21 20:38:20 bru Exp $ */ 2 + 3 + /* 4 + * Copyright (c) 2017 Ulf Brosziewski 5 + * 6 + * Permission to use, copy, modify, and distribute this software for any 7 + * purpose with or without fee is hereby granted, provided that the above 8 + * copyright notice and this permission notice appear in all copies. 9 + * 10 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 + */ 18 + 19 + /* 20 + * Read/write wsmouse parameters for touchpad configuration. 21 + */ 22 + 23 + #include <sys/ioctl.h> 24 + #include <sys/param.h> 25 + #include <dev/wscons/wsconsio.h> 26 + #include <stdio.h> 27 + #include <stdlib.h> 28 + #include <string.h> 29 + #include <err.h> 30 + #include <errno.h> 31 + #include "mousecfg.h" 32 + 33 + #define BASE_FIRST WSMOUSECFG_DX_SCALE 34 + #define BASE_LAST WSMOUSECFG_Y_INV 35 + #define TP_FILTER_FIRST WSMOUSECFG_DX_MAX 36 + #define TP_FILTER_LAST WSMOUSECFG_SMOOTHING 37 + #define TP_FEATURES_FIRST WSMOUSECFG_SOFTBUTTONS 38 + #define TP_FEATURES_LAST WSMOUSECFG_TAPPING 39 + #define TP_SETUP_FIRST WSMOUSECFG_LEFT_EDGE 40 + #define TP_SETUP_LAST WSMOUSECFG_TAP_LOCKTIME 41 + 42 + #define BASESIZE (BASE_LAST - BASE_FIRST + 1) 43 + 44 + #define BUFSIZE (BASESIZE \ 45 + + (TP_FILTER_LAST - TP_FILTER_FIRST + 1) \ 46 + + (TP_FEATURES_LAST - TP_FEATURES_FIRST + 1) \ 47 + + (TP_SETUP_LAST - TP_SETUP_FIRST + 1)) 48 + 49 + static const int range[][2] = { 50 + { BASE_FIRST, BASE_LAST }, 51 + { TP_FILTER_FIRST, TP_FILTER_LAST }, 52 + { TP_FEATURES_FIRST, TP_FEATURES_LAST }, 53 + { TP_SETUP_FIRST, TP_SETUP_LAST }, 54 + }; 55 + 56 + static const int touchpad_types[] = { 57 + WSMOUSE_TYPE_SYNAPTICS, /* Synaptics touchpad */ 58 + WSMOUSE_TYPE_ALPS, /* ALPS touchpad */ 59 + WSMOUSE_TYPE_ELANTECH, /* Elantech touchpad */ 60 + WSMOUSE_TYPE_SYNAP_SBTN, /* Synaptics soft buttons */ 61 + }; 62 + 63 + struct wsmouse_parameters cfg_tapping = { 64 + (struct wsmouse_param[]) { 65 + { WSMOUSECFG_TAPPING, 0 }, }, 66 + 1 67 + }; 68 + 69 + struct wsmouse_parameters cfg_scaling = { 70 + (struct wsmouse_param[]) { 71 + { WSMOUSECFG_DX_SCALE, 0 }, 72 + { WSMOUSECFG_DY_SCALE, 0 } }, 73 + 2 74 + }; 75 + 76 + struct wsmouse_parameters cfg_swapsides = { 77 + (struct wsmouse_param[]) { 78 + { WSMOUSECFG_SWAPSIDES, 0 }, }, 79 + 1 80 + }; 81 + 82 + struct wsmouse_parameters cfg_disable = { 83 + (struct wsmouse_param[]) { 84 + { WSMOUSECFG_DISABLE, 0 }, }, 85 + 1 86 + }; 87 + 88 + struct wsmouse_parameters cfg_param = { 89 + (struct wsmouse_param[]) { 90 + { -1, 0 }, 91 + { -1, 0 }, 92 + { -1, 0 }, 93 + { -1, 0 } }, 94 + 4 95 + }; 96 + 97 + static int cfg_horiz_res; 98 + static int cfg_vert_res; 99 + static struct wsmouse_param cfg_buffer[BUFSIZE]; 100 + 101 + 102 + int 103 + mousecfg_init(int dev_fd, const char **errstr) 104 + { 105 + struct wsmouse_calibcoords coords; 106 + struct wsmouse_parameters parameters; 107 + struct wsmouse_param *param; 108 + enum wsmousecfg k; 109 + int i, err, type; 110 + 111 + *errstr = NULL; 112 + 113 + if ((err = ioctl(dev_fd, WSMOUSEIO_GTYPE, &type))) { 114 + *errstr = "WSMOUSEIO_GTYPE"; 115 + return err; 116 + } 117 + for (i = 0; i < nitems(touchpad_types) 118 + && type != touchpad_types[i]; i++) {} 119 + 120 + /* 121 + * If the device is not a touchpad, return an error without 122 + * setting the error string. The caller shouldn't print a 123 + * warning in this case. 124 + */ 125 + if (i == nitems(touchpad_types)) 126 + return (-1); 127 + 128 + if ((err = ioctl(dev_fd, WSMOUSEIO_GCALIBCOORDS, &coords))) { 129 + *errstr = "WSMOUSEIO_GCALIBCOORDS"; 130 + return err; 131 + } 132 + cfg_horiz_res = coords.resx; 133 + cfg_vert_res = coords.resy; 134 + 135 + param = cfg_buffer; 136 + for (i = 0; i < nitems(range); i++) 137 + for (k = range[i][0]; k <= range[i][1]; k++, param++) { 138 + param->key = k; 139 + param->value = 0; 140 + } 141 + 142 + /* 143 + * Not all touchpad drivers configure wsmouse for compat mode yet. 144 + * In those cases the first ioctl call may be successful but the 145 + * second one will fail because it includes wstpad parameters: 146 + */ 147 + parameters.params = cfg_buffer; 148 + parameters.nparams = BASESIZE; 149 + if ((err = ioctl(dev_fd, WSMOUSEIO_GETPARAMS, &parameters))) { 150 + *errstr = "WSMOUSEIO_GETPARAMS"; 151 + return (err); 152 + } 153 + parameters.params = cfg_buffer + BASESIZE; 154 + parameters.nparams = BUFSIZE - BASESIZE; 155 + if ((err = ioctl(dev_fd, WSMOUSEIO_GETPARAMS, &parameters))) { 156 + if (err != EINVAL) 157 + *errstr = "WSMOUSEIO_GETPARAMS"; 158 + return (err); 159 + } 160 + 161 + return (0); 162 + } 163 + 164 + /* Map a key to its buffer index. */ 165 + static int 166 + index_of(enum wsmousecfg key) 167 + { 168 + int i, n; 169 + 170 + for (i = 0, n = 0; i < nitems(range); i++) 171 + if (key <= range[i][1] && key >= range[i][0]) 172 + return (key - range[i][0] + n); 173 + else 174 + n += range[i][1] - range[i][0] + 1; 175 + 176 + return (-1); 177 + } 178 + 179 + int 180 + mousecfg_get_field(struct wsmouse_parameters *field) 181 + { 182 + int i, n; 183 + 184 + for (i = 0; i < field->nparams; i++) { 185 + if ((n = index_of(field->params[i].key)) >= 0) 186 + field->params[i].value = cfg_buffer[n].value; 187 + else 188 + return (-1); 189 + } 190 + return (0); 191 + } 192 + 193 + int 194 + mousecfg_put_field(int fd, struct wsmouse_parameters *field) 195 + { 196 + int i, n, d, err; 197 + 198 + d = 0; 199 + for (i = 0; i < field->nparams; i++) 200 + if ((n = index_of(field->params[i].key)) < 0) 201 + return (-1); 202 + else 203 + d |= (cfg_buffer[n].value != field->params[i].value); 204 + 205 + if (!d) 206 + return (0); 207 + 208 + /* Write and read back immediately, wsmouse may normalize values. */ 209 + if ((err = ioctl(fd, WSMOUSEIO_SETPARAMS, field)) 210 + || (err = ioctl(fd, WSMOUSEIO_GETPARAMS, field))) 211 + return err; 212 + 213 + for (i = 0; i < field->nparams; i++) 214 + cfg_buffer[n].value = field->params[i].value; 215 + 216 + return (0); 217 + } 218 + 219 + static int 220 + get_value(struct wsmouse_parameters *field, enum wsmousecfg key) 221 + { 222 + int i; 223 + 224 + for (i = 0; i < field->nparams && key != field->params[i].key; i++) {} 225 + 226 + return (i < field->nparams ? field->params[i].value : 0); 227 + } 228 + 229 + static void 230 + set_value(struct wsmouse_parameters *field, enum wsmousecfg key, int value) 231 + { 232 + int i; 233 + 234 + for (i = 0; i < field->nparams && key != field->params[i].key; i++) {} 235 + 236 + field->params[i].value = (i < field->nparams ? value : 0); 237 + } 238 + 239 + /* 240 + * Read or write up to four raw parameter values. In this case 241 + * reading is a 'put' operation that writes back a value from the 242 + * buffer. 243 + */ 244 + static int 245 + read_param(struct wsmouse_parameters *field, char *val) 246 + { 247 + int i, j, n; 248 + 249 + n = sscanf(val, "%d:%d,%d:%d,%d:%d,%d:%d", 250 + &field->params[0].key, &field->params[0].value, 251 + &field->params[1].key, &field->params[1].value, 252 + &field->params[2].key, &field->params[2].value, 253 + &field->params[3].key, &field->params[3].value); 254 + if (n > 0 && (n & 1) == 0) { 255 + n /= 2; 256 + for (i = 0; i < n; i++) { 257 + if (index_of(field->params[i].key) < 0) 258 + return (-1); 259 + } 260 + field->nparams = n; 261 + return (0); 262 + } 263 + n = sscanf(val, "%d,%d,%d,%d", 264 + &field->params[0].key, &field->params[1].key, 265 + &field->params[2].key, &field->params[3].key); 266 + if (n > 0) { 267 + for (i = 0; i < n; i++) { 268 + if ((j = index_of(field->params[i].key)) < 0) 269 + return (-1); 270 + field->params[i].value = cfg_buffer[j].value; 271 + } 272 + field->nparams = n; 273 + return (0); 274 + } 275 + return (-1); 276 + } 277 + 278 + void 279 + mousecfg_pr_field(struct wsmouse_parameters *field) 280 + { 281 + int i, value; 282 + float f; 283 + 284 + if (field == &cfg_param) { 285 + for (i = 0; i < field->nparams; i++) 286 + printf(i > 0 ? ",%d:%d" : "%d:%d", 287 + field->params[i].key, 288 + field->params[i].value); 289 + return; 290 + } 291 + 292 + if (field == &cfg_scaling) { 293 + value = get_value(field, WSMOUSECFG_DX_SCALE); 294 + f = (float) value / 4096; 295 + printf("%.3f", f); 296 + return; 297 + } 298 + 299 + for (i = 0; i < field->nparams; i++) 300 + printf(i > 0 ? ",%d" : "%d", field->params[i].value); 301 + } 302 + 303 + void 304 + mousecfg_rd_field(struct wsmouse_parameters *field, char *val) 305 + { 306 + enum wsmousecfg first = field->params[0].key; 307 + int i, n; 308 + const char *s; 309 + float f; 310 + 311 + if (field == &cfg_param) { 312 + if (read_param(field, val)) 313 + errx(1, "invalid input (param)"); 314 + return; 315 + } 316 + 317 + if (field == &cfg_scaling) { 318 + if (sscanf(val, "%f", &f) == 1) { 319 + n = (int) (f * 4096); 320 + set_value(field, WSMOUSECFG_DX_SCALE, n); 321 + if (cfg_horiz_res && cfg_vert_res) 322 + n = n * cfg_horiz_res / cfg_vert_res; 323 + set_value(field, WSMOUSECFG_DY_SCALE, n); 324 + } else { 325 + errx(1, "invalid input (scaling)"); 326 + } 327 + return; 328 + } 329 + 330 + s = val; 331 + for (i = 0; i < field->nparams; i++) { 332 + if (sscanf(s, (i > 0 ? ",%d" : "%d"), &n) != 1) 333 + break; 334 + field->params[i].value = abs(n); 335 + for (s++; *s != '\0' && *s != ','; s++) {} 336 + } 337 + if (i < field->nparams || *s != '\0') 338 + errx(1, "invalid input '%s'", val); 339 + }
+29
sbin/wsconsctl/mousecfg.h
··· 1 + /* $OpenBSD: mousecfg.h,v 1.1 2017/07/21 20:38:20 bru Exp $ */ 2 + 3 + /* 4 + * Copyright (c) 2017 Ulf Brosziewski 5 + * 6 + * Permission to use, copy, modify, and distribute this software for any 7 + * purpose with or without fee is hereby granted, provided that the above 8 + * copyright notice and this permission notice appear in all copies. 9 + * 10 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 + */ 18 + 19 + extern struct wsmouse_parameters cfg_tapping; 20 + extern struct wsmouse_parameters cfg_scaling; 21 + extern struct wsmouse_parameters cfg_swapsides; 22 + extern struct wsmouse_parameters cfg_disable; 23 + extern struct wsmouse_parameters cfg_param; 24 + 25 + int mousecfg_init(int, const char **); 26 + int mousecfg_get_field(struct wsmouse_parameters *); 27 + int mousecfg_put_field(int, struct wsmouse_parameters *); 28 + void mousecfg_pr_field(struct wsmouse_parameters *); 29 + void mousecfg_rd_field(struct wsmouse_parameters *, char *);
+8 -1
sbin/wsconsctl/util.c
··· 1 - /* $OpenBSD: util.c,v 1.63 2016/02/10 05:49:50 guenther Exp $ */ 1 + /* $OpenBSD: util.c,v 1.64 2017/07/21 20:38:20 bru Exp $ */ 2 2 /* $NetBSD: util.c,v 1.8 2000/03/14 08:11:53 sato Exp $ */ 3 3 4 4 /*- ··· 40 40 #include <stdio.h> 41 41 #include <unistd.h> 42 42 #include "wsconsctl.h" 43 + #include "mousecfg.h" 43 44 44 45 #define TABLEN(t) (sizeof(t)/sizeof(t[0])) 45 46 ··· 309 310 case FMT_STRING: 310 311 printf("%s", (const char *)f->valp); 311 312 break; 313 + case FMT_CFG: 314 + mousecfg_pr_field((struct wsmouse_parameters *) f->valp); 315 + break; 312 316 default: 313 317 errx(1, "internal error: pr_field: no format %d", f->format); 314 318 break; ··· 461 465 } 462 466 case FMT_STRING: 463 467 strlcpy(f->valp, val, WSFONT_NAME_SIZE); 468 + break; 469 + case FMT_CFG: 470 + mousecfg_rd_field((struct wsmouse_parameters *) f->valp, val); 464 471 break; 465 472 default: 466 473 errx(1, "internal error: rd_field: no format %d", f->format);
+11 -4
sbin/wsconsctl/wsconsctl.c
··· 1 - /* $OpenBSD: wsconsctl.c,v 1.30 2017/04/06 17:33:39 jmc Exp $ */ 1 + /* $OpenBSD: wsconsctl.c,v 1.31 2017/07/21 20:38:20 bru Exp $ */ 2 2 /* $NetBSD: wsconsctl.c,v 1.2 1998/12/29 22:40:20 hannken Exp $ */ 3 3 4 4 /*- ··· 50 50 struct vartypesw { 51 51 const char *name; 52 52 struct field *field_tab; 53 + void (*init)(int,int); 53 54 void (*getval)(int); 54 55 int (*putval)(int); 55 56 char * (*nextdev)(int); 56 57 } typesw[] = { 57 - { "keyboard", keyboard_field_tab, 58 + { "keyboard", keyboard_field_tab, NULL, 58 59 keyboard_get_values, keyboard_put_values, keyboard_next_device }, 59 - { "mouse", mouse_field_tab, 60 + { "mouse", mouse_field_tab, mouse_init, 60 61 mouse_get_values, mouse_put_values, mouse_next_device }, 61 - { "display", display_field_tab, 62 + { "display", display_field_tab, NULL, 62 63 display_get_values, display_put_values, display_next_device }, 63 64 { NULL } 64 65 }; ··· 138 139 snprintf(devname, sizeof(devname), 139 140 "%s%d", sw->name, devidx); 140 141 142 + if (sw->init != NULL) 143 + (*sw->init)(devfd, devidx); 144 + 141 145 for (f = sw->field_tab; f->name; f++) 142 146 if (!(f->flags & 143 147 (FLG_NOAUTO|FLG_WRONLY))) ··· 188 192 else 189 193 snprintf(devname, sizeof(devname), 190 194 "%s%d", sw->name, devidx); 195 + 196 + if (sw->init != NULL) 197 + (*sw->init)(devfd, devidx); 191 198 192 199 p = strchr(argv[i], '='); 193 200 if (p == NULL) {
+3 -1
sbin/wsconsctl/wsconsctl.h
··· 1 - /* $OpenBSD: wsconsctl.h,v 1.15 2015/05/08 19:12:51 miod Exp $ */ 1 + /* $OpenBSD: wsconsctl.h,v 1.16 2017/07/21 20:38:20 bru Exp $ */ 2 2 /* $NetBSD: wsconsctl.h 1.1 1998/12/28 14:01:17 hannken Exp $ */ 3 3 4 4 /*- ··· 48 48 #define FMT_EMUL 107 /* wsdisplay emulations */ 49 49 #define FMT_SCREEN 108 /* wsdisplay screen types */ 50 50 #define FMT_STRING 109 /* free string */ 51 + #define FMT_CFG 201 /* wsmouse parameters */ 51 52 int format; 52 53 #define FLG_RDONLY 0x0001 /* variable cannot be modified */ 53 54 #define FLG_WRONLY 0x0002 /* variable cannot be displayed */ ··· 78 79 void keyboard_get_values(int); 79 80 int keyboard_put_values(int); 80 81 char * keyboard_next_device(int); 82 + void mouse_init(int,int); 81 83 void mouse_get_values(int); 82 84 int mouse_put_values(int); 83 85 char * mouse_next_device(int);