xref: /dflybsd-src/sys/dev/misc/syscons/scmouse.c (revision b721b9ee4205a28b1f2d01b5c95851add56bf82b)
1 /*-
2  * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer as
10  *    the first lines of this file unmodified.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * $FreeBSD: src/sys/dev/syscons/scmouse.c,v 1.12.2.3 2001/07/28 12:51:47 yokota Exp $
27  * $DragonFly: src/sys/dev/misc/syscons/scmouse.c,v 1.8 2005/03/28 21:30:23 swildner Exp $
28  */
29 
30 #include "opt_syscons.h"
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/conf.h>
35 #include <sys/signalvar.h>
36 #include <sys/proc.h>
37 #include <sys/tty.h>
38 
39 #include <machine/console.h>
40 #include <machine/mouse.h>
41 
42 #include "syscons.h"
43 
44 #ifdef SC_TWOBUTTON_MOUSE
45 #define SC_MOUSE_PASTEBUTTON	MOUSE_BUTTON3DOWN	/* right button */
46 #define SC_MOUSE_EXTENDBUTTON	MOUSE_BUTTON2DOWN	/* not really used */
47 #else
48 #define SC_MOUSE_PASTEBUTTON	MOUSE_BUTTON2DOWN	/* middle button */
49 #define SC_MOUSE_EXTENDBUTTON	MOUSE_BUTTON3DOWN	/* right button */
50 #endif /* SC_TWOBUTTON_MOUSE */
51 
52 #define SC_WAKEUP_DELTA		20
53 
54 #ifndef SC_NO_SYSMOUSE
55 
56 /* local variables */
57 static int		cut_buffer_size;
58 static u_char		*cut_buffer;
59 
60 /* local functions */
61 static void set_mouse_pos(scr_stat *scp);
62 #ifndef SC_NO_CUTPASTE
63 static int skip_spc_right(scr_stat *scp, int p);
64 static int skip_spc_left(scr_stat *scp, int p);
65 static void mouse_cut(scr_stat *scp);
66 static void mouse_cut_start(scr_stat *scp);
67 static void mouse_cut_end(scr_stat *scp);
68 static void mouse_cut_word(scr_stat *scp);
69 static void mouse_cut_line(scr_stat *scp);
70 static void mouse_cut_extend(scr_stat *scp);
71 static void mouse_paste(scr_stat *scp);
72 #endif /* SC_NO_CUTPASTE */
73 
74 #ifndef SC_NO_CUTPASTE
75 /* allocate a cut buffer */
76 void
77 sc_alloc_cut_buffer(scr_stat *scp, int wait)
78 {
79     u_char *p;
80 
81     if ((cut_buffer == NULL)
82 	|| (cut_buffer_size < scp->xsize * scp->ysize + 1)) {
83 	p = cut_buffer;
84 	cut_buffer = NULL;
85 	if (p != NULL)
86 	    free(p, M_SYSCONS);
87 	cut_buffer_size = scp->xsize * scp->ysize + 1;
88 	p = malloc(cut_buffer_size, M_SYSCONS, (wait) ? M_WAITOK : M_NOWAIT);
89 	if (p != NULL)
90 	    p[0] = '\0';
91 	cut_buffer = p;
92     }
93 }
94 #endif /* SC_NO_CUTPASTE */
95 
96 /* move mouse */
97 void
98 sc_mouse_move(scr_stat *scp, int x, int y)
99 {
100     int s;
101 
102     s = spltty();
103     scp->mouse_xpos = scp->mouse_oldxpos = x;
104     scp->mouse_ypos = scp->mouse_oldypos = y;
105     if (scp->font_size <= 0)
106 	scp->mouse_pos = scp->mouse_oldpos = 0;
107     else
108 	scp->mouse_pos = scp->mouse_oldpos =
109 	    (y/scp->font_size - scp->yoff)*scp->xsize + x/8 - scp->xoff;
110     scp->status |= MOUSE_MOVED;
111     splx(s);
112 }
113 
114 /* adjust mouse position */
115 static void
116 set_mouse_pos(scr_stat *scp)
117 {
118     if (scp->mouse_xpos < scp->xoff*8)
119 	scp->mouse_xpos = scp->xoff*8;
120     if (scp->mouse_ypos < scp->yoff*scp->font_size)
121 	scp->mouse_ypos = scp->yoff*scp->font_size;
122     if (ISGRAPHSC(scp)) {
123         if (scp->mouse_xpos > scp->xpixel-1)
124 	    scp->mouse_xpos = scp->xpixel-1;
125         if (scp->mouse_ypos > scp->ypixel-1)
126 	    scp->mouse_ypos = scp->ypixel-1;
127 	return;
128     } else {
129 	if (scp->mouse_xpos > (scp->xsize + scp->xoff)*8 - 1)
130 	    scp->mouse_xpos = (scp->xsize + scp->xoff)*8 - 1;
131 	if (scp->mouse_ypos > (scp->ysize + scp->yoff)*scp->font_size - 1)
132 	    scp->mouse_ypos = (scp->ysize + scp->yoff)*scp->font_size - 1;
133     }
134 
135     if (scp->mouse_xpos != scp->mouse_oldxpos || scp->mouse_ypos != scp->mouse_oldypos) {
136 	scp->status |= MOUSE_MOVED;
137     	scp->mouse_pos =
138 	    (scp->mouse_ypos/scp->font_size - scp->yoff)*scp->xsize
139 		+ scp->mouse_xpos/8 - scp->xoff;
140 #ifndef SC_NO_CUTPASTE
141 	if ((scp->status & MOUSE_VISIBLE) && (scp->status & MOUSE_CUTTING))
142 	    mouse_cut(scp);
143 #endif
144     }
145 }
146 
147 #ifndef SC_NO_CUTPASTE
148 
149 void
150 sc_draw_mouse_image(scr_stat *scp)
151 {
152     if (ISGRAPHSC(scp))
153 	return;
154 
155     ++scp->sc->videoio_in_progress;
156     (*scp->rndr->draw_mouse)(scp, scp->mouse_xpos, scp->mouse_ypos, TRUE);
157     scp->mouse_oldpos = scp->mouse_pos;
158     scp->mouse_oldxpos = scp->mouse_xpos;
159     scp->mouse_oldypos = scp->mouse_ypos;
160     scp->status |= MOUSE_VISIBLE;
161     --scp->sc->videoio_in_progress;
162 }
163 
164 void
165 sc_remove_mouse_image(scr_stat *scp)
166 {
167     int size;
168     int i;
169 
170     if (ISGRAPHSC(scp))
171 	return;
172 
173     ++scp->sc->videoio_in_progress;
174     (*scp->rndr->draw_mouse)(scp,
175 			     (scp->mouse_oldpos%scp->xsize + scp->xoff)*8,
176 			     (scp->mouse_oldpos/scp->xsize + scp->yoff)
177 				 * scp->font_size,
178 			     FALSE);
179     size = scp->xsize*scp->ysize;
180     i = scp->mouse_oldpos;
181     mark_for_update(scp, i);
182     mark_for_update(scp, i);
183     if (i + scp->xsize + 1 < size) {
184 	mark_for_update(scp, i + scp->xsize + 1);
185     } else if (i + scp->xsize < size) {
186 	mark_for_update(scp, i + scp->xsize);
187     } else if (i + 1 < size) {
188 	mark_for_update(scp, i + 1);
189     }
190     scp->status &= ~MOUSE_VISIBLE;
191     --scp->sc->videoio_in_progress;
192 }
193 
194 int
195 sc_inside_cutmark(scr_stat *scp, int pos)
196 {
197     int start;
198     int end;
199 
200     if (scp->mouse_cut_end < 0)
201 	return FALSE;
202     if (scp->mouse_cut_start <= scp->mouse_cut_end) {
203 	start = scp->mouse_cut_start;
204 	end = scp->mouse_cut_end;
205     } else {
206 	start = scp->mouse_cut_end;
207 	end = scp->mouse_cut_start - 1;
208     }
209     return ((start <= pos) && (pos <= end));
210 }
211 
212 void
213 sc_remove_cutmarking(scr_stat *scp)
214 {
215     int s;
216 
217     s = spltty();
218     if (scp->mouse_cut_end >= 0) {
219 	mark_for_update(scp, scp->mouse_cut_start);
220 	mark_for_update(scp, scp->mouse_cut_end);
221     }
222     scp->mouse_cut_start = scp->xsize*scp->ysize;
223     scp->mouse_cut_end = -1;
224     splx(s);
225     scp->status &= ~MOUSE_CUTTING;
226 }
227 
228 void
229 sc_remove_all_cutmarkings(sc_softc_t *sc)
230 {
231     scr_stat *scp;
232     int i;
233 
234     /* delete cut markings in all vtys */
235     for (i = 0; i < sc->vtys; ++i) {
236 	scp = SC_STAT(sc->dev[i]);
237 	if (scp == NULL)
238 	    continue;
239 	sc_remove_cutmarking(scp);
240     }
241 }
242 
243 void
244 sc_remove_all_mouse(sc_softc_t *sc)
245 {
246     scr_stat *scp;
247     int i;
248 
249     for (i = 0; i < sc->vtys; ++i) {
250 	scp = SC_STAT(sc->dev[i]);
251 	if (scp == NULL)
252 	    continue;
253 	if (scp->status & MOUSE_VISIBLE) {
254 	    scp->status &= ~MOUSE_VISIBLE;
255 	    mark_all(scp);
256 	}
257     }
258 }
259 
260 #define IS_SPACE_CHAR(c)	(((c) & 0xff) == ' ')
261 
262 /* skip spaces to right */
263 static int
264 skip_spc_right(scr_stat *scp, int p)
265 {
266     int c;
267     int i;
268 
269     for (i = p % scp->xsize; i < scp->xsize; ++i) {
270 	c = sc_vtb_getc(&scp->vtb, p);
271 	if (!IS_SPACE_CHAR(c))
272 	    break;
273 	++p;
274     }
275     return i;
276 }
277 
278 /* skip spaces to left */
279 static int
280 skip_spc_left(scr_stat *scp, int p)
281 {
282     int c;
283     int i;
284 
285     for (i = p-- % scp->xsize - 1; i >= 0; --i) {
286 	c = sc_vtb_getc(&scp->vtb, p);
287 	if (!IS_SPACE_CHAR(c))
288 	    break;
289 	--p;
290     }
291     return i;
292 }
293 
294 /* copy marked region to the cut buffer */
295 static void
296 mouse_cut(scr_stat *scp)
297 {
298     int start;
299     int end;
300     int from;
301     int to;
302     int blank;
303     int c;
304     int p;
305     int s;
306     int i;
307 
308     start = scp->mouse_cut_start;
309     end = scp->mouse_cut_end;
310     if (scp->mouse_pos >= start) {
311 	from = start;
312 	to = end = scp->mouse_pos;
313     } else {
314 	from = end = scp->mouse_pos;
315 	to = start - 1;
316     }
317     for (p = from, i = blank = 0; p <= to; ++p) {
318 	cut_buffer[i] = sc_vtb_getc(&scp->vtb, p);
319 	/* remember the position of the last non-space char */
320 	if (!IS_SPACE_CHAR(cut_buffer[i++]))
321 	    blank = i;		/* the first space after the last non-space */
322 	/* trim trailing blank when crossing lines */
323 	if ((p % scp->xsize) == (scp->xsize - 1)) {
324 	    cut_buffer[blank] = '\r';
325 	    i = blank + 1;
326 	}
327     }
328     cut_buffer[i] = '\0';
329 
330     /* scan towards the end of the last line */
331     --p;
332     for (i = p % scp->xsize; i < scp->xsize; ++i) {
333 	c = sc_vtb_getc(&scp->vtb, p);
334 	if (!IS_SPACE_CHAR(c))
335 	    break;
336 	++p;
337     }
338     /* if there is nothing but blank chars, trim them, but mark towards eol */
339     if (i >= scp->xsize) {
340 	if (end >= start)
341 	    to = end = p - 1;
342 	else
343 	    to = start = p;
344 	cut_buffer[blank++] = '\r';
345 	cut_buffer[blank] = '\0';
346     }
347 
348     /* remove the current marking */
349     s = spltty();
350     if (scp->mouse_cut_start <= scp->mouse_cut_end) {
351 	mark_for_update(scp, scp->mouse_cut_start);
352 	mark_for_update(scp, scp->mouse_cut_end);
353     } else if (scp->mouse_cut_end >= 0) {
354 	mark_for_update(scp, scp->mouse_cut_end);
355 	mark_for_update(scp, scp->mouse_cut_start);
356     }
357 
358     /* mark the new region */
359     scp->mouse_cut_start = start;
360     scp->mouse_cut_end = end;
361     mark_for_update(scp, from);
362     mark_for_update(scp, to);
363     splx(s);
364 }
365 
366 /* a mouse button is pressed, start cut operation */
367 static void
368 mouse_cut_start(scr_stat *scp)
369 {
370     int i;
371     int j;
372     int s;
373 
374     if (scp->status & MOUSE_VISIBLE) {
375 	i = scp->mouse_cut_start;
376 	j = scp->mouse_cut_end;
377 	sc_remove_all_cutmarkings(scp->sc);
378 	if (scp->mouse_pos == i && i == j) {
379 	    cut_buffer[0] = '\0';
380 	} else if (skip_spc_right(scp, scp->mouse_pos) >= scp->xsize) {
381 	    /* if the pointer is on trailing blank chars, mark towards eol */
382 	    i = skip_spc_left(scp, scp->mouse_pos) + 1;
383 	    s = spltty();
384 	    scp->mouse_cut_start =
385 	        (scp->mouse_pos / scp->xsize) * scp->xsize + i;
386 	    scp->mouse_cut_end =
387 	        (scp->mouse_pos / scp->xsize + 1) * scp->xsize - 1;
388 	    splx(s);
389 	    cut_buffer[0] = '\r';
390 	    cut_buffer[1] = '\0';
391 	    scp->status |= MOUSE_CUTTING;
392 	} else {
393 	    s = spltty();
394 	    scp->mouse_cut_start = scp->mouse_pos;
395 	    scp->mouse_cut_end = scp->mouse_cut_start;
396 	    splx(s);
397 	    cut_buffer[0] = sc_vtb_getc(&scp->vtb, scp->mouse_cut_start);
398 	    cut_buffer[1] = '\0';
399 	    scp->status |= MOUSE_CUTTING;
400 	}
401     	mark_all(scp);	/* this is probably overkill XXX */
402     }
403 }
404 
405 /* end of cut operation */
406 static void
407 mouse_cut_end(scr_stat *scp)
408 {
409     if (scp->status & MOUSE_VISIBLE)
410 	scp->status &= ~MOUSE_CUTTING;
411 }
412 
413 /* copy a word under the mouse pointer */
414 static void
415 mouse_cut_word(scr_stat *scp)
416 {
417     int start;
418     int end;
419     int sol;
420     int eol;
421     int c;
422     int s;
423     int i;
424     int j;
425 
426     /*
427      * Because we don't have locale information in the kernel,
428      * we only distinguish space char and non-space chars.  Punctuation
429      * chars, symbols and other regular chars are all treated alike.
430      */
431     if (scp->status & MOUSE_VISIBLE) {
432 	/* remove the current cut mark */
433 	s = spltty();
434 	if (scp->mouse_cut_start <= scp->mouse_cut_end) {
435 	    mark_for_update(scp, scp->mouse_cut_start);
436 	    mark_for_update(scp, scp->mouse_cut_end);
437 	} else if (scp->mouse_cut_end >= 0) {
438 	    mark_for_update(scp, scp->mouse_cut_end);
439 	    mark_for_update(scp, scp->mouse_cut_start);
440 	}
441 	scp->mouse_cut_start = scp->xsize*scp->ysize;
442 	scp->mouse_cut_end = -1;
443 	splx(s);
444 
445 	sol = (scp->mouse_pos / scp->xsize) * scp->xsize;
446 	eol = sol + scp->xsize;
447 	c = sc_vtb_getc(&scp->vtb, scp->mouse_pos);
448 	if (IS_SPACE_CHAR(c)) {
449 	    /* blank space */
450 	    for (j = scp->mouse_pos; j >= sol; --j) {
451 		c = sc_vtb_getc(&scp->vtb, j);
452 	        if (!IS_SPACE_CHAR(c))
453 		    break;
454 	    }
455 	    start = ++j;
456 	    for (j = scp->mouse_pos; j < eol; ++j) {
457 		c = sc_vtb_getc(&scp->vtb, j);
458 	        if (!IS_SPACE_CHAR(c))
459 		    break;
460 	    }
461 	    end = j - 1;
462 	} else {
463 	    /* non-space word */
464 	    for (j = scp->mouse_pos; j >= sol; --j) {
465 		c = sc_vtb_getc(&scp->vtb, j);
466 	        if (IS_SPACE_CHAR(c))
467 		    break;
468 	    }
469 	    start = ++j;
470 	    for (j = scp->mouse_pos; j < eol; ++j) {
471 		c = sc_vtb_getc(&scp->vtb, j);
472 	        if (IS_SPACE_CHAR(c))
473 		    break;
474 	    }
475 	    end = j - 1;
476 	}
477 
478 	/* copy the found word */
479 	for (i = 0, j = start; j <= end; ++j)
480 	    cut_buffer[i++] = sc_vtb_getc(&scp->vtb, j);
481 	cut_buffer[i] = '\0';
482 	scp->status |= MOUSE_CUTTING;
483 
484 	/* mark the region */
485 	s = spltty();
486 	scp->mouse_cut_start = start;
487 	scp->mouse_cut_end = end;
488 	mark_for_update(scp, start);
489 	mark_for_update(scp, end);
490 	splx(s);
491     }
492 }
493 
494 /* copy a line under the mouse pointer */
495 static void
496 mouse_cut_line(scr_stat *scp)
497 {
498     int s;
499     int i;
500     int j;
501 
502     if (scp->status & MOUSE_VISIBLE) {
503 	/* remove the current cut mark */
504 	s = spltty();
505 	if (scp->mouse_cut_start <= scp->mouse_cut_end) {
506 	    mark_for_update(scp, scp->mouse_cut_start);
507 	    mark_for_update(scp, scp->mouse_cut_end);
508 	} else if (scp->mouse_cut_end >= 0) {
509 	    mark_for_update(scp, scp->mouse_cut_end);
510 	    mark_for_update(scp, scp->mouse_cut_start);
511 	}
512 
513 	/* mark the entire line */
514 	scp->mouse_cut_start =
515 	    (scp->mouse_pos / scp->xsize) * scp->xsize;
516 	scp->mouse_cut_end = scp->mouse_cut_start + scp->xsize - 1;
517 	mark_for_update(scp, scp->mouse_cut_start);
518 	mark_for_update(scp, scp->mouse_cut_end);
519 	splx(s);
520 
521 	/* copy the line into the cut buffer */
522 	for (i = 0, j = scp->mouse_cut_start; j <= scp->mouse_cut_end; ++j)
523 	    cut_buffer[i++] = sc_vtb_getc(&scp->vtb, j);
524 	cut_buffer[i++] = '\r';
525 	cut_buffer[i] = '\0';
526 	scp->status |= MOUSE_CUTTING;
527     }
528 }
529 
530 /* extend the marked region to the mouse pointer position */
531 static void
532 mouse_cut_extend(scr_stat *scp)
533 {
534     int start;
535     int end;
536     int s;
537 
538     if ((scp->status & MOUSE_VISIBLE) && !(scp->status & MOUSE_CUTTING)
539 	&& (scp->mouse_cut_end >= 0)) {
540 	if (scp->mouse_cut_start <= scp->mouse_cut_end) {
541 	    start = scp->mouse_cut_start;
542 	    end = scp->mouse_cut_end;
543 	} else {
544 	    start = scp->mouse_cut_end;
545 	    end = scp->mouse_cut_start - 1;
546 	}
547 	s = spltty();
548 	if (scp->mouse_pos > end) {
549 	    scp->mouse_cut_start = start;
550 	    scp->mouse_cut_end = end;
551 	} else if (scp->mouse_pos < start) {
552 	    scp->mouse_cut_start = end + 1;
553 	    scp->mouse_cut_end = start;
554 	} else {
555 	    if (scp->mouse_pos - start > end + 1 - scp->mouse_pos) {
556 		scp->mouse_cut_start = start;
557 		scp->mouse_cut_end = end;
558 	    } else {
559 		scp->mouse_cut_start = end + 1;
560 		scp->mouse_cut_end = start;
561 	    }
562 	}
563 	splx(s);
564 	mouse_cut(scp);
565 	scp->status |= MOUSE_CUTTING;
566     }
567 }
568 
569 /* paste cut buffer contents into the current vty */
570 static void
571 mouse_paste(scr_stat *scp)
572 {
573     if (scp->status & MOUSE_VISIBLE)
574 	sc_paste(scp, cut_buffer, strlen(cut_buffer));
575 }
576 
577 #endif /* SC_NO_CUTPASTE */
578 
579 int
580 sc_mouse_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag,
581 	       struct thread *td)
582 {
583     mouse_info_t *mouse;
584     scr_stat *cur_scp;
585     scr_stat *scp;
586     int s;
587     int f;
588 
589     scp = SC_STAT(tp->t_dev);
590 
591     switch (cmd) {
592 
593     case CONS_MOUSECTL:		/* control mouse arrow */
594 	mouse = (mouse_info_t*)data;
595 	cur_scp = scp->sc->cur_scp;
596 
597 	switch (mouse->operation) {
598 	case MOUSE_MODE:
599 	    if (ISSIGVALID(mouse->u.mode.signal)) {
600 		scp->mouse_signal = mouse->u.mode.signal;
601 		scp->mouse_proc = td->td_proc;
602 		scp->mouse_pid = td->td_proc->p_pid;
603 	    }
604 	    else {
605 		scp->mouse_signal = 0;
606 		scp->mouse_proc = NULL;
607 		scp->mouse_pid = 0;
608 	    }
609 	    return 0;
610 
611 	case MOUSE_SHOW:
612 	    s = spltty();
613 	    if (!(scp->sc->flags & SC_MOUSE_ENABLED)) {
614 		scp->sc->flags |= SC_MOUSE_ENABLED;
615 		cur_scp->status &= ~MOUSE_HIDDEN;
616 		if (!ISGRAPHSC(cur_scp))
617 		    mark_all(cur_scp);
618 		splx(s);
619 		return 0;
620 	    } else {
621 		splx(s);
622 		return EINVAL;
623 	    }
624 	    break;
625 
626 	case MOUSE_HIDE:
627 	    s = spltty();
628 	    if (scp->sc->flags & SC_MOUSE_ENABLED) {
629 		scp->sc->flags &= ~SC_MOUSE_ENABLED;
630 		sc_remove_all_mouse(scp->sc);
631 		splx(s);
632 		return 0;
633 	    } else {
634 		splx(s);
635 		return EINVAL;
636 	    }
637 	    break;
638 
639 	case MOUSE_MOVEABS:
640 	    s = spltty();
641 	    scp->mouse_xpos = mouse->u.data.x;
642 	    scp->mouse_ypos = mouse->u.data.y;
643 	    set_mouse_pos(scp);
644 	    splx(s);
645 	    break;
646 
647 	case MOUSE_MOVEREL:
648 	    s = spltty();
649 	    scp->mouse_xpos += mouse->u.data.x;
650 	    scp->mouse_ypos += mouse->u.data.y;
651 	    set_mouse_pos(scp);
652 	    splx(s);
653 	    break;
654 
655 	case MOUSE_GETINFO:
656 	    mouse->u.data.x = scp->mouse_xpos;
657 	    mouse->u.data.y = scp->mouse_ypos;
658 	    mouse->u.data.z = 0;
659 	    mouse->u.data.buttons = scp->mouse_buttons;
660 	    return 0;
661 
662 	case MOUSE_ACTION:
663 	case MOUSE_MOTION_EVENT:
664 	    /* send out mouse event on /dev/sysmouse */
665 #if 0
666 	    /* this should maybe only be settable from /dev/consolectl SOS */
667 	    if (SC_VTY(tp->t_dev) != SC_CONSOLECTL)
668 		return ENOTTY;
669 #endif
670 	    s = spltty();
671 	    if (mouse->u.data.x != 0 || mouse->u.data.y != 0) {
672 		cur_scp->mouse_xpos += mouse->u.data.x;
673 		cur_scp->mouse_ypos += mouse->u.data.y;
674 		set_mouse_pos(cur_scp);
675 	    }
676 	    f = 0;
677 	    if (mouse->operation == MOUSE_ACTION) {
678 		f = cur_scp->mouse_buttons ^ mouse->u.data.buttons;
679 		cur_scp->mouse_buttons = mouse->u.data.buttons;
680 	    }
681 	    splx(s);
682 
683 	    if (sysmouse_event(mouse) == 0)
684 		return 0;
685 
686 	    /*
687 	     * If any buttons are down or the mouse has moved a lot,
688 	     * stop the screen saver.
689 	     */
690 	    if (((mouse->operation == MOUSE_ACTION) && mouse->u.data.buttons)
691 		|| (mouse->u.data.x*mouse->u.data.x
692 			+ mouse->u.data.y*mouse->u.data.y
693 			>= SC_WAKEUP_DELTA*SC_WAKEUP_DELTA)) {
694 		sc_touch_scrn_saver();
695 	    }
696 
697 	    cur_scp->status &= ~MOUSE_HIDDEN;
698 
699 	    if (cur_scp->mouse_signal) {
700     		/* has controlling process died? */
701 		if (cur_scp->mouse_proc &&
702 		    (cur_scp->mouse_proc != pfind(cur_scp->mouse_pid))){
703 		    	cur_scp->mouse_signal = 0;
704 			cur_scp->mouse_proc = NULL;
705 			cur_scp->mouse_pid = 0;
706 		} else {
707 		    psignal(cur_scp->mouse_proc, cur_scp->mouse_signal);
708 		    break;
709 		}
710 	    }
711 
712 	    if (ISGRAPHSC(cur_scp) || (cut_buffer == NULL))
713 		break;
714 
715 #ifndef SC_NO_CUTPASTE
716 	    if ((mouse->operation == MOUSE_ACTION) && f) {
717 		/* process button presses */
718 		if (cur_scp->mouse_buttons & MOUSE_BUTTON1DOWN)
719 		    mouse_cut_start(cur_scp);
720 		else
721 		    mouse_cut_end(cur_scp);
722 		if (cur_scp->mouse_buttons & MOUSE_BUTTON2DOWN ||
723 		    cur_scp->mouse_buttons & MOUSE_BUTTON3DOWN)
724 		    mouse_paste(cur_scp);
725 	    }
726 #endif /* SC_NO_CUTPASTE */
727 	    break;
728 
729 	case MOUSE_BUTTON_EVENT:
730 	    if ((mouse->u.event.id & MOUSE_BUTTONS) == 0)
731 		return EINVAL;
732 	    if (mouse->u.event.value < 0)
733 		return EINVAL;
734 #if 0
735 	    /* this should maybe only be settable from /dev/consolectl SOS */
736 	    if (SC_VTY(tp->t_dev) != SC_CONSOLECTL)
737 		return ENOTTY;
738 #endif
739 	    if (mouse->u.event.value > 0)
740 		cur_scp->mouse_buttons |= mouse->u.event.id;
741 	    else
742 		cur_scp->mouse_buttons &= ~mouse->u.event.id;
743 
744 	    if (sysmouse_event(mouse) == 0)
745 		return 0;
746 
747 	    /* if a button is held down, stop the screen saver */
748 	    if (mouse->u.event.value > 0)
749 		sc_touch_scrn_saver();
750 
751 	    cur_scp->status &= ~MOUSE_HIDDEN;
752 
753 	    if (cur_scp->mouse_signal) {
754 		if (cur_scp->mouse_proc &&
755 		    (cur_scp->mouse_proc != pfind(cur_scp->mouse_pid))){
756 		    	cur_scp->mouse_signal = 0;
757 			cur_scp->mouse_proc = NULL;
758 			cur_scp->mouse_pid = 0;
759 		} else {
760 		    psignal(cur_scp->mouse_proc, cur_scp->mouse_signal);
761 		    break;
762 		}
763 	    }
764 
765 	    if (ISGRAPHSC(cur_scp) || (cut_buffer == NULL))
766 		break;
767 
768 #ifndef SC_NO_CUTPASTE
769 	    switch (mouse->u.event.id) {
770 	    case MOUSE_BUTTON1DOWN:
771 	        switch (mouse->u.event.value % 4) {
772 		case 0:	/* up */
773 		    mouse_cut_end(cur_scp);
774 		    break;
775 		case 1: /* single click: start cut operation */
776 		    mouse_cut_start(cur_scp);
777 		    break;
778 		case 2:	/* double click: cut a word */
779 		    mouse_cut_word(cur_scp);
780 		    mouse_cut_end(cur_scp);
781 		    break;
782 		case 3:	/* triple click: cut a line */
783 		    mouse_cut_line(cur_scp);
784 		    mouse_cut_end(cur_scp);
785 		    break;
786 		}
787 		break;
788 	    case SC_MOUSE_PASTEBUTTON:
789 	        switch (mouse->u.event.value) {
790 		case 0:	/* up */
791 		    break;
792 		default:
793 		    mouse_paste(cur_scp);
794 		    break;
795 		}
796 		break;
797 	    case SC_MOUSE_EXTENDBUTTON:
798 	        switch (mouse->u.event.value) {
799 		case 0:	/* up */
800 		    if (!(cur_scp->mouse_buttons & MOUSE_BUTTON1DOWN))
801 		        mouse_cut_end(cur_scp);
802 		    break;
803 		default:
804 		    mouse_cut_extend(cur_scp);
805 		    break;
806 		}
807 		break;
808 	    }
809 #endif /* SC_NO_CUTPASTE */
810 	    break;
811 
812 	case MOUSE_MOUSECHAR:
813 	    if (mouse->u.mouse_char < 0) {
814 		mouse->u.mouse_char = scp->sc->mouse_char;
815 	    } else {
816 		if (mouse->u.mouse_char >= (unsigned char)-1 - 4)
817 		    return EINVAL;
818 		s = spltty();
819 		sc_remove_all_mouse(scp->sc);
820 #ifndef SC_NO_FONT_LOADING
821 		if (ISTEXTSC(cur_scp) && (cur_scp->font != NULL))
822 		    sc_load_font(cur_scp, 0, cur_scp->font_size, cur_scp->font,
823 				 cur_scp->sc->mouse_char, 4);
824 #endif
825 		scp->sc->mouse_char = mouse->u.mouse_char;
826 		splx(s);
827 	    }
828 	    break;
829 
830 	default:
831 	    return EINVAL;
832 	}
833 
834 	return 0;
835     }
836 
837     return ENOIOCTL;
838 }
839 
840 #endif /* SC_NO_SYSMOUSE */
841