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