xref: /netbsd-src/sbin/wsconsctl/mouse.c (revision 82d56013d7b633d116a93943de88e08335357a7c)
1 /*	$NetBSD: mouse.c,v 1.10 2012/12/24 01:29:20 khorben 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 mstype;
46 static int resolution;
47 static int samplerate;
48 static struct wsmouse_calibcoords calibration;
49 static char *calibration_samples;
50 static struct wsmouse_repeat repeat;
51 
52 static void mouse_get_calibration(int);
53 static void mouse_put_calibration(int);
54 
55 static void mouse_get_repeat(int);
56 static void mouse_put_repeat(int);
57 
58 struct field mouse_field_tab[] = {
59     { "resolution",		&resolution,	FMT_UINT,	FLG_WRONLY },
60     { "samplerate",		&samplerate,	FMT_UINT,	FLG_WRONLY },
61     { "type",			&mstype,	FMT_MSTYPE,	FLG_RDONLY },
62     { "calibration.minx",	&calibration.minx,
63     						FMT_INT,	FLG_MODIFY },
64     { "calibration.miny",	&calibration.miny,
65     						FMT_INT,	FLG_MODIFY },
66     { "calibration.maxx",	&calibration.maxx,
67     						FMT_INT,	FLG_MODIFY },
68     { "calibration.maxy",	&calibration.maxy,
69     						FMT_INT,	FLG_MODIFY },
70     { "calibration.samples",	&calibration_samples,
71 	    					FMT_STRING,	FLG_MODIFY },
72     { "repeat.buttons",		&repeat.wr_buttons,
73     						FMT_BITFIELD, FLG_MODIFY },
74     { "repeat.delay.first",	&repeat.wr_delay_first,
75     						FMT_UINT, FLG_MODIFY },
76     { "repeat.delay.decrement",	&repeat.wr_delay_decrement,
77     						FMT_UINT, FLG_MODIFY },
78     { "repeat.delay.minimum",	&repeat.wr_delay_minimum,
79  		   				FMT_UINT, FLG_MODIFY },
80 };
81 
82 int mouse_field_tab_len = sizeof(mouse_field_tab)/
83 			   sizeof(mouse_field_tab[0]);
84 
85 void
86 mouse_get_values(int fd)
87 {
88 
89 	if (field_by_value(&mstype)->flags & FLG_GET)
90 		if (ioctl(fd, WSMOUSEIO_GTYPE, &mstype) < 0)
91 			err(EXIT_FAILURE, "WSMOUSEIO_GTYPE");
92 
93 	if (field_by_value(&calibration.minx)->flags & FLG_GET ||
94 	    field_by_value(&calibration.miny)->flags & FLG_GET ||
95 	    field_by_value(&calibration.maxx)->flags & FLG_GET ||
96 	    field_by_value(&calibration.maxy)->flags & FLG_GET ||
97 	    field_by_value(&calibration_samples)->flags & FLG_GET)
98 		mouse_get_calibration(fd);
99 
100 	if (field_by_value(&repeat.wr_buttons)->flags & FLG_GET ||
101 	    field_by_value(&repeat.wr_delay_first)->flags & FLG_GET ||
102 	    field_by_value(&repeat.wr_delay_decrement)->flags & FLG_GET ||
103 	    field_by_value(&repeat.wr_delay_minimum)->flags & FLG_GET)
104 		mouse_get_repeat(fd);
105 }
106 
107 static void
108 mouse_get_calibration(int fd)
109 {
110 	struct wsmouse_calibcoords tmp;
111 	char *samples;
112 	char buf[48];
113 	int i;
114 
115 	if (ioctl(fd, WSMOUSEIO_GCALIBCOORDS, &tmp) < 0) {
116 		field_disable_by_value(&calibration.minx);
117 		field_disable_by_value(&calibration.miny);
118 		field_disable_by_value(&calibration.maxx);
119 		field_disable_by_value(&calibration.maxy);
120 		field_disable_by_value(&calibration_samples);
121 		return;
122 	}
123 
124 	if (field_by_value(&calibration.minx)->flags & FLG_GET)
125 		calibration.minx = tmp.minx;
126 	if (field_by_value(&calibration.miny)->flags & FLG_GET)
127 		calibration.miny = tmp.miny;
128 	if (field_by_value(&calibration.maxx)->flags & FLG_GET)
129 		calibration.maxx = tmp.maxx;
130 	if (field_by_value(&calibration.maxy)->flags & FLG_GET)
131 		calibration.maxy = tmp.maxy;
132 	if (field_by_value(&calibration_samples)->flags & FLG_GET) {
133 		free(calibration_samples);
134 		if (tmp.samplelen <= 0) {
135 			calibration_samples = strdup("");
136 			if (calibration_samples == NULL)
137 				err(EXIT_FAILURE, "could not list calibration"
138 						" samples");
139 		} else {
140 			samples = malloc(tmp.samplelen * sizeof(buf));
141 			if (samples == NULL)
142 				err(EXIT_FAILURE, "could not list calibration"
143 						" samples");
144 			samples[0] = '\0';
145 			for (i = 0; i < tmp.samplelen; i++) {
146 				snprintf(buf, sizeof(buf), "%s%d,%d,%d,%d",
147 						(i == 0) ? "" : ":",
148 						tmp.samples[i].rawx,
149 						tmp.samples[i].rawy,
150 						tmp.samples[i].x,
151 						tmp.samples[i].y);
152 				strcat(samples, buf);
153 			}
154 			calibration_samples = samples;
155 		}
156 	}
157 }
158 
159 static void
160 mouse_get_repeat(int fd)
161 {
162 	struct wsmouse_repeat tmp;
163 
164 	if (ioctl(fd, WSMOUSEIO_GETREPEAT, &tmp) < 0)
165 		err(EXIT_FAILURE, "WSMOUSEIO_GETREPEAT");
166 
167 	if (field_by_value(&repeat.wr_buttons)->flags & FLG_GET)
168 		repeat.wr_buttons = tmp.wr_buttons;
169 	if (field_by_value(&repeat.wr_delay_first)->flags & FLG_GET)
170 		repeat.wr_delay_first = tmp.wr_delay_first;
171 	if (field_by_value(&repeat.wr_delay_decrement)->flags & FLG_GET)
172 		repeat.wr_delay_decrement = tmp.wr_delay_decrement;
173 	if (field_by_value(&repeat.wr_delay_minimum)->flags & FLG_GET)
174 		repeat.wr_delay_minimum = tmp.wr_delay_minimum;
175 }
176 
177 void
178 mouse_put_values(int fd)
179 {
180 	int tmp;
181 
182 	if (field_by_value(&resolution)->flags & FLG_SET) {
183 		tmp = resolution;
184 		if (ioctl(fd, WSMOUSEIO_SRES, &tmp) < 0)
185 			err(EXIT_FAILURE, "WSMOUSEIO_SRES");
186 		pr_field(field_by_value(&resolution), " -> ");
187 	}
188 
189 	if (field_by_value(&samplerate)->flags & FLG_SET) {
190 		tmp = samplerate;
191 		if (ioctl(fd, WSMOUSEIO_SRATE, &tmp) < 0)
192 			err(EXIT_FAILURE, "WSMOUSEIO_SRATE");
193 		pr_field(field_by_value(&samplerate), " -> ");
194 	}
195 
196 	if (field_by_value(&calibration.minx)->flags & FLG_SET ||
197 	    field_by_value(&calibration.miny)->flags & FLG_SET ||
198 	    field_by_value(&calibration.maxx)->flags & FLG_SET ||
199 	    field_by_value(&calibration.maxy)->flags & FLG_SET ||
200 	    field_by_value(&calibration_samples)->flags & FLG_SET)
201 		mouse_put_calibration(fd);
202 
203 	if (field_by_value(&repeat.wr_buttons)->flags & FLG_SET ||
204 	    field_by_value(&repeat.wr_delay_first)->flags & FLG_SET ||
205 	    field_by_value(&repeat.wr_delay_decrement)->flags & FLG_SET ||
206 	    field_by_value(&repeat.wr_delay_minimum)->flags & FLG_SET)
207 		mouse_put_repeat(fd);
208 }
209 
210 static void
211 mouse_put_calibration(int fd)
212 {
213 	struct wsmouse_calibcoords tmp;
214 	int i;
215 	const char *p;
216 	char *q;
217 
218 	/* Fetch current values into the temporary structure. */
219 	if (ioctl(fd, WSMOUSEIO_GCALIBCOORDS, &tmp) < 0)
220 		err(EXIT_FAILURE, "WSMOUSEIO_GCALIBCOORDS");
221 
222 	/* Overwrite the desired values in the temporary structure. */
223 	if (field_by_value(&calibration.minx)->flags & FLG_SET)
224 		tmp.minx = calibration.minx;
225 	if (field_by_value(&calibration.miny)->flags & FLG_SET)
226 		tmp.miny = calibration.miny;
227 	if (field_by_value(&calibration.maxx)->flags & FLG_SET)
228 		tmp.maxx = calibration.maxx;
229 	if (field_by_value(&calibration.maxy)->flags & FLG_SET)
230 		tmp.maxy = calibration.maxy;
231 	if (field_by_value(&calibration_samples)->flags & FLG_SET) {
232 		p = calibration_samples;
233 		for (i = 0; p[0] != '\0' && i < WSMOUSE_CALIBCOORDS_MAX; i++) {
234 			tmp.samples[i].rawx = strtol(p, &q, 0);
235 			if (*q != ',')
236 				break;
237 			p = q + 1;
238 			tmp.samples[i].rawy = strtol(p, &q, 0);
239 			if (*q != ',')
240 				break;
241 			p = q + 1;
242 			tmp.samples[i].x = strtol(p, &q, 0);
243 			if (*q != ',')
244 				break;
245 			p = q + 1;
246 			tmp.samples[i].y = strtol(p, &q, 0);
247 			p = q + 1;
248 			if (*q != '\0' && *q != ':')
249 				break;
250 		}
251 		if (p[0] != '\0')
252 			errx(EXIT_FAILURE, "%s: invalid calibration data",
253 					calibration_samples);
254 		tmp.samplelen = i;
255 	}
256 
257 	/* Set new values for calibrating events. */
258 	if (ioctl(fd, WSMOUSEIO_SCALIBCOORDS, &tmp) < 0)
259 		err(EXIT_FAILURE, "WSMOUSEIO_SCALIBCOORDS");
260 
261 	/* Now print what changed. */
262 	if (field_by_value(&calibration.minx)->flags & FLG_SET)
263 		pr_field(field_by_value(&calibration.minx), " -> ");
264 	if (field_by_value(&calibration.miny)->flags & FLG_SET)
265 		pr_field(field_by_value(&calibration.miny), " -> ");
266 	if (field_by_value(&calibration.maxx)->flags & FLG_SET)
267 		pr_field(field_by_value(&calibration.maxx), " -> ");
268 	if (field_by_value(&calibration.maxy)->flags & FLG_SET)
269 		pr_field(field_by_value(&calibration.maxy), " -> ");
270 	if (field_by_value(&calibration_samples)->flags & FLG_SET)
271 		pr_field(field_by_value(&calibration_samples), " -> ");
272 }
273 
274 static void
275 mouse_put_repeat(int fd)
276 {
277 	struct wsmouse_repeat tmp;
278 
279 	/* Fetch current values into the temporary structure. */
280 	if (ioctl(fd, WSMOUSEIO_GETREPEAT, &tmp) < 0)
281 		err(EXIT_FAILURE, "WSMOUSEIO_GETREPEAT");
282 
283 	/* Overwrite the desired values in the temporary structure. */
284 	if (field_by_value(&repeat.wr_buttons)->flags & FLG_SET)
285 		tmp.wr_buttons = repeat.wr_buttons;
286 	if (field_by_value(&repeat.wr_delay_first)->flags & FLG_SET)
287 		tmp.wr_delay_first = repeat.wr_delay_first;
288 	if (field_by_value(&repeat.wr_delay_decrement)->flags & FLG_SET)
289 		tmp.wr_delay_decrement = repeat.wr_delay_decrement;
290 	if (field_by_value(&repeat.wr_delay_minimum)->flags & FLG_SET)
291 		tmp.wr_delay_minimum = repeat.wr_delay_minimum;
292 
293 	/* Set new values for repeating events. */
294 	if (ioctl(fd, WSMOUSEIO_SETREPEAT, &tmp) < 0)
295 		err(EXIT_FAILURE, "WSMOUSEIO_SETREPEAT");
296 
297 	/* Now print what changed. */
298 	if (field_by_value(&repeat.wr_buttons)->flags & FLG_SET)
299 		pr_field(field_by_value(&repeat.wr_buttons), " -> ");
300 	if (field_by_value(&repeat.wr_delay_first)->flags & FLG_SET)
301 		pr_field(field_by_value(&repeat.wr_delay_first), " -> ");
302 	if (field_by_value(&repeat.wr_delay_decrement)->flags & FLG_SET)
303 		pr_field(field_by_value(&repeat.wr_delay_decrement), " -> ");
304 	if (field_by_value(&repeat.wr_delay_minimum)->flags & FLG_SET)
305 		pr_field(field_by_value(&repeat.wr_delay_minimum), " -> ");
306 }
307