148104Syokota/*-
248104Syokota * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
348104Syokota * All rights reserved.
448104Syokota *
548104Syokota * Redistribution and use in source and binary forms, with or without
648104Syokota * modification, are permitted provided that the following conditions
748104Syokota * are met:
848104Syokota * 1. Redistributions of source code must retain the above copyright
948104Syokota *    notice, this list of conditions and the following disclaimer as
1048104Syokota *    the first lines of this file unmodified.
1148104Syokota * 2. Redistributions in binary form must reproduce the above copyright
1248104Syokota *    notice, this list of conditions and the following disclaimer in the
1348104Syokota *    documentation and/or other materials provided with the distribution.
1448104Syokota *
1548104Syokota * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
1648104Syokota * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1748104Syokota * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1848104Syokota * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
1948104Syokota * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2048104Syokota * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2148104Syokota * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2248104Syokota * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2348104Syokota * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2448104Syokota * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2548104Syokota */
2648104Syokota
27119420Sobrien#include <sys/cdefs.h>
28119420Sobrien__FBSDID("$FreeBSD$");
29119420Sobrien
3048104Syokota#include "opt_syscons.h"
3148104Syokota
3248104Syokota#include <sys/param.h>
3348104Syokota#include <sys/systm.h>
3448104Syokota#include <sys/conf.h>
3576166Smarkm#include <sys/consio.h>
3676166Smarkm#include <sys/fbio.h>
37114216Skan#include <sys/limits.h>
3876166Smarkm#include <sys/lock.h>
3976166Smarkm#include <sys/malloc.h>
4076166Smarkm#include <sys/mouse.h>
4176166Smarkm#include <sys/mutex.h>
4248104Syokota#include <sys/proc.h>
4365690Smarkm#include <sys/random.h>
4476166Smarkm#include <sys/signalvar.h>
4548104Syokota#include <sys/tty.h>
4648104Syokota
4748104Syokota#include <dev/syscons/syscons.h>
4848104Syokota
4953011Syokota#ifdef SC_TWOBUTTON_MOUSE
5053011Syokota#define SC_MOUSE_PASTEBUTTON	MOUSE_BUTTON3DOWN	/* right button */
5153011Syokota#define SC_MOUSE_EXTENDBUTTON	MOUSE_BUTTON2DOWN	/* not really used */
5253011Syokota#else
5353011Syokota#define SC_MOUSE_PASTEBUTTON	MOUSE_BUTTON2DOWN	/* middle button */
5453011Syokota#define SC_MOUSE_EXTENDBUTTON	MOUSE_BUTTON3DOWN	/* right button */
5553011Syokota#endif /* SC_TWOBUTTON_MOUSE */
5653011Syokota
5748104Syokota#define SC_WAKEUP_DELTA		20
5848104Syokota
5948104Syokota/* for backward compatibility */
6048104Syokota#define OLD_CONS_MOUSECTL	_IOWR('c', 10, old_mouse_info_t)
6148104Syokota
6248104Syokotatypedef struct old_mouse_data {
6348104Syokota    int x;
6448104Syokota    int y;
6548104Syokota    int buttons;
6648104Syokota} old_mouse_data_t;
6748104Syokota
6848104Syokotatypedef struct old_mouse_info {
6948104Syokota    int operation;
7048104Syokota    union {
7148104Syokota	struct old_mouse_data data;
7248104Syokota	struct mouse_mode mode;
7348104Syokota    } u;
7448104Syokota} old_mouse_info_t;
7548104Syokota
7656043Syokota#ifndef SC_NO_SYSMOUSE
7756043Syokota
7848104Syokota/* local variables */
79115595Sjmallett#ifndef SC_NO_CUTPASTE
8048104Syokotastatic int		cut_buffer_size;
8148104Syokotastatic u_char		*cut_buffer;
82115595Sjmallett#endif
8348104Syokota
8448104Syokota/* local functions */
8548104Syokotastatic void set_mouse_pos(scr_stat *scp);
8648104Syokota#ifndef SC_NO_CUTPASTE
8748104Syokotastatic int skip_spc_right(scr_stat *scp, int p);
8848104Syokotastatic int skip_spc_left(scr_stat *scp, int p);
8948104Syokotastatic void mouse_cut(scr_stat *scp);
9048104Syokotastatic void mouse_cut_start(scr_stat *scp);
9148104Syokotastatic void mouse_cut_end(scr_stat *scp);
9248104Syokotastatic void mouse_cut_word(scr_stat *scp);
9348104Syokotastatic void mouse_cut_line(scr_stat *scp);
9448104Syokotastatic void mouse_cut_extend(scr_stat *scp);
9548104Syokota#endif /* SC_NO_CUTPASTE */
9648104Syokota
9748104Syokota#ifndef SC_NO_CUTPASTE
9848104Syokota/* allocate a cut buffer */
9948104Syokotavoid
10048104Syokotasc_alloc_cut_buffer(scr_stat *scp, int wait)
10148104Syokota{
10248104Syokota    u_char *p;
10348104Syokota
10448104Syokota    if ((cut_buffer == NULL)
10548104Syokota	|| (cut_buffer_size < scp->xsize * scp->ysize + 1)) {
10648104Syokota	p = cut_buffer;
10748104Syokota	cut_buffer = NULL;
10848104Syokota	if (p != NULL)
10948104Syokota	    free(p, M_DEVBUF);
11048104Syokota	cut_buffer_size = scp->xsize * scp->ysize + 1;
11148104Syokota	p = (u_char *)malloc(cut_buffer_size,
112111119Simp			     M_DEVBUF, (wait) ? M_WAITOK : M_NOWAIT);
11348104Syokota	if (p != NULL)
11448104Syokota	    p[0] = '\0';
11548104Syokota	cut_buffer = p;
11648104Syokota    }
11748104Syokota}
11848104Syokota#endif /* SC_NO_CUTPASTE */
11948104Syokota
120197539Sedstatic void
121197539Sedsc_mouse_input_button(scr_stat *scp, int button)
122197539Sed{
123197539Sed	char mouseb[6] = "\x1B[M";
124197539Sed
125197539Sed	mouseb[3] = ' ' + button;
126197539Sed	mouseb[4] = '!' + scp->mouse_pos % scp->xsize;
127197539Sed	mouseb[5] = '!' + scp->mouse_pos / scp->xsize;
128197539Sed	sc_respond(scp, mouseb, sizeof mouseb, 1);
129197539Sed}
130197539Sed
131197539Sedstatic void
132197539Sedsc_mouse_input(scr_stat *scp, mouse_info_t *mouse)
133197539Sed{
134197539Sed
135197539Sed	switch (mouse->operation) {
136197539Sed	case MOUSE_BUTTON_EVENT:
137197539Sed		if (mouse->u.event.value > 0) {
138197539Sed			/* Mouse button pressed. */
139197539Sed			if (mouse->u.event.id & MOUSE_BUTTON1DOWN)
140197539Sed				sc_mouse_input_button(scp, 0);
141197539Sed			if (mouse->u.event.id & MOUSE_BUTTON2DOWN)
142197539Sed				sc_mouse_input_button(scp, 1);
143197539Sed			if (mouse->u.event.id & MOUSE_BUTTON3DOWN)
144197539Sed				sc_mouse_input_button(scp, 2);
145197539Sed		} else {
146197539Sed			/* Mouse button released. */
147197539Sed			sc_mouse_input_button(scp, 3);
148197539Sed		}
149197539Sed		break;
150197539Sed	case MOUSE_MOTION_EVENT:
151197539Sed		if (mouse->u.data.z < 0) {
152197539Sed			/* Scroll up. */
153197539Sed			sc_mouse_input_button(scp, 64);
154197539Sed		} else if (mouse->u.data.z > 0) {
155197539Sed			/* Scroll down. */
156197539Sed			sc_mouse_input_button(scp, 65);
157197539Sed		}
158197539Sed		break;
159197539Sed	}
160197539Sed}
161197539Sed
16248104Syokota/* move mouse */
16348104Syokotavoid
16448104Syokotasc_mouse_move(scr_stat *scp, int x, int y)
16548104Syokota{
16648104Syokota    int s;
16748104Syokota
16848104Syokota    s = spltty();
16958872Syokota    scp->mouse_xpos = scp->mouse_oldxpos = x;
17058872Syokota    scp->mouse_ypos = scp->mouse_oldypos = y;
171149640Srodrigc    if (scp->font_size <= 0 || scp->font_width <= 0)
17256528Syokota	scp->mouse_pos = scp->mouse_oldpos = 0;
17356528Syokota    else
17456528Syokota	scp->mouse_pos = scp->mouse_oldpos =
175119388Sjake	    (y/scp->font_size - scp->yoff)*scp->xsize + x/scp->font_width -
176119388Sjake	    scp->xoff;
17758872Syokota    scp->status |= MOUSE_MOVED;
17848104Syokota    splx(s);
17948104Syokota}
18048104Syokota
18148104Syokota/* adjust mouse position */
18248104Syokotastatic void
18348104Syokotaset_mouse_pos(scr_stat *scp)
18448104Syokota{
185119388Sjake    if (scp->mouse_xpos < scp->xoff*scp->font_width)
186119388Sjake	scp->mouse_xpos = scp->xoff*scp->font_width;
18748104Syokota    if (scp->mouse_ypos < scp->yoff*scp->font_size)
18848104Syokota	scp->mouse_ypos = scp->yoff*scp->font_size;
18948104Syokota    if (ISGRAPHSC(scp)) {
19048104Syokota        if (scp->mouse_xpos > scp->xpixel-1)
19148104Syokota	    scp->mouse_xpos = scp->xpixel-1;
19248104Syokota        if (scp->mouse_ypos > scp->ypixel-1)
19348104Syokota	    scp->mouse_ypos = scp->ypixel-1;
19448104Syokota	return;
19548104Syokota    } else {
196119388Sjake	if (scp->mouse_xpos > (scp->xsize + scp->xoff)*scp->font_width - 1)
197119388Sjake	    scp->mouse_xpos = (scp->xsize + scp->xoff)*scp->font_width - 1;
19848104Syokota	if (scp->mouse_ypos > (scp->ysize + scp->yoff)*scp->font_size - 1)
19948104Syokota	    scp->mouse_ypos = (scp->ysize + scp->yoff)*scp->font_size - 1;
20048104Syokota    }
20148104Syokota
202149855Srodrigc    if ((scp->mouse_xpos != scp->mouse_oldxpos || scp->mouse_ypos != scp->mouse_oldypos)
203149855Srodrigc	&& (scp->font_size != 0 && scp->font_width != 0)) {
20448104Syokota	scp->status |= MOUSE_MOVED;
20548104Syokota    	scp->mouse_pos =
20648104Syokota	    (scp->mouse_ypos/scp->font_size - scp->yoff)*scp->xsize
207119388Sjake		+ scp->mouse_xpos/scp->font_width - scp->xoff;
20848104Syokota#ifndef SC_NO_CUTPASTE
20948104Syokota	if ((scp->status & MOUSE_VISIBLE) && (scp->status & MOUSE_CUTTING))
21048104Syokota	    mouse_cut(scp);
21148104Syokota#endif
21248104Syokota    }
21348104Syokota}
21448104Syokota
21548104Syokota#ifndef SC_NO_CUTPASTE
21648104Syokota
21748104Syokotavoid
21848104Syokotasc_draw_mouse_image(scr_stat *scp)
21948104Syokota{
22048104Syokota    if (ISGRAPHSC(scp))
22148104Syokota	return;
22248104Syokota
223162285Sscottl    SC_VIDEO_LOCK(scp->sc);
22448104Syokota    (*scp->rndr->draw_mouse)(scp, scp->mouse_xpos, scp->mouse_ypos, TRUE);
22548104Syokota    scp->mouse_oldpos = scp->mouse_pos;
22658872Syokota    scp->mouse_oldxpos = scp->mouse_xpos;
22758872Syokota    scp->mouse_oldypos = scp->mouse_ypos;
22858872Syokota    scp->status |= MOUSE_VISIBLE;
229162285Sscottl    SC_VIDEO_UNLOCK(scp->sc);
23048104Syokota}
23148104Syokota
23248104Syokotavoid
23348104Syokotasc_remove_mouse_image(scr_stat *scp)
23448104Syokota{
23548104Syokota    int size;
23648104Syokota    int i;
23748104Syokota
23848104Syokota    if (ISGRAPHSC(scp))
23948104Syokota	return;
24048104Syokota
241162285Sscottl    SC_VIDEO_LOCK(scp->sc);
24248104Syokota    (*scp->rndr->draw_mouse)(scp,
243119388Sjake			     (scp->mouse_oldpos%scp->xsize + scp->xoff)
244119388Sjake			         * scp->font_width,
24548104Syokota			     (scp->mouse_oldpos/scp->xsize + scp->yoff)
24648104Syokota				 * scp->font_size,
24748104Syokota			     FALSE);
24848104Syokota    size = scp->xsize*scp->ysize;
24948104Syokota    i = scp->mouse_oldpos;
25048104Syokota    mark_for_update(scp, i);
25148104Syokota    mark_for_update(scp, i);
25248104Syokota#ifndef PC98
25348104Syokota    if (i + scp->xsize + 1 < size) {
25448104Syokota	mark_for_update(scp, i + scp->xsize + 1);
25548104Syokota    } else if (i + scp->xsize < size) {
25648104Syokota	mark_for_update(scp, i + scp->xsize);
25748104Syokota    } else if (i + 1 < size) {
25848104Syokota	mark_for_update(scp, i + 1);
25948104Syokota    }
26048104Syokota#endif /* PC98 */
26158872Syokota    scp->status &= ~MOUSE_VISIBLE;
262162285Sscottl    SC_VIDEO_UNLOCK(scp->sc);
26348104Syokota}
26448104Syokota
26548104Syokotaint
26648104Syokotasc_inside_cutmark(scr_stat *scp, int pos)
26748104Syokota{
26848104Syokota    int start;
26948104Syokota    int end;
27048104Syokota
27148104Syokota    if (scp->mouse_cut_end < 0)
27248104Syokota	return FALSE;
27348104Syokota    if (scp->mouse_cut_start <= scp->mouse_cut_end) {
27448104Syokota	start = scp->mouse_cut_start;
27548104Syokota	end = scp->mouse_cut_end;
27648104Syokota    } else {
27748104Syokota	start = scp->mouse_cut_end;
27848104Syokota	end = scp->mouse_cut_start - 1;
27948104Syokota    }
28048104Syokota    return ((start <= pos) && (pos <= end));
28148104Syokota}
28248104Syokota
28348104Syokotavoid
28448104Syokotasc_remove_cutmarking(scr_stat *scp)
28548104Syokota{
28648104Syokota    int s;
28748104Syokota
28848104Syokota    s = spltty();
28948104Syokota    if (scp->mouse_cut_end >= 0) {
29048104Syokota	mark_for_update(scp, scp->mouse_cut_start);
29148104Syokota	mark_for_update(scp, scp->mouse_cut_end);
29248104Syokota    }
29348104Syokota    scp->mouse_cut_start = scp->xsize*scp->ysize;
29448104Syokota    scp->mouse_cut_end = -1;
29548104Syokota    splx(s);
29648104Syokota    scp->status &= ~MOUSE_CUTTING;
29748104Syokota}
29848104Syokota
29948104Syokotavoid
30048104Syokotasc_remove_all_cutmarkings(sc_softc_t *sc)
30148104Syokota{
30251404Syokota    scr_stat *scp;
30348104Syokota    int i;
30448104Syokota
30548104Syokota    /* delete cut markings in all vtys */
30648104Syokota    for (i = 0; i < sc->vtys; ++i) {
30751404Syokota	scp = SC_STAT(sc->dev[i]);
30851404Syokota	if (scp == NULL)
30948104Syokota	    continue;
31051404Syokota	sc_remove_cutmarking(scp);
31148104Syokota    }
31248104Syokota}
31348104Syokota
31448104Syokotavoid
31548104Syokotasc_remove_all_mouse(sc_softc_t *sc)
31648104Syokota{
31751404Syokota    scr_stat *scp;
31848104Syokota    int i;
31948104Syokota
32048104Syokota    for (i = 0; i < sc->vtys; ++i) {
32151404Syokota	scp = SC_STAT(sc->dev[i]);
32251404Syokota	if (scp == NULL)
32348104Syokota	    continue;
32451404Syokota	if (scp->status & MOUSE_VISIBLE) {
32551404Syokota	    scp->status &= ~MOUSE_VISIBLE;
32651404Syokota	    mark_all(scp);
32748104Syokota	}
32848104Syokota    }
32948104Syokota}
33048104Syokota
33152813Sarchie#define IS_SPACE_CHAR(c)	(((c) & 0xff) == ' ')
33248104Syokota
33383791Ssobomax#ifdef SC_CUT_SPACES2TABS
33483791Ssobomax#define IS_BLANK_CHAR(c)	(((c) & 0xff) == ' ' || ((c) & 0xff) == '\t')
33583791Ssobomax#else
33683791Ssobomax#define IS_BLANK_CHAR(c)	IS_SPACE_CHAR(c)
33783791Ssobomax#endif /* SC_CUT_SPACES2TABS */
33883791Ssobomax
33983791Ssobomax#ifdef SC_CUT_SEPCHARS
34083791Ssobomax#define IS_SEP_CHAR(c)		(index(SC_CUT_SEPCHARS, (c) & 0xff) != NULL)
34183791Ssobomax#else
34283791Ssobomax#define IS_SEP_CHAR(c)		IS_SPACE_CHAR(c)
34383791Ssobomax#endif /* SC_CUT_SEPCHARS */
34483791Ssobomax
34548104Syokota/* skip spaces to right */
34648104Syokotastatic int
34748104Syokotaskip_spc_right(scr_stat *scp, int p)
34848104Syokota{
34948104Syokota    int c;
35048104Syokota    int i;
35148104Syokota
35248104Syokota    for (i = p % scp->xsize; i < scp->xsize; ++i) {
35348104Syokota	c = sc_vtb_getc(&scp->vtb, p);
35452813Sarchie	if (!IS_SPACE_CHAR(c))
35548104Syokota	    break;
35648104Syokota	++p;
35748104Syokota    }
35848104Syokota    return i;
35948104Syokota}
36048104Syokota
36148104Syokota/* skip spaces to left */
36248104Syokotastatic int
36348104Syokotaskip_spc_left(scr_stat *scp, int p)
36448104Syokota{
36548104Syokota    int c;
36648104Syokota    int i;
36748104Syokota
36848104Syokota    for (i = p-- % scp->xsize - 1; i >= 0; --i) {
36948104Syokota	c = sc_vtb_getc(&scp->vtb, p);
37052813Sarchie	if (!IS_SPACE_CHAR(c))
37148104Syokota	    break;
37248104Syokota	--p;
37348104Syokota    }
37448104Syokota    return i;
37548104Syokota}
37648104Syokota
37783791Ssobomaxstatic void
37883791Ssobomaxmouse_do_cut(scr_stat *scp, int from, int to)
37983791Ssobomax{
38083791Ssobomax    int blank;
38183791Ssobomax    int i;
38283791Ssobomax    int leadspaces;
38383791Ssobomax    int p;
38483791Ssobomax    int s;
38583791Ssobomax
38683791Ssobomax    for (p = from, i = blank = leadspaces = 0; p <= to; ++p) {
38783791Ssobomax	cut_buffer[i] = sc_vtb_getc(&scp->vtb, p);
38883791Ssobomax	/* Be prepared that sc_vtb_getc() can return '\0' */
38983791Ssobomax	if (cut_buffer[i] == '\0')
39083791Ssobomax	    cut_buffer[i] = ' ';
39183791Ssobomax#ifdef SC_CUT_SPACES2TABS
39283791Ssobomax	if (leadspaces != -1) {
39383791Ssobomax	    if (IS_SPACE_CHAR(cut_buffer[i])) {
39483791Ssobomax		leadspaces++;
39583791Ssobomax		/* Check that we are at tabstop position */
39683791Ssobomax		if ((p % scp->xsize) % 8 == 7) {
39783791Ssobomax		    i -= leadspaces - 1;
39883791Ssobomax		    cut_buffer[i] = '\t';
39983791Ssobomax		    leadspaces = 0;
40083791Ssobomax		}
40183791Ssobomax	    } else {
40283791Ssobomax		leadspaces = -1;
40383791Ssobomax	    }
40483791Ssobomax	}
40583791Ssobomax#endif /* SC_CUT_SPACES2TABS */
40683791Ssobomax	/* remember the position of the last non-space char */
40783791Ssobomax	if (!IS_BLANK_CHAR(cut_buffer[i]))
40883791Ssobomax	    blank = i + 1;	/* the first space after the last non-space */
40983791Ssobomax	++i;
41083791Ssobomax	/* trim trailing blank when crossing lines */
41183791Ssobomax	if ((p % scp->xsize) == (scp->xsize - 1)) {
41283791Ssobomax	    cut_buffer[blank++] = '\r';
41383791Ssobomax	    i = blank;
41483791Ssobomax	    leadspaces = 0;
41583791Ssobomax	}
41683791Ssobomax    }
41783791Ssobomax    cut_buffer[i] = '\0';
41883791Ssobomax
41983791Ssobomax    /* remove the current marking */
42083791Ssobomax    s = spltty();
42183791Ssobomax    if (scp->mouse_cut_start <= scp->mouse_cut_end) {
42283791Ssobomax	mark_for_update(scp, scp->mouse_cut_start);
42383791Ssobomax	mark_for_update(scp, scp->mouse_cut_end);
42483791Ssobomax    } else if (scp->mouse_cut_end >= 0) {
42583791Ssobomax	mark_for_update(scp, scp->mouse_cut_end);
42683791Ssobomax	mark_for_update(scp, scp->mouse_cut_start);
42783791Ssobomax    }
42883791Ssobomax
42983791Ssobomax    /* mark the new region */
43083791Ssobomax    scp->mouse_cut_start = from;
43183791Ssobomax    scp->mouse_cut_end = to;
43283791Ssobomax    mark_for_update(scp, from);
43383791Ssobomax    mark_for_update(scp, to);
43483791Ssobomax    splx(s);
43583791Ssobomax}
43683791Ssobomax
43748104Syokota/* copy marked region to the cut buffer */
43848104Syokotastatic void
43948104Syokotamouse_cut(scr_stat *scp)
44048104Syokota{
44148104Syokota    int start;
44248104Syokota    int end;
44348104Syokota    int from;
44448104Syokota    int to;
44548104Syokota    int c;
44648104Syokota    int p;
44748104Syokota    int s;
44848104Syokota    int i;
44948104Syokota
45048104Syokota    start = scp->mouse_cut_start;
45148104Syokota    end = scp->mouse_cut_end;
45248104Syokota    if (scp->mouse_pos >= start) {
45348104Syokota	from = start;
45448104Syokota	to = end = scp->mouse_pos;
45548104Syokota    } else {
45648104Syokota	from = end = scp->mouse_pos;
45748104Syokota	to = start - 1;
45848104Syokota    }
45983791Ssobomax    p = to;
46048104Syokota    for (i = p % scp->xsize; i < scp->xsize; ++i) {
46148104Syokota	c = sc_vtb_getc(&scp->vtb, p);
46252813Sarchie	if (!IS_SPACE_CHAR(c))
46348104Syokota	    break;
46448104Syokota	++p;
46548104Syokota    }
46648104Syokota    /* if there is nothing but blank chars, trim them, but mark towards eol */
46783791Ssobomax    if (i == scp->xsize) {
46848104Syokota	if (end >= start)
46948104Syokota	    to = end = p - 1;
47048104Syokota	else
47148104Syokota	    to = start = p;
47248104Syokota    }
47383791Ssobomax    mouse_do_cut(scp, from, to);
47448104Syokota    s = spltty();
47548104Syokota    scp->mouse_cut_start = start;
47648104Syokota    scp->mouse_cut_end = end;
47748104Syokota    splx(s);
47848104Syokota}
47948104Syokota
48048104Syokota/* a mouse button is pressed, start cut operation */
48148104Syokotastatic void
48283791Ssobomaxmouse_cut_start(scr_stat *scp)
48348104Syokota{
48448104Syokota    int i;
48548104Syokota    int s;
48648104Syokota
48748104Syokota    if (scp->status & MOUSE_VISIBLE) {
48848104Syokota	sc_remove_all_cutmarkings(scp->sc);
489169983Sdelphij	if ((scp->mouse_pos == scp->mouse_cut_start) &&
490169983Sdelphij	    (scp->mouse_pos == scp->mouse_cut_end)) {
49148104Syokota	    cut_buffer[0] = '\0';
49283791Ssobomax	    return;
49348104Syokota	} else if (skip_spc_right(scp, scp->mouse_pos) >= scp->xsize) {
49448104Syokota	    /* if the pointer is on trailing blank chars, mark towards eol */
49548104Syokota	    i = skip_spc_left(scp, scp->mouse_pos) + 1;
49648104Syokota	    s = spltty();
49748104Syokota	    scp->mouse_cut_start =
49848104Syokota	        (scp->mouse_pos / scp->xsize) * scp->xsize + i;
49948104Syokota	    scp->mouse_cut_end =
50048104Syokota	        (scp->mouse_pos / scp->xsize + 1) * scp->xsize - 1;
50148104Syokota	    splx(s);
50248104Syokota	    cut_buffer[0] = '\r';
50348104Syokota	} else {
50448104Syokota	    s = spltty();
50548104Syokota	    scp->mouse_cut_start = scp->mouse_pos;
50648104Syokota	    scp->mouse_cut_end = scp->mouse_cut_start;
50748104Syokota	    splx(s);
50848104Syokota	    cut_buffer[0] = sc_vtb_getc(&scp->vtb, scp->mouse_cut_start);
50948104Syokota	}
51083791Ssobomax	cut_buffer[1] = '\0';
51183791Ssobomax	scp->status |= MOUSE_CUTTING;
51248104Syokota    	mark_all(scp);	/* this is probably overkill XXX */
51348104Syokota    }
51448104Syokota}
51548104Syokota
51648104Syokota/* end of cut operation */
51748104Syokotastatic void
51848104Syokotamouse_cut_end(scr_stat *scp)
51948104Syokota{
52048104Syokota    if (scp->status & MOUSE_VISIBLE)
52148104Syokota	scp->status &= ~MOUSE_CUTTING;
52248104Syokota}
52348104Syokota
52448104Syokota/* copy a word under the mouse pointer */
52548104Syokotastatic void
52648104Syokotamouse_cut_word(scr_stat *scp)
52748104Syokota{
52848104Syokota    int start;
52948104Syokota    int end;
53048104Syokota    int sol;
53148104Syokota    int eol;
53248104Syokota    int c;
53348104Syokota    int j;
53488926Ssobomax    int len;
53548104Syokota
53648104Syokota    /*
53748104Syokota     * Because we don't have locale information in the kernel,
53848104Syokota     * we only distinguish space char and non-space chars.  Punctuation
53983791Ssobomax     * chars, symbols and other regular chars are all treated alike
54083791Ssobomax     * unless user specified SC_CUT_SEPCHARS in his kernel config file.
54148104Syokota     */
54248104Syokota    if (scp->status & MOUSE_VISIBLE) {
54348104Syokota	sol = (scp->mouse_pos / scp->xsize) * scp->xsize;
54448104Syokota	eol = sol + scp->xsize;
54548104Syokota	c = sc_vtb_getc(&scp->vtb, scp->mouse_pos);
54683791Ssobomax	if (IS_SEP_CHAR(c)) {
54748104Syokota	    /* blank space */
54848104Syokota	    for (j = scp->mouse_pos; j >= sol; --j) {
54948104Syokota		c = sc_vtb_getc(&scp->vtb, j);
55083791Ssobomax	        if (!IS_SEP_CHAR(c))
55148104Syokota		    break;
55248104Syokota	    }
55348104Syokota	    start = ++j;
55448104Syokota	    for (j = scp->mouse_pos; j < eol; ++j) {
55548104Syokota		c = sc_vtb_getc(&scp->vtb, j);
55683791Ssobomax	        if (!IS_SEP_CHAR(c))
55748104Syokota		    break;
55848104Syokota	    }
55948104Syokota	    end = j - 1;
56048104Syokota	} else {
56148104Syokota	    /* non-space word */
56248104Syokota	    for (j = scp->mouse_pos; j >= sol; --j) {
56348104Syokota		c = sc_vtb_getc(&scp->vtb, j);
56483791Ssobomax	        if (IS_SEP_CHAR(c))
56548104Syokota		    break;
56648104Syokota	    }
56748104Syokota	    start = ++j;
56848104Syokota	    for (j = scp->mouse_pos; j < eol; ++j) {
56948104Syokota		c = sc_vtb_getc(&scp->vtb, j);
57083791Ssobomax	        if (IS_SEP_CHAR(c))
57148104Syokota		    break;
57248104Syokota	    }
57348104Syokota	    end = j - 1;
57448104Syokota	}
57548104Syokota
57648104Syokota	/* copy the found word */
57783791Ssobomax	mouse_do_cut(scp, start, end);
57888926Ssobomax	len = strlen(cut_buffer);
57988926Ssobomax	if (cut_buffer[len - 1] == '\r')
58088926Ssobomax	    cut_buffer[len - 1] = '\0';
58148104Syokota    }
58248104Syokota}
58348104Syokota
58448104Syokota/* copy a line under the mouse pointer */
58548104Syokotastatic void
58648104Syokotamouse_cut_line(scr_stat *scp)
58748104Syokota{
58886894Ssobomax    int len;
58983791Ssobomax    int from;
59048104Syokota
59148104Syokota    if (scp->status & MOUSE_VISIBLE) {
59283791Ssobomax	from = (scp->mouse_pos / scp->xsize) * scp->xsize;
59383791Ssobomax	mouse_do_cut(scp, from, from + scp->xsize - 1);
59486894Ssobomax	len = strlen(cut_buffer);
59586894Ssobomax	if (cut_buffer[len - 1] == '\r')
59686894Ssobomax	    cut_buffer[len - 1] = '\0';
59748104Syokota	scp->status |= MOUSE_CUTTING;
59848104Syokota    }
59948104Syokota}
60048104Syokota
60148104Syokota/* extend the marked region to the mouse pointer position */
60248104Syokotastatic void
60348104Syokotamouse_cut_extend(scr_stat *scp)
60448104Syokota{
60548104Syokota    int start;
60648104Syokota    int end;
60748104Syokota    int s;
60848104Syokota
60948104Syokota    if ((scp->status & MOUSE_VISIBLE) && !(scp->status & MOUSE_CUTTING)
61048104Syokota	&& (scp->mouse_cut_end >= 0)) {
61148104Syokota	if (scp->mouse_cut_start <= scp->mouse_cut_end) {
61248104Syokota	    start = scp->mouse_cut_start;
61348104Syokota	    end = scp->mouse_cut_end;
61448104Syokota	} else {
61548104Syokota	    start = scp->mouse_cut_end;
61648104Syokota	    end = scp->mouse_cut_start - 1;
61748104Syokota	}
61848104Syokota	s = spltty();
61948104Syokota	if (scp->mouse_pos > end) {
62048104Syokota	    scp->mouse_cut_start = start;
62148104Syokota	    scp->mouse_cut_end = end;
62248104Syokota	} else if (scp->mouse_pos < start) {
62348104Syokota	    scp->mouse_cut_start = end + 1;
62448104Syokota	    scp->mouse_cut_end = start;
62548104Syokota	} else {
62648104Syokota	    if (scp->mouse_pos - start > end + 1 - scp->mouse_pos) {
62748104Syokota		scp->mouse_cut_start = start;
62848104Syokota		scp->mouse_cut_end = end;
62948104Syokota	    } else {
63048104Syokota		scp->mouse_cut_start = end + 1;
63148104Syokota		scp->mouse_cut_end = start;
63248104Syokota	    }
63348104Syokota	}
63448104Syokota	splx(s);
63548104Syokota	mouse_cut(scp);
63648104Syokota	scp->status |= MOUSE_CUTTING;
63748104Syokota    }
63848104Syokota}
63948104Syokota
64048104Syokota/* paste cut buffer contents into the current vty */
64174118Sachevoid
64274118Sachesc_mouse_paste(scr_stat *scp)
64348104Syokota{
64474125Sache    sc_paste(scp, cut_buffer, strlen(cut_buffer));
64548104Syokota}
64648104Syokota
64748104Syokota#endif /* SC_NO_CUTPASTE */
64848104Syokota
64948104Syokotaint
650181905Sedsc_mouse_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
65148104Syokota{
65256043Syokota    mouse_info_t *mouse;
65356043Syokota    mouse_info_t buf;
65456043Syokota    scr_stat *cur_scp;
65548104Syokota    scr_stat *scp;
65675893Sjhb    struct proc *p1;
65748104Syokota    int s;
65856043Syokota    int f;
65948104Syokota
660181905Sed    scp = SC_STAT(tp);
66148104Syokota
66248104Syokota    switch (cmd) {
66348104Syokota
66448104Syokota    case CONS_MOUSECTL:		/* control mouse arrow */
66548104Syokota    case OLD_CONS_MOUSECTL:
66648104Syokota
66756043Syokota	mouse = (mouse_info_t*)data;
66865690Smarkm
66965690Smarkm	random_harvest(mouse, sizeof(mouse_info_t), 2, 0, RANDOM_MOUSE);
67065690Smarkm
67148104Syokota	if (cmd == OLD_CONS_MOUSECTL) {
67248104Syokota	    static u_char swapb[] = { 0, 4, 2, 6, 1, 5, 3, 7 };
67348104Syokota	    old_mouse_info_t *old_mouse = (old_mouse_info_t *)data;
67448104Syokota
67548104Syokota	    mouse = &buf;
67648104Syokota	    mouse->operation = old_mouse->operation;
67748104Syokota	    switch (mouse->operation) {
67848104Syokota	    case MOUSE_MODE:
67948104Syokota		mouse->u.mode = old_mouse->u.mode;
68048104Syokota		break;
68148104Syokota	    case MOUSE_SHOW:
68248104Syokota	    case MOUSE_HIDE:
68348104Syokota		break;
68448104Syokota	    case MOUSE_MOVEABS:
68548104Syokota	    case MOUSE_MOVEREL:
68648104Syokota	    case MOUSE_ACTION:
68748104Syokota		mouse->u.data.x = old_mouse->u.data.x;
68848104Syokota		mouse->u.data.y = old_mouse->u.data.y;
68948104Syokota		mouse->u.data.z = 0;
69048104Syokota		mouse->u.data.buttons = swapb[old_mouse->u.data.buttons & 0x7];
69148104Syokota		break;
69248104Syokota	    case MOUSE_GETINFO:
69348104Syokota		old_mouse->u.data.x = scp->mouse_xpos;
69448104Syokota		old_mouse->u.data.y = scp->mouse_ypos;
69548104Syokota		old_mouse->u.data.buttons = swapb[scp->mouse_buttons & 0x7];
69678951Syokota		return 0;
69748104Syokota	    default:
69848104Syokota		return EINVAL;
69948104Syokota	    }
70048104Syokota	}
70148104Syokota
70248104Syokota	cur_scp = scp->sc->cur_scp;
70348104Syokota
70448104Syokota	switch (mouse->operation) {
70548104Syokota	case MOUSE_MODE:
70648104Syokota	    if (ISSIGVALID(mouse->u.mode.signal)) {
70748104Syokota		scp->mouse_signal = mouse->u.mode.signal;
70883366Sjulian		scp->mouse_proc = td->td_proc;
70983366Sjulian		scp->mouse_pid = td->td_proc->p_pid;
71048104Syokota	    }
71148104Syokota	    else {
71248104Syokota		scp->mouse_signal = 0;
71348104Syokota		scp->mouse_proc = NULL;
71448104Syokota		scp->mouse_pid = 0;
71548104Syokota	    }
71648104Syokota	    return 0;
71748104Syokota
71848104Syokota	case MOUSE_SHOW:
71948104Syokota	    s = spltty();
72048104Syokota	    if (!(scp->sc->flags & SC_MOUSE_ENABLED)) {
72148104Syokota		scp->sc->flags |= SC_MOUSE_ENABLED;
72258872Syokota		cur_scp->status &= ~MOUSE_HIDDEN;
72358872Syokota		if (!ISGRAPHSC(cur_scp))
72448104Syokota		    mark_all(cur_scp);
72548104Syokota	    }
726146736Sdelphij	    splx(s);
727146736Sdelphij	    return 0;
728146736Sdelphij	    /* NOTREACHED */
72948104Syokota
73048104Syokota	case MOUSE_HIDE:
73148104Syokota	    s = spltty();
73248104Syokota	    if (scp->sc->flags & SC_MOUSE_ENABLED) {
73348104Syokota		scp->sc->flags &= ~SC_MOUSE_ENABLED;
73448104Syokota		sc_remove_all_mouse(scp->sc);
73548104Syokota	    }
736146736Sdelphij	    splx(s);
737146736Sdelphij	    return 0;
738146736Sdelphij	    /* NOTREACHED */
73948104Syokota
74048104Syokota	case MOUSE_MOVEABS:
74148104Syokota	    s = spltty();
74248104Syokota	    scp->mouse_xpos = mouse->u.data.x;
74348104Syokota	    scp->mouse_ypos = mouse->u.data.y;
74448104Syokota	    set_mouse_pos(scp);
74548104Syokota	    splx(s);
74648104Syokota	    break;
74748104Syokota
74848104Syokota	case MOUSE_MOVEREL:
74948104Syokota	    s = spltty();
75048104Syokota	    scp->mouse_xpos += mouse->u.data.x;
75148104Syokota	    scp->mouse_ypos += mouse->u.data.y;
75248104Syokota	    set_mouse_pos(scp);
75348104Syokota	    splx(s);
75448104Syokota	    break;
75548104Syokota
75648104Syokota	case MOUSE_GETINFO:
75748104Syokota	    mouse->u.data.x = scp->mouse_xpos;
75848104Syokota	    mouse->u.data.y = scp->mouse_ypos;
75948104Syokota	    mouse->u.data.z = 0;
76048104Syokota	    mouse->u.data.buttons = scp->mouse_buttons;
76148104Syokota	    return 0;
76248104Syokota
76348104Syokota	case MOUSE_ACTION:
76448104Syokota	case MOUSE_MOTION_EVENT:
76548104Syokota	    /* send out mouse event on /dev/sysmouse */
76648104Syokota#if 0
76748104Syokota	    /* this should maybe only be settable from /dev/consolectl SOS */
76848104Syokota	    if (SC_VTY(tp->t_dev) != SC_CONSOLECTL)
76948104Syokota		return ENOTTY;
77048104Syokota#endif
77153057Syokota	    s = spltty();
77253057Syokota	    if (mouse->u.data.x != 0 || mouse->u.data.y != 0) {
77353057Syokota		cur_scp->mouse_xpos += mouse->u.data.x;
77453057Syokota		cur_scp->mouse_ypos += mouse->u.data.y;
77553057Syokota		set_mouse_pos(cur_scp);
77653057Syokota	    }
77753057Syokota	    f = 0;
77853057Syokota	    if (mouse->operation == MOUSE_ACTION) {
77953057Syokota		f = cur_scp->mouse_buttons ^ mouse->u.data.buttons;
78053057Syokota		cur_scp->mouse_buttons = mouse->u.data.buttons;
78153057Syokota	    }
78253057Syokota	    splx(s);
78353057Syokota
78456043Syokota	    if (sysmouse_event(mouse) == 0)
78548104Syokota		return 0;
78648104Syokota
78748104Syokota	    /*
78848104Syokota	     * If any buttons are down or the mouse has moved a lot,
78948104Syokota	     * stop the screen saver.
79048104Syokota	     */
79148104Syokota	    if (((mouse->operation == MOUSE_ACTION) && mouse->u.data.buttons)
79248104Syokota		|| (mouse->u.data.x*mouse->u.data.x
79348104Syokota			+ mouse->u.data.y*mouse->u.data.y
79448104Syokota			>= SC_WAKEUP_DELTA*SC_WAKEUP_DELTA)) {
79548104Syokota		sc_touch_scrn_saver();
79648104Syokota	    }
79748104Syokota
79858872Syokota	    cur_scp->status &= ~MOUSE_HIDDEN;
79954182Syokota
800197539Sed	    if (cur_scp->mouse_level > 0) {
801197539Sed	    	sc_mouse_input(scp, mouse);
802197539Sed		break;
803197539Sed	    }
804197539Sed
80575893Sjhb	    if (cur_scp->mouse_signal && cur_scp->mouse_proc) {
80654182Syokota    		/* has controlling process died? */
80775893Sjhb		if (cur_scp->mouse_proc != (p1 = pfind(cur_scp->mouse_pid))) {
80854182Syokota		    	cur_scp->mouse_signal = 0;
80954182Syokota			cur_scp->mouse_proc = NULL;
81054182Syokota			cur_scp->mouse_pid = 0;
81175893Sjhb			if (p1)
81275893Sjhb			    PROC_UNLOCK(p1);
81354182Syokota		} else {
814225617Skmacy		    kern_psignal(cur_scp->mouse_proc, cur_scp->mouse_signal);
81573929Sjhb		    PROC_UNLOCK(cur_scp->mouse_proc);
81654182Syokota		    break;
81754182Syokota		}
81854182Syokota	    }
81954182Syokota
820115595Sjmallett#ifndef SC_NO_CUTPASTE
82148104Syokota	    if (ISGRAPHSC(cur_scp) || (cut_buffer == NULL))
82248104Syokota		break;
82348104Syokota
82453057Syokota	    if ((mouse->operation == MOUSE_ACTION) && f) {
82548104Syokota		/* process button presses */
82653057Syokota		if (cur_scp->mouse_buttons & MOUSE_BUTTON1DOWN)
82753057Syokota		    mouse_cut_start(cur_scp);
82853057Syokota		else
82953057Syokota		    mouse_cut_end(cur_scp);
83053057Syokota		if (cur_scp->mouse_buttons & MOUSE_BUTTON2DOWN ||
83153057Syokota		    cur_scp->mouse_buttons & MOUSE_BUTTON3DOWN)
83274118Sache		    sc_mouse_paste(cur_scp);
83348104Syokota	    }
83448104Syokota#endif /* SC_NO_CUTPASTE */
83548104Syokota	    break;
83648104Syokota
83748104Syokota	case MOUSE_BUTTON_EVENT:
83848104Syokota	    if ((mouse->u.event.id & MOUSE_BUTTONS) == 0)
83948104Syokota		return EINVAL;
84048104Syokota	    if (mouse->u.event.value < 0)
84148104Syokota		return EINVAL;
84248104Syokota#if 0
84348104Syokota	    /* this should maybe only be settable from /dev/consolectl SOS */
84448104Syokota	    if (SC_VTY(tp->t_dev) != SC_CONSOLECTL)
84548104Syokota		return ENOTTY;
84648104Syokota#endif
84756043Syokota	    if (mouse->u.event.value > 0)
84848104Syokota		cur_scp->mouse_buttons |= mouse->u.event.id;
84956043Syokota	    else
85048104Syokota		cur_scp->mouse_buttons &= ~mouse->u.event.id;
85156043Syokota
85256043Syokota	    if (sysmouse_event(mouse) == 0)
85348104Syokota		return 0;
85448104Syokota
85554182Syokota	    /* if a button is held down, stop the screen saver */
85654182Syokota	    if (mouse->u.event.value > 0)
85754182Syokota		sc_touch_scrn_saver();
85854182Syokota
85958872Syokota	    cur_scp->status &= ~MOUSE_HIDDEN;
86054182Syokota
861197539Sed	    if (cur_scp->mouse_level > 0) {
862197539Sed	    	sc_mouse_input(scp, mouse);
863197539Sed		break;
864197539Sed	    }
865197539Sed
86675893Sjhb	    if (cur_scp->mouse_signal && cur_scp->mouse_proc) {
86775893Sjhb		if (cur_scp->mouse_proc != (p1 = pfind(cur_scp->mouse_pid))){
86848104Syokota		    	cur_scp->mouse_signal = 0;
86948104Syokota			cur_scp->mouse_proc = NULL;
87048104Syokota			cur_scp->mouse_pid = 0;
87175893Sjhb			if (p1)
87275893Sjhb			    PROC_UNLOCK(p1);
87354182Syokota		} else {
874225617Skmacy		    kern_psignal(cur_scp->mouse_proc, cur_scp->mouse_signal);
87573929Sjhb		    PROC_UNLOCK(cur_scp->mouse_proc);
87654182Syokota		    break;
87748104Syokota		}
87848104Syokota	    }
87948104Syokota
880115595Sjmallett#ifndef SC_NO_CUTPASTE
88148104Syokota	    if (ISGRAPHSC(cur_scp) || (cut_buffer == NULL))
88248104Syokota		break;
88348104Syokota
88448104Syokota	    switch (mouse->u.event.id) {
88548104Syokota	    case MOUSE_BUTTON1DOWN:
88648104Syokota	        switch (mouse->u.event.value % 4) {
88748104Syokota		case 0:	/* up */
88848104Syokota		    mouse_cut_end(cur_scp);
88948104Syokota		    break;
89048104Syokota		case 1: /* single click: start cut operation */
89148104Syokota		    mouse_cut_start(cur_scp);
89248104Syokota		    break;
89348104Syokota		case 2:	/* double click: cut a word */
89448104Syokota		    mouse_cut_word(cur_scp);
89548104Syokota		    mouse_cut_end(cur_scp);
89648104Syokota		    break;
89748104Syokota		case 3:	/* triple click: cut a line */
89848104Syokota		    mouse_cut_line(cur_scp);
89948104Syokota		    mouse_cut_end(cur_scp);
90048104Syokota		    break;
90148104Syokota		}
90248104Syokota		break;
90353011Syokota	    case SC_MOUSE_PASTEBUTTON:
90448104Syokota	        switch (mouse->u.event.value) {
90548104Syokota		case 0:	/* up */
90648104Syokota		    break;
90748104Syokota		default:
90874118Sache		    sc_mouse_paste(cur_scp);
90948104Syokota		    break;
91048104Syokota		}
91148104Syokota		break;
91253011Syokota	    case SC_MOUSE_EXTENDBUTTON:
91348104Syokota	        switch (mouse->u.event.value) {
91448104Syokota		case 0:	/* up */
91548104Syokota		    if (!(cur_scp->mouse_buttons & MOUSE_BUTTON1DOWN))
91648104Syokota		        mouse_cut_end(cur_scp);
91748104Syokota		    break;
91848104Syokota		default:
91948104Syokota		    mouse_cut_extend(cur_scp);
92048104Syokota		    break;
92148104Syokota		}
92248104Syokota		break;
92348104Syokota	    }
92448104Syokota#endif /* SC_NO_CUTPASTE */
92548104Syokota	    break;
92648104Syokota
92755849Syokota	case MOUSE_MOUSECHAR:
92855849Syokota	    if (mouse->u.mouse_char < 0) {
92955849Syokota		mouse->u.mouse_char = scp->sc->mouse_char;
93055849Syokota	    } else {
93175790Sache		if (mouse->u.mouse_char > UCHAR_MAX - 3)
93255849Syokota		    return EINVAL;
93356043Syokota		s = spltty();
93455849Syokota		sc_remove_all_mouse(scp->sc);
93555849Syokota#ifndef SC_NO_FONT_LOADING
93656328Syokota		if (ISTEXTSC(cur_scp) && (cur_scp->font != NULL))
93775790Sache		    sc_load_font(cur_scp, 0, cur_scp->font_size,
938150686Smarius				 cur_scp->font_width,
93975790Sache				 cur_scp->font + cur_scp->font_size
94075790Sache				 * cur_scp->sc->mouse_char,
94156043Syokota				 cur_scp->sc->mouse_char, 4);
94255849Syokota#endif
94355849Syokota		scp->sc->mouse_char = mouse->u.mouse_char;
94455849Syokota		splx(s);
94555849Syokota	    }
94655849Syokota	    break;
94755849Syokota
94848104Syokota	default:
94948104Syokota	    return EINVAL;
95048104Syokota	}
95148104Syokota
95248104Syokota	return 0;
95348104Syokota    }
95448104Syokota
95548104Syokota    return ENOIOCTL;
95648104Syokota}
95748104Syokota
95848104Syokota#endif /* SC_NO_SYSMOUSE */
959