Home | History | Annotate | Line # | Download | only in wsconsctl
      1 /*	$NetBSD: mouse.c,v 1.11 2021/09/28 06:20:09 nia Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 1998, 2006, 2012 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Juergen Hannken-Illjes and Julio M. Merino Vidal.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/ioctl.h>
     33 #include <sys/time.h>
     34 #include <dev/wscons/wsconsio.h>
     35 
     36 #include <err.h>
     37 #include <errno.h>
     38 #include <limits.h>
     39 #include <stdio.h>
     40 #include <stdlib.h>
     41 #include <string.h>
     42 
     43 #include "wsconsctl.h"
     44 
     45 static int reverse_scrolling;
     46 static int horiz_scroll_dist;
     47 static int vert_scroll_dist;
     48 static int mstype;
     49 static int resolution;
     50 static int samplerate;
     51 static struct wsmouse_calibcoords calibration;
     52 static char *calibration_samples;
     53 static struct wsmouse_repeat repeat;
     54 
     55 static void mouse_get_parameters(int);
     56 static void mouse_put_parameters(int);
     57 
     58 static void mouse_get_calibration(int);
     59 static void mouse_put_calibration(int);
     60 
     61 static void mouse_get_repeat(int);
     62 static void mouse_put_repeat(int);
     63 
     64 struct field mouse_field_tab[] = {
     65     { "resolution",		&resolution,		FMT_UINT,	FLG_WRONLY },
     66     { "samplerate",		&samplerate,		FMT_UINT,	FLG_WRONLY },
     67     { "type",			&mstype,		FMT_MSTYPE,	FLG_RDONLY },
     68     { "scroll.reverse",		&reverse_scrolling,	FMT_INT,	FLG_MODIFY },
     69     { "scroll.distance.x",	&horiz_scroll_dist,	FMT_INT,	FLG_MODIFY },
     70     { "scroll.distance.y",	&vert_scroll_dist,	FMT_INT,	FLG_MODIFY },
     71     { "calibration.minx",	&calibration.minx,
     72     								FMT_INT,	FLG_MODIFY },
     73     { "calibration.miny",	&calibration.miny,
     74     							FMT_INT,	FLG_MODIFY },
     75     { "calibration.maxx",	&calibration.maxx,
     76     							FMT_INT,	FLG_MODIFY },
     77     { "calibration.maxy",	&calibration.maxy,
     78     							FMT_INT,	FLG_MODIFY },
     79     { "calibration.samples",	&calibration_samples,
     80 	    						FMT_STRING,	FLG_MODIFY },
     81     { "repeat.buttons",		&repeat.wr_buttons,
     82     							FMT_BITFIELD, FLG_MODIFY },
     83     { "repeat.delay.first",	&repeat.wr_delay_first,
     84     							FMT_UINT, FLG_MODIFY },
     85     { "repeat.delay.decrement",	&repeat.wr_delay_decrement,
     86     							FMT_UINT, FLG_MODIFY },
     87     { "repeat.delay.minimum",	&repeat.wr_delay_minimum,
     88  		   					FMT_UINT, FLG_MODIFY },
     89 };
     90 
     91 int mouse_field_tab_len = sizeof(mouse_field_tab)/
     92 			   sizeof(mouse_field_tab[0]);
     93 
     94 void
     95 mouse_get_values(int fd)
     96 {
     97 
     98 	if (field_by_value(&mstype)->flags & FLG_GET)
     99 		if (ioctl(fd, WSMOUSEIO_GTYPE, &mstype) < 0)
    100 			err(EXIT_FAILURE, "WSMOUSEIO_GTYPE");
    101 
    102 	if (field_by_value(&calibration.minx)->flags & FLG_GET ||
    103 	    field_by_value(&calibration.miny)->flags & FLG_GET ||
    104 	    field_by_value(&calibration.maxx)->flags & FLG_GET ||
    105 	    field_by_value(&calibration.maxy)->flags & FLG_GET ||
    106 	    field_by_value(&calibration_samples)->flags & FLG_GET)
    107 		mouse_get_calibration(fd);
    108 
    109 	if (field_by_value(&repeat.wr_buttons)->flags & FLG_GET ||
    110 	    field_by_value(&repeat.wr_delay_first)->flags & FLG_GET ||
    111 	    field_by_value(&repeat.wr_delay_decrement)->flags & FLG_GET ||
    112 	    field_by_value(&repeat.wr_delay_minimum)->flags & FLG_GET)
    113 		mouse_get_repeat(fd);
    114 
    115 	if (field_by_value(&horiz_scroll_dist)->flags & FLG_GET ||
    116 	    field_by_value(&vert_scroll_dist)->flags & FLG_GET ||
    117 	    field_by_value(&reverse_scrolling)->flags & FLG_GET)
    118 		mouse_get_parameters(fd);
    119 }
    120 
    121 static void
    122 mouse_get_parameters(int fd)
    123 {
    124 	struct wsmouse_param params[WSMOUSECFG_MAX];
    125 	struct wsmouse_parameters pl;
    126 	unsigned int i;
    127 
    128 	pl.nparams = 0;
    129 	pl.params = params;
    130 
    131 	if (field_by_value(&reverse_scrolling)->flags & FLG_GET)
    132 		params[pl.nparams++].key = WSMOUSECFG_REVERSE_SCROLLING;
    133 	if (field_by_value(&horiz_scroll_dist)->flags & FLG_GET)
    134 		params[pl.nparams++].key = WSMOUSECFG_HORIZSCROLLDIST;
    135 	if (field_by_value(&vert_scroll_dist)->flags & FLG_GET)
    136 		params[pl.nparams++].key = WSMOUSECFG_VERTSCROLLDIST;
    137 
    138 	if (ioctl(fd, WSMOUSEIO_GETPARAMS, &pl) < 0) {
    139 		if (field_by_value(&horiz_scroll_dist)->flags & FLG_GET)
    140 			field_disable_by_value(&horiz_scroll_dist);
    141 		if (field_by_value(&vert_scroll_dist)->flags & FLG_GET)
    142 			field_disable_by_value(&vert_scroll_dist);
    143 		if (field_by_value(&reverse_scrolling)->flags & FLG_GET)
    144 			field_disable_by_value(&reverse_scrolling);
    145 		return;
    146 	}
    147 
    148 	for (i = 0; i < pl.nparams; ++i) {
    149 		switch (params[i].key) {
    150 		case WSMOUSECFG_REVERSE_SCROLLING:
    151 			reverse_scrolling = params[i].value;
    152 			break;
    153 		case WSMOUSECFG_HORIZSCROLLDIST:
    154 			horiz_scroll_dist = params[i].value;
    155 			break;
    156 		case WSMOUSECFG_VERTSCROLLDIST:
    157 			vert_scroll_dist = params[i].value;
    158 			break;
    159 		}
    160 	}
    161 }
    162 
    163 static void
    164 mouse_get_calibration(int fd)
    165 {
    166 	struct wsmouse_calibcoords tmp;
    167 	char *samples;
    168 	char buf[48];
    169 	int i;
    170 
    171 	if (ioctl(fd, WSMOUSEIO_GCALIBCOORDS, &tmp) < 0) {
    172 		field_disable_by_value(&calibration.minx);
    173 		field_disable_by_value(&calibration.miny);
    174 		field_disable_by_value(&calibration.maxx);
    175 		field_disable_by_value(&calibration.maxy);
    176 		field_disable_by_value(&calibration_samples);
    177 		return;
    178 	}
    179 
    180 	if (field_by_value(&calibration.minx)->flags & FLG_GET)
    181 		calibration.minx = tmp.minx;
    182 	if (field_by_value(&calibration.miny)->flags & FLG_GET)
    183 		calibration.miny = tmp.miny;
    184 	if (field_by_value(&calibration.maxx)->flags & FLG_GET)
    185 		calibration.maxx = tmp.maxx;
    186 	if (field_by_value(&calibration.maxy)->flags & FLG_GET)
    187 		calibration.maxy = tmp.maxy;
    188 	if (field_by_value(&calibration_samples)->flags & FLG_GET) {
    189 		free(calibration_samples);
    190 		if (tmp.samplelen <= 0) {
    191 			calibration_samples = strdup("");
    192 			if (calibration_samples == NULL)
    193 				err(EXIT_FAILURE, "could not list calibration"
    194 						" samples");
    195 		} else {
    196 			samples = malloc(tmp.samplelen * sizeof(buf));
    197 			if (samples == NULL)
    198 				err(EXIT_FAILURE, "could not list calibration"
    199 						" samples");
    200 			samples[0] = '\0';
    201 			for (i = 0; i < tmp.samplelen; i++) {
    202 				snprintf(buf, sizeof(buf), "%s%d,%d,%d,%d",
    203 						(i == 0) ? "" : ":",
    204 						tmp.samples[i].rawx,
    205 						tmp.samples[i].rawy,
    206 						tmp.samples[i].x,
    207 						tmp.samples[i].y);
    208 				strcat(samples, buf);
    209 			}
    210 			calibration_samples = samples;
    211 		}
    212 	}
    213 }
    214 
    215 static void
    216 mouse_get_repeat(int fd)
    217 {
    218 	struct wsmouse_repeat tmp;
    219 
    220 	if (ioctl(fd, WSMOUSEIO_GETREPEAT, &tmp) < 0)
    221 		err(EXIT_FAILURE, "WSMOUSEIO_GETREPEAT");
    222 
    223 	if (field_by_value(&repeat.wr_buttons)->flags & FLG_GET)
    224 		repeat.wr_buttons = tmp.wr_buttons;
    225 	if (field_by_value(&repeat.wr_delay_first)->flags & FLG_GET)
    226 		repeat.wr_delay_first = tmp.wr_delay_first;
    227 	if (field_by_value(&repeat.wr_delay_decrement)->flags & FLG_GET)
    228 		repeat.wr_delay_decrement = tmp.wr_delay_decrement;
    229 	if (field_by_value(&repeat.wr_delay_minimum)->flags & FLG_GET)
    230 		repeat.wr_delay_minimum = tmp.wr_delay_minimum;
    231 }
    232 
    233 void
    234 mouse_put_values(int fd)
    235 {
    236 	int tmp;
    237 
    238 	if (field_by_value(&resolution)->flags & FLG_SET) {
    239 		tmp = resolution;
    240 		if (ioctl(fd, WSMOUSEIO_SRES, &tmp) < 0)
    241 			err(EXIT_FAILURE, "WSMOUSEIO_SRES");
    242 		pr_field(field_by_value(&resolution), " -> ");
    243 	}
    244 
    245 	if (field_by_value(&samplerate)->flags & FLG_SET) {
    246 		tmp = samplerate;
    247 		if (ioctl(fd, WSMOUSEIO_SRATE, &tmp) < 0)
    248 			err(EXIT_FAILURE, "WSMOUSEIO_SRATE");
    249 		pr_field(field_by_value(&samplerate), " -> ");
    250 	}
    251 
    252 	if (field_by_value(&calibration.minx)->flags & FLG_SET ||
    253 	    field_by_value(&calibration.miny)->flags & FLG_SET ||
    254 	    field_by_value(&calibration.maxx)->flags & FLG_SET ||
    255 	    field_by_value(&calibration.maxy)->flags & FLG_SET ||
    256 	    field_by_value(&calibration_samples)->flags & FLG_SET)
    257 		mouse_put_calibration(fd);
    258 
    259 	if (field_by_value(&repeat.wr_buttons)->flags & FLG_SET ||
    260 	    field_by_value(&repeat.wr_delay_first)->flags & FLG_SET ||
    261 	    field_by_value(&repeat.wr_delay_decrement)->flags & FLG_SET ||
    262 	    field_by_value(&repeat.wr_delay_minimum)->flags & FLG_SET)
    263 		mouse_put_repeat(fd);
    264 
    265 	if (field_by_value(&horiz_scroll_dist)->flags & FLG_SET ||
    266 	    field_by_value(&vert_scroll_dist)->flags & FLG_SET ||
    267 	    field_by_value(&reverse_scrolling)->flags & FLG_SET)
    268 		mouse_put_parameters(fd);
    269 }
    270 
    271 static void
    272 mouse_put_parameters(int fd)
    273 {
    274 	struct wsmouse_param params[WSMOUSECFG_MAX];
    275 	struct wsmouse_parameters pl;
    276 
    277 	pl.nparams = 0;
    278 	pl.params = params;
    279 
    280 	if (field_by_value(&reverse_scrolling)->flags & FLG_SET) {
    281 		params[pl.nparams].key = WSMOUSECFG_REVERSE_SCROLLING;
    282 		params[pl.nparams++].value = reverse_scrolling;
    283 	}
    284 
    285 	if (field_by_value(&horiz_scroll_dist)->flags & FLG_SET) {
    286 		params[pl.nparams].key = WSMOUSECFG_HORIZSCROLLDIST;
    287 		params[pl.nparams++].value = horiz_scroll_dist;
    288 	}
    289 
    290 	if (field_by_value(&vert_scroll_dist)->flags & FLG_SET) {
    291 		params[pl.nparams].key = WSMOUSECFG_VERTSCROLLDIST;
    292 		params[pl.nparams++].value = vert_scroll_dist;
    293 	}
    294 
    295 	if (ioctl(fd, WSMOUSEIO_SETPARAMS, &pl) < 0) {
    296 		if (field_by_value(&horiz_scroll_dist)->flags & FLG_SET)
    297 			field_disable_by_value(&horiz_scroll_dist);
    298 		if (field_by_value(&vert_scroll_dist)->flags & FLG_SET)
    299 			field_disable_by_value(&vert_scroll_dist);
    300 		if (field_by_value(&vert_scroll_dist)->flags & FLG_SET)
    301 			field_disable_by_value(&reverse_scrolling);
    302 		return;
    303 	}
    304 }
    305 
    306 static void
    307 mouse_put_calibration(int fd)
    308 {
    309 	struct wsmouse_calibcoords tmp;
    310 	int i;
    311 	const char *p;
    312 	char *q;
    313 
    314 	/* Fetch current values into the temporary structure. */
    315 	if (ioctl(fd, WSMOUSEIO_GCALIBCOORDS, &tmp) < 0)
    316 		err(EXIT_FAILURE, "WSMOUSEIO_GCALIBCOORDS");
    317 
    318 	/* Overwrite the desired values in the temporary structure. */
    319 	if (field_by_value(&calibration.minx)->flags & FLG_SET)
    320 		tmp.minx = calibration.minx;
    321 	if (field_by_value(&calibration.miny)->flags & FLG_SET)
    322 		tmp.miny = calibration.miny;
    323 	if (field_by_value(&calibration.maxx)->flags & FLG_SET)
    324 		tmp.maxx = calibration.maxx;
    325 	if (field_by_value(&calibration.maxy)->flags & FLG_SET)
    326 		tmp.maxy = calibration.maxy;
    327 	if (field_by_value(&calibration_samples)->flags & FLG_SET) {
    328 		p = calibration_samples;
    329 		for (i = 0; p[0] != '\0' && i < WSMOUSE_CALIBCOORDS_MAX; i++) {
    330 			tmp.samples[i].rawx = strtol(p, &q, 0);
    331 			if (*q != ',')
    332 				break;
    333 			p = q + 1;
    334 			tmp.samples[i].rawy = strtol(p, &q, 0);
    335 			if (*q != ',')
    336 				break;
    337 			p = q + 1;
    338 			tmp.samples[i].x = strtol(p, &q, 0);
    339 			if (*q != ',')
    340 				break;
    341 			p = q + 1;
    342 			tmp.samples[i].y = strtol(p, &q, 0);
    343 			p = q + 1;
    344 			if (*q != '\0' && *q != ':')
    345 				break;
    346 		}
    347 		if (p[0] != '\0')
    348 			errx(EXIT_FAILURE, "%s: invalid calibration data",
    349 					calibration_samples);
    350 		tmp.samplelen = i;
    351 	}
    352 
    353 	/* Set new values for calibrating events. */
    354 	if (ioctl(fd, WSMOUSEIO_SCALIBCOORDS, &tmp) < 0)
    355 		err(EXIT_FAILURE, "WSMOUSEIO_SCALIBCOORDS");
    356 
    357 	/* Now print what changed. */
    358 	if (field_by_value(&calibration.minx)->flags & FLG_SET)
    359 		pr_field(field_by_value(&calibration.minx), " -> ");
    360 	if (field_by_value(&calibration.miny)->flags & FLG_SET)
    361 		pr_field(field_by_value(&calibration.miny), " -> ");
    362 	if (field_by_value(&calibration.maxx)->flags & FLG_SET)
    363 		pr_field(field_by_value(&calibration.maxx), " -> ");
    364 	if (field_by_value(&calibration.maxy)->flags & FLG_SET)
    365 		pr_field(field_by_value(&calibration.maxy), " -> ");
    366 	if (field_by_value(&calibration_samples)->flags & FLG_SET)
    367 		pr_field(field_by_value(&calibration_samples), " -> ");
    368 }
    369 
    370 static void
    371 mouse_put_repeat(int fd)
    372 {
    373 	struct wsmouse_repeat tmp;
    374 
    375 	/* Fetch current values into the temporary structure. */
    376 	if (ioctl(fd, WSMOUSEIO_GETREPEAT, &tmp) < 0)
    377 		err(EXIT_FAILURE, "WSMOUSEIO_GETREPEAT");
    378 
    379 	/* Overwrite the desired values in the temporary structure. */
    380 	if (field_by_value(&repeat.wr_buttons)->flags & FLG_SET)
    381 		tmp.wr_buttons = repeat.wr_buttons;
    382 	if (field_by_value(&repeat.wr_delay_first)->flags & FLG_SET)
    383 		tmp.wr_delay_first = repeat.wr_delay_first;
    384 	if (field_by_value(&repeat.wr_delay_decrement)->flags & FLG_SET)
    385 		tmp.wr_delay_decrement = repeat.wr_delay_decrement;
    386 	if (field_by_value(&repeat.wr_delay_minimum)->flags & FLG_SET)
    387 		tmp.wr_delay_minimum = repeat.wr_delay_minimum;
    388 
    389 	/* Set new values for repeating events. */
    390 	if (ioctl(fd, WSMOUSEIO_SETREPEAT, &tmp) < 0)
    391 		err(EXIT_FAILURE, "WSMOUSEIO_SETREPEAT");
    392 
    393 	/* Now print what changed. */
    394 	if (field_by_value(&repeat.wr_buttons)->flags & FLG_SET)
    395 		pr_field(field_by_value(&repeat.wr_buttons), " -> ");
    396 	if (field_by_value(&repeat.wr_delay_first)->flags & FLG_SET)
    397 		pr_field(field_by_value(&repeat.wr_delay_first), " -> ");
    398 	if (field_by_value(&repeat.wr_delay_decrement)->flags & FLG_SET)
    399 		pr_field(field_by_value(&repeat.wr_delay_decrement), " -> ");
    400 	if (field_by_value(&repeat.wr_delay_minimum)->flags & FLG_SET)
    401 		pr_field(field_by_value(&repeat.wr_delay_minimum), " -> ");
    402 }
    403