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