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