Merge from vendor branch NCURSES:
[games.git] / sys / dev / misc / syscons / scmouse.c
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 */