scmouse.c revision 58872
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 *
2650477Speter * $FreeBSD: head/sys/dev/syscons/scmouse.c 58872 2000-03-31 16:05:46Z yokota $
2748104Syokota */
2848104Syokota
2948104Syokota#include "opt_syscons.h"
3048104Syokota
3155849Syokota#include <limits.h>
3248104Syokota#include <sys/param.h>
3348104Syokota#include <sys/systm.h>
3448104Syokota#include <sys/conf.h>
3548104Syokota#include <sys/signalvar.h>
3648104Syokota#include <sys/proc.h>
3748104Syokota#include <sys/tty.h>
3848104Syokota#include <sys/malloc.h>
3948104Syokota
4048104Syokota#include <machine/console.h>
4148104Syokota#include <machine/mouse.h>
4248104Syokota
4348104Syokota#include <dev/syscons/syscons.h>
4448104Syokota
4553011Syokota#ifdef SC_TWOBUTTON_MOUSE
4653011Syokota#define SC_MOUSE_PASTEBUTTON	MOUSE_BUTTON3DOWN	/* right button */
4753011Syokota#define SC_MOUSE_EXTENDBUTTON	MOUSE_BUTTON2DOWN	/* not really used */
4853011Syokota#else
4953011Syokota#define SC_MOUSE_PASTEBUTTON	MOUSE_BUTTON2DOWN	/* middle button */
5053011Syokota#define SC_MOUSE_EXTENDBUTTON	MOUSE_BUTTON3DOWN	/* right button */
5153011Syokota#endif /* SC_TWOBUTTON_MOUSE */
5253011Syokota
5348104Syokota#define SC_WAKEUP_DELTA		20
5448104Syokota
5548104Syokota/* for backward compatibility */
5648104Syokota#define OLD_CONS_MOUSECTL	_IOWR('c', 10, old_mouse_info_t)
5748104Syokota
5848104Syokotatypedef struct old_mouse_data {
5948104Syokota    int x;
6048104Syokota    int y;
6148104Syokota    int buttons;
6248104Syokota} old_mouse_data_t;
6348104Syokota
6448104Syokotatypedef struct old_mouse_info {
6548104Syokota    int operation;
6648104Syokota    union {
6748104Syokota	struct old_mouse_data data;
6848104Syokota	struct mouse_mode mode;
6948104Syokota    } u;
7048104Syokota} old_mouse_info_t;
7148104Syokota
7256043Syokota#ifndef SC_NO_SYSMOUSE
7356043Syokota
7448104Syokota/* local variables */
7548104Syokotastatic int		cut_buffer_size;
7648104Syokotastatic u_char		*cut_buffer;
7748104Syokota
7848104Syokota/* local functions */
7948104Syokotastatic void set_mouse_pos(scr_stat *scp);
8048104Syokota#ifndef SC_NO_CUTPASTE
8148104Syokotastatic int skip_spc_right(scr_stat *scp, int p);
8248104Syokotastatic int skip_spc_left(scr_stat *scp, int p);
8348104Syokotastatic void mouse_cut(scr_stat *scp);
8448104Syokotastatic void mouse_cut_start(scr_stat *scp);
8548104Syokotastatic void mouse_cut_end(scr_stat *scp);
8648104Syokotastatic void mouse_cut_word(scr_stat *scp);
8748104Syokotastatic void mouse_cut_line(scr_stat *scp);
8848104Syokotastatic void mouse_cut_extend(scr_stat *scp);
8948104Syokotastatic void mouse_paste(scr_stat *scp);
9048104Syokota#endif /* SC_NO_CUTPASTE */
9148104Syokota
9248104Syokota#ifndef SC_NO_CUTPASTE
9348104Syokota/* allocate a cut buffer */
9448104Syokotavoid
9548104Syokotasc_alloc_cut_buffer(scr_stat *scp, int wait)
9648104Syokota{
9748104Syokota    u_char *p;
9848104Syokota
9948104Syokota    if ((cut_buffer == NULL)
10048104Syokota	|| (cut_buffer_size < scp->xsize * scp->ysize + 1)) {
10148104Syokota	p = cut_buffer;
10248104Syokota	cut_buffer = NULL;
10348104Syokota	if (p != NULL)
10448104Syokota	    free(p, M_DEVBUF);
10548104Syokota	cut_buffer_size = scp->xsize * scp->ysize + 1;
10648104Syokota	p = (u_char *)malloc(cut_buffer_size,
10748104Syokota			     M_DEVBUF, (wait) ? M_WAITOK : M_NOWAIT);
10848104Syokota	if (p != NULL)
10948104Syokota	    p[0] = '\0';
11048104Syokota	cut_buffer = p;
11148104Syokota    }
11248104Syokota}
11348104Syokota#endif /* SC_NO_CUTPASTE */
11448104Syokota
11548104Syokota/* move mouse */
11648104Syokotavoid
11748104Syokotasc_mouse_move(scr_stat *scp, int x, int y)
11848104Syokota{
11948104Syokota    int s;
12048104Syokota
12148104Syokota    s = spltty();
12258872Syokota    scp->mouse_xpos = scp->mouse_oldxpos = x;
12358872Syokota    scp->mouse_ypos = scp->mouse_oldypos = y;
12458872Syokota    if (scp->font_size <= 0)
12556528Syokota	scp->mouse_pos = scp->mouse_oldpos = 0;
12656528Syokota    else
12756528Syokota	scp->mouse_pos = scp->mouse_oldpos =
12856528Syokota	    (y/scp->font_size - scp->yoff)*scp->xsize + x/8 - scp->xoff;
12958872Syokota    scp->status |= MOUSE_MOVED;
13048104Syokota    splx(s);
13148104Syokota}
13248104Syokota
13348104Syokota/* adjust mouse position */
13448104Syokotastatic void
13548104Syokotaset_mouse_pos(scr_stat *scp)
13648104Syokota{
13748104Syokota    if (scp->mouse_xpos < scp->xoff*8)
13848104Syokota	scp->mouse_xpos = scp->xoff*8;
13948104Syokota    if (scp->mouse_ypos < scp->yoff*scp->font_size)
14048104Syokota	scp->mouse_ypos = scp->yoff*scp->font_size;
14148104Syokota    if (ISGRAPHSC(scp)) {
14248104Syokota        if (scp->mouse_xpos > scp->xpixel-1)
14348104Syokota	    scp->mouse_xpos = scp->xpixel-1;
14448104Syokota        if (scp->mouse_ypos > scp->ypixel-1)
14548104Syokota	    scp->mouse_ypos = scp->ypixel-1;
14648104Syokota	return;
14748104Syokota    } else {
14848104Syokota	if (scp->mouse_xpos > (scp->xsize + scp->xoff)*8 - 1)
14948104Syokota	    scp->mouse_xpos = (scp->xsize + scp->xoff)*8 - 1;
15048104Syokota	if (scp->mouse_ypos > (scp->ysize + scp->yoff)*scp->font_size - 1)
15148104Syokota	    scp->mouse_ypos = (scp->ysize + scp->yoff)*scp->font_size - 1;
15248104Syokota    }
15348104Syokota
15458872Syokota    if (scp->mouse_xpos != scp->mouse_oldxpos || scp->mouse_ypos != scp->mouse_oldypos) {
15548104Syokota	scp->status |= MOUSE_MOVED;
15648104Syokota    	scp->mouse_pos =
15748104Syokota	    (scp->mouse_ypos/scp->font_size - scp->yoff)*scp->xsize
15848104Syokota		+ scp->mouse_xpos/8 - scp->xoff;
15948104Syokota#ifndef SC_NO_CUTPASTE
16048104Syokota	if ((scp->status & MOUSE_VISIBLE) && (scp->status & MOUSE_CUTTING))
16148104Syokota	    mouse_cut(scp);
16248104Syokota#endif
16348104Syokota    }
16448104Syokota}
16548104Syokota
16648104Syokota#ifndef SC_NO_CUTPASTE
16748104Syokota
16848104Syokotavoid
16948104Syokotasc_draw_mouse_image(scr_stat *scp)
17048104Syokota{
17148104Syokota    if (ISGRAPHSC(scp))
17248104Syokota	return;
17348104Syokota
17448104Syokota    ++scp->sc->videoio_in_progress;
17548104Syokota    (*scp->rndr->draw_mouse)(scp, scp->mouse_xpos, scp->mouse_ypos, TRUE);
17648104Syokota    scp->mouse_oldpos = scp->mouse_pos;
17758872Syokota    scp->mouse_oldxpos = scp->mouse_xpos;
17858872Syokota    scp->mouse_oldypos = scp->mouse_ypos;
17958872Syokota    scp->status |= MOUSE_VISIBLE;
18048104Syokota    --scp->sc->videoio_in_progress;
18148104Syokota}
18248104Syokota
18348104Syokotavoid
18448104Syokotasc_remove_mouse_image(scr_stat *scp)
18548104Syokota{
18648104Syokota    int size;
18748104Syokota    int i;
18848104Syokota
18948104Syokota    if (ISGRAPHSC(scp))
19048104Syokota	return;
19148104Syokota
19248104Syokota    ++scp->sc->videoio_in_progress;
19348104Syokota    (*scp->rndr->draw_mouse)(scp,
19448104Syokota			     (scp->mouse_oldpos%scp->xsize + scp->xoff)*8,
19548104Syokota			     (scp->mouse_oldpos/scp->xsize + scp->yoff)
19648104Syokota				 * scp->font_size,
19748104Syokota			     FALSE);
19848104Syokota    size = scp->xsize*scp->ysize;
19948104Syokota    i = scp->mouse_oldpos;
20048104Syokota    mark_for_update(scp, i);
20148104Syokota    mark_for_update(scp, i);
20248104Syokota#ifndef PC98
20348104Syokota    if (i + scp->xsize + 1 < size) {
20448104Syokota	mark_for_update(scp, i + scp->xsize + 1);
20548104Syokota    } else if (i + scp->xsize < size) {
20648104Syokota	mark_for_update(scp, i + scp->xsize);
20748104Syokota    } else if (i + 1 < size) {
20848104Syokota	mark_for_update(scp, i + 1);
20948104Syokota    }
21048104Syokota#endif /* PC98 */
21158872Syokota    scp->status &= ~MOUSE_VISIBLE;
21248104Syokota    --scp->sc->videoio_in_progress;
21348104Syokota}
21448104Syokota
21548104Syokotaint
21648104Syokotasc_inside_cutmark(scr_stat *scp, int pos)
21748104Syokota{
21848104Syokota    int start;
21948104Syokota    int end;
22048104Syokota
22148104Syokota    if (scp->mouse_cut_end < 0)
22248104Syokota	return FALSE;
22348104Syokota    if (scp->mouse_cut_start <= scp->mouse_cut_end) {
22448104Syokota	start = scp->mouse_cut_start;
22548104Syokota	end = scp->mouse_cut_end;
22648104Syokota    } else {
22748104Syokota	start = scp->mouse_cut_end;
22848104Syokota	end = scp->mouse_cut_start - 1;
22948104Syokota    }
23048104Syokota    return ((start <= pos) && (pos <= end));
23148104Syokota}
23248104Syokota
23348104Syokotavoid
23448104Syokotasc_remove_cutmarking(scr_stat *scp)
23548104Syokota{
23648104Syokota    int s;
23748104Syokota
23848104Syokota    s = spltty();
23948104Syokota    if (scp->mouse_cut_end >= 0) {
24048104Syokota	mark_for_update(scp, scp->mouse_cut_start);
24148104Syokota	mark_for_update(scp, scp->mouse_cut_end);
24248104Syokota    }
24348104Syokota    scp->mouse_cut_start = scp->xsize*scp->ysize;
24448104Syokota    scp->mouse_cut_end = -1;
24548104Syokota    splx(s);
24648104Syokota    scp->status &= ~MOUSE_CUTTING;
24748104Syokota}
24848104Syokota
24948104Syokotavoid
25048104Syokotasc_remove_all_cutmarkings(sc_softc_t *sc)
25148104Syokota{
25251404Syokota    scr_stat *scp;
25348104Syokota    int i;
25448104Syokota
25548104Syokota    /* delete cut markings in all vtys */
25648104Syokota    for (i = 0; i < sc->vtys; ++i) {
25751404Syokota	scp = SC_STAT(sc->dev[i]);
25851404Syokota	if (scp == NULL)
25948104Syokota	    continue;
26051404Syokota	sc_remove_cutmarking(scp);
26148104Syokota    }
26248104Syokota}
26348104Syokota
26448104Syokotavoid
26548104Syokotasc_remove_all_mouse(sc_softc_t *sc)
26648104Syokota{
26751404Syokota    scr_stat *scp;
26848104Syokota    int i;
26948104Syokota
27048104Syokota    for (i = 0; i < sc->vtys; ++i) {
27151404Syokota	scp = SC_STAT(sc->dev[i]);
27251404Syokota	if (scp == NULL)
27348104Syokota	    continue;
27451404Syokota	if (scp->status & MOUSE_VISIBLE) {
27551404Syokota	    scp->status &= ~MOUSE_VISIBLE;
27651404Syokota	    mark_all(scp);
27748104Syokota	}
27848104Syokota    }
27948104Syokota}
28048104Syokota
28152813Sarchie#define IS_SPACE_CHAR(c)	(((c) & 0xff) == ' ')
28248104Syokota
28348104Syokota/* skip spaces to right */
28448104Syokotastatic int
28548104Syokotaskip_spc_right(scr_stat *scp, int p)
28648104Syokota{
28748104Syokota    int c;
28848104Syokota    int i;
28948104Syokota
29048104Syokota    for (i = p % scp->xsize; i < scp->xsize; ++i) {
29148104Syokota	c = sc_vtb_getc(&scp->vtb, p);
29252813Sarchie	if (!IS_SPACE_CHAR(c))
29348104Syokota	    break;
29448104Syokota	++p;
29548104Syokota    }
29648104Syokota    return i;
29748104Syokota}
29848104Syokota
29948104Syokota/* skip spaces to left */
30048104Syokotastatic int
30148104Syokotaskip_spc_left(scr_stat *scp, int p)
30248104Syokota{
30348104Syokota    int c;
30448104Syokota    int i;
30548104Syokota
30648104Syokota    for (i = p-- % scp->xsize - 1; i >= 0; --i) {
30748104Syokota	c = sc_vtb_getc(&scp->vtb, p);
30852813Sarchie	if (!IS_SPACE_CHAR(c))
30948104Syokota	    break;
31048104Syokota	--p;
31148104Syokota    }
31248104Syokota    return i;
31348104Syokota}
31448104Syokota
31548104Syokota/* copy marked region to the cut buffer */
31648104Syokotastatic void
31748104Syokotamouse_cut(scr_stat *scp)
31848104Syokota{
31948104Syokota    int start;
32048104Syokota    int end;
32148104Syokota    int from;
32248104Syokota    int to;
32348104Syokota    int blank;
32448104Syokota    int c;
32548104Syokota    int p;
32648104Syokota    int s;
32748104Syokota    int i;
32848104Syokota
32948104Syokota    start = scp->mouse_cut_start;
33048104Syokota    end = scp->mouse_cut_end;
33148104Syokota    if (scp->mouse_pos >= start) {
33248104Syokota	from = start;
33348104Syokota	to = end = scp->mouse_pos;
33448104Syokota    } else {
33548104Syokota	from = end = scp->mouse_pos;
33648104Syokota	to = start - 1;
33748104Syokota    }
33848104Syokota    for (p = from, i = blank = 0; p <= to; ++p) {
33948104Syokota	cut_buffer[i] = sc_vtb_getc(&scp->vtb, p);
34048104Syokota	/* remember the position of the last non-space char */
34152813Sarchie	if (!IS_SPACE_CHAR(cut_buffer[i++]))
34248104Syokota	    blank = i;		/* the first space after the last non-space */
34348104Syokota	/* trim trailing blank when crossing lines */
34448104Syokota	if ((p % scp->xsize) == (scp->xsize - 1)) {
34548104Syokota	    cut_buffer[blank] = '\r';
34648104Syokota	    i = blank + 1;
34748104Syokota	}
34848104Syokota    }
34948104Syokota    cut_buffer[i] = '\0';
35048104Syokota
35148104Syokota    /* scan towards the end of the last line */
35248104Syokota    --p;
35348104Syokota    for (i = p % scp->xsize; i < scp->xsize; ++i) {
35448104Syokota	c = sc_vtb_getc(&scp->vtb, p);
35552813Sarchie	if (!IS_SPACE_CHAR(c))
35648104Syokota	    break;
35748104Syokota	++p;
35848104Syokota    }
35948104Syokota    /* if there is nothing but blank chars, trim them, but mark towards eol */
36048104Syokota    if (i >= scp->xsize) {
36148104Syokota	if (end >= start)
36248104Syokota	    to = end = p - 1;
36348104Syokota	else
36448104Syokota	    to = start = p;
36548104Syokota	cut_buffer[blank++] = '\r';
36648104Syokota	cut_buffer[blank] = '\0';
36748104Syokota    }
36848104Syokota
36948104Syokota    /* remove the current marking */
37048104Syokota    s = spltty();
37148104Syokota    if (scp->mouse_cut_start <= scp->mouse_cut_end) {
37248104Syokota	mark_for_update(scp, scp->mouse_cut_start);
37348104Syokota	mark_for_update(scp, scp->mouse_cut_end);
37448104Syokota    } else if (scp->mouse_cut_end >= 0) {
37548104Syokota	mark_for_update(scp, scp->mouse_cut_end);
37648104Syokota	mark_for_update(scp, scp->mouse_cut_start);
37748104Syokota    }
37848104Syokota
37948104Syokota    /* mark the new region */
38048104Syokota    scp->mouse_cut_start = start;
38148104Syokota    scp->mouse_cut_end = end;
38248104Syokota    mark_for_update(scp, from);
38348104Syokota    mark_for_update(scp, to);
38448104Syokota    splx(s);
38548104Syokota}
38648104Syokota
38748104Syokota/* a mouse button is pressed, start cut operation */
38848104Syokotastatic void
38948104Syokotamouse_cut_start(scr_stat *scp)
39048104Syokota{
39148104Syokota    int i;
39248104Syokota    int j;
39348104Syokota    int s;
39448104Syokota
39548104Syokota    if (scp->status & MOUSE_VISIBLE) {
39648104Syokota	i = scp->mouse_cut_start;
39748104Syokota	j = scp->mouse_cut_end;
39848104Syokota	sc_remove_all_cutmarkings(scp->sc);
39948104Syokota	if (scp->mouse_pos == i && i == j) {
40048104Syokota	    cut_buffer[0] = '\0';
40148104Syokota	} else if (skip_spc_right(scp, scp->mouse_pos) >= scp->xsize) {
40248104Syokota	    /* if the pointer is on trailing blank chars, mark towards eol */
40348104Syokota	    i = skip_spc_left(scp, scp->mouse_pos) + 1;
40448104Syokota	    s = spltty();
40548104Syokota	    scp->mouse_cut_start =
40648104Syokota	        (scp->mouse_pos / scp->xsize) * scp->xsize + i;
40748104Syokota	    scp->mouse_cut_end =
40848104Syokota	        (scp->mouse_pos / scp->xsize + 1) * scp->xsize - 1;
40948104Syokota	    splx(s);
41048104Syokota	    cut_buffer[0] = '\r';
41148104Syokota	    cut_buffer[1] = '\0';
41248104Syokota	    scp->status |= MOUSE_CUTTING;
41348104Syokota	} else {
41448104Syokota	    s = spltty();
41548104Syokota	    scp->mouse_cut_start = scp->mouse_pos;
41648104Syokota	    scp->mouse_cut_end = scp->mouse_cut_start;
41748104Syokota	    splx(s);
41848104Syokota	    cut_buffer[0] = sc_vtb_getc(&scp->vtb, scp->mouse_cut_start);
41948104Syokota	    cut_buffer[1] = '\0';
42048104Syokota	    scp->status |= MOUSE_CUTTING;
42148104Syokota	}
42248104Syokota    	mark_all(scp);	/* this is probably overkill XXX */
42348104Syokota    }
42448104Syokota}
42548104Syokota
42648104Syokota/* end of cut operation */
42748104Syokotastatic void
42848104Syokotamouse_cut_end(scr_stat *scp)
42948104Syokota{
43048104Syokota    if (scp->status & MOUSE_VISIBLE)
43148104Syokota	scp->status &= ~MOUSE_CUTTING;
43248104Syokota}
43348104Syokota
43448104Syokota/* copy a word under the mouse pointer */
43548104Syokotastatic void
43648104Syokotamouse_cut_word(scr_stat *scp)
43748104Syokota{
43848104Syokota    int start;
43948104Syokota    int end;
44048104Syokota    int sol;
44148104Syokota    int eol;
44248104Syokota    int c;
44348104Syokota    int s;
44448104Syokota    int i;
44548104Syokota    int j;
44648104Syokota
44748104Syokota    /*
44848104Syokota     * Because we don't have locale information in the kernel,
44948104Syokota     * we only distinguish space char and non-space chars.  Punctuation
45048104Syokota     * chars, symbols and other regular chars are all treated alike.
45148104Syokota     */
45248104Syokota    if (scp->status & MOUSE_VISIBLE) {
45348104Syokota	/* remove the current cut mark */
45448104Syokota	s = spltty();
45548104Syokota	if (scp->mouse_cut_start <= scp->mouse_cut_end) {
45648104Syokota	    mark_for_update(scp, scp->mouse_cut_start);
45748104Syokota	    mark_for_update(scp, scp->mouse_cut_end);
45848104Syokota	} else if (scp->mouse_cut_end >= 0) {
45948104Syokota	    mark_for_update(scp, scp->mouse_cut_end);
46048104Syokota	    mark_for_update(scp, scp->mouse_cut_start);
46148104Syokota	}
46248104Syokota	scp->mouse_cut_start = scp->xsize*scp->ysize;
46348104Syokota	scp->mouse_cut_end = -1;
46448104Syokota	splx(s);
46548104Syokota
46648104Syokota	sol = (scp->mouse_pos / scp->xsize) * scp->xsize;
46748104Syokota	eol = sol + scp->xsize;
46848104Syokota	c = sc_vtb_getc(&scp->vtb, scp->mouse_pos);
46952813Sarchie	if (IS_SPACE_CHAR(c)) {
47048104Syokota	    /* blank space */
47148104Syokota	    for (j = scp->mouse_pos; j >= sol; --j) {
47248104Syokota		c = sc_vtb_getc(&scp->vtb, j);
47352813Sarchie	        if (!IS_SPACE_CHAR(c))
47448104Syokota		    break;
47548104Syokota	    }
47648104Syokota	    start = ++j;
47748104Syokota	    for (j = scp->mouse_pos; j < eol; ++j) {
47848104Syokota		c = sc_vtb_getc(&scp->vtb, j);
47952813Sarchie	        if (!IS_SPACE_CHAR(c))
48048104Syokota		    break;
48148104Syokota	    }
48248104Syokota	    end = j - 1;
48348104Syokota	} else {
48448104Syokota	    /* non-space word */
48548104Syokota	    for (j = scp->mouse_pos; j >= sol; --j) {
48648104Syokota		c = sc_vtb_getc(&scp->vtb, j);
48752813Sarchie	        if (IS_SPACE_CHAR(c))
48848104Syokota		    break;
48948104Syokota	    }
49048104Syokota	    start = ++j;
49148104Syokota	    for (j = scp->mouse_pos; j < eol; ++j) {
49248104Syokota		c = sc_vtb_getc(&scp->vtb, j);
49352813Sarchie	        if (IS_SPACE_CHAR(c))
49448104Syokota		    break;
49548104Syokota	    }
49648104Syokota	    end = j - 1;
49748104Syokota	}
49848104Syokota
49948104Syokota	/* copy the found word */
50048104Syokota	for (i = 0, j = start; j <= end; ++j)
50148104Syokota	    cut_buffer[i++] = sc_vtb_getc(&scp->vtb, j);
50248104Syokota	cut_buffer[i] = '\0';
50348104Syokota	scp->status |= MOUSE_CUTTING;
50448104Syokota
50548104Syokota	/* mark the region */
50648104Syokota	s = spltty();
50748104Syokota	scp->mouse_cut_start = start;
50848104Syokota	scp->mouse_cut_end = end;
50948104Syokota	mark_for_update(scp, start);
51048104Syokota	mark_for_update(scp, end);
51148104Syokota	splx(s);
51248104Syokota    }
51348104Syokota}
51448104Syokota
51548104Syokota/* copy a line under the mouse pointer */
51648104Syokotastatic void
51748104Syokotamouse_cut_line(scr_stat *scp)
51848104Syokota{
51948104Syokota    int s;
52048104Syokota    int i;
52148104Syokota    int j;
52248104Syokota
52348104Syokota    if (scp->status & MOUSE_VISIBLE) {
52448104Syokota	/* remove the current cut mark */
52548104Syokota	s = spltty();
52648104Syokota	if (scp->mouse_cut_start <= scp->mouse_cut_end) {
52748104Syokota	    mark_for_update(scp, scp->mouse_cut_start);
52848104Syokota	    mark_for_update(scp, scp->mouse_cut_end);
52948104Syokota	} else if (scp->mouse_cut_end >= 0) {
53048104Syokota	    mark_for_update(scp, scp->mouse_cut_end);
53148104Syokota	    mark_for_update(scp, scp->mouse_cut_start);
53248104Syokota	}
53348104Syokota
53448104Syokota	/* mark the entire line */
53548104Syokota	scp->mouse_cut_start =
53648104Syokota	    (scp->mouse_pos / scp->xsize) * scp->xsize;
53748104Syokota	scp->mouse_cut_end = scp->mouse_cut_start + scp->xsize - 1;
53848104Syokota	mark_for_update(scp, scp->mouse_cut_start);
53948104Syokota	mark_for_update(scp, scp->mouse_cut_end);
54048104Syokota	splx(s);
54148104Syokota
54248104Syokota	/* copy the line into the cut buffer */
54348104Syokota	for (i = 0, j = scp->mouse_cut_start; j <= scp->mouse_cut_end; ++j)
54448104Syokota	    cut_buffer[i++] = sc_vtb_getc(&scp->vtb, j);
54548104Syokota	cut_buffer[i++] = '\r';
54648104Syokota	cut_buffer[i] = '\0';
54748104Syokota	scp->status |= MOUSE_CUTTING;
54848104Syokota    }
54948104Syokota}
55048104Syokota
55148104Syokota/* extend the marked region to the mouse pointer position */
55248104Syokotastatic void
55348104Syokotamouse_cut_extend(scr_stat *scp)
55448104Syokota{
55548104Syokota    int start;
55648104Syokota    int end;
55748104Syokota    int s;
55848104Syokota
55948104Syokota    if ((scp->status & MOUSE_VISIBLE) && !(scp->status & MOUSE_CUTTING)
56048104Syokota	&& (scp->mouse_cut_end >= 0)) {
56148104Syokota	if (scp->mouse_cut_start <= scp->mouse_cut_end) {
56248104Syokota	    start = scp->mouse_cut_start;
56348104Syokota	    end = scp->mouse_cut_end;
56448104Syokota	} else {
56548104Syokota	    start = scp->mouse_cut_end;
56648104Syokota	    end = scp->mouse_cut_start - 1;
56748104Syokota	}
56848104Syokota	s = spltty();
56948104Syokota	if (scp->mouse_pos > end) {
57048104Syokota	    scp->mouse_cut_start = start;
57148104Syokota	    scp->mouse_cut_end = end;
57248104Syokota	} else if (scp->mouse_pos < start) {
57348104Syokota	    scp->mouse_cut_start = end + 1;
57448104Syokota	    scp->mouse_cut_end = start;
57548104Syokota	} else {
57648104Syokota	    if (scp->mouse_pos - start > end + 1 - scp->mouse_pos) {
57748104Syokota		scp->mouse_cut_start = start;
57848104Syokota		scp->mouse_cut_end = end;
57948104Syokota	    } else {
58048104Syokota		scp->mouse_cut_start = end + 1;
58148104Syokota		scp->mouse_cut_end = start;
58248104Syokota	    }
58348104Syokota	}
58448104Syokota	splx(s);
58548104Syokota	mouse_cut(scp);
58648104Syokota	scp->status |= MOUSE_CUTTING;
58748104Syokota    }
58848104Syokota}
58948104Syokota
59048104Syokota/* paste cut buffer contents into the current vty */
59148104Syokotastatic void
59248104Syokotamouse_paste(scr_stat *scp)
59348104Syokota{
59448104Syokota    if (scp->status & MOUSE_VISIBLE)
59548104Syokota	sc_paste(scp, cut_buffer, strlen(cut_buffer));
59648104Syokota}
59748104Syokota
59848104Syokota#endif /* SC_NO_CUTPASTE */
59948104Syokota
60048104Syokotaint
60148104Syokotasc_mouse_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag,
60248104Syokota	       struct proc *p)
60348104Syokota{
60456043Syokota    mouse_info_t *mouse;
60556043Syokota    mouse_info_t buf;
60656043Syokota    scr_stat *cur_scp;
60748104Syokota    scr_stat *scp;
60848104Syokota    int s;
60956043Syokota    int f;
61048104Syokota
61151404Syokota    scp = SC_STAT(tp->t_dev);
61248104Syokota
61348104Syokota    switch (cmd) {
61448104Syokota
61548104Syokota    case CONS_MOUSECTL:		/* control mouse arrow */
61648104Syokota    case OLD_CONS_MOUSECTL:
61748104Syokota
61856043Syokota	mouse = (mouse_info_t*)data;
61948104Syokota	if (cmd == OLD_CONS_MOUSECTL) {
62048104Syokota	    static u_char swapb[] = { 0, 4, 2, 6, 1, 5, 3, 7 };
62148104Syokota	    old_mouse_info_t *old_mouse = (old_mouse_info_t *)data;
62248104Syokota
62348104Syokota	    mouse = &buf;
62448104Syokota	    mouse->operation = old_mouse->operation;
62548104Syokota	    switch (mouse->operation) {
62648104Syokota	    case MOUSE_MODE:
62748104Syokota		mouse->u.mode = old_mouse->u.mode;
62848104Syokota		break;
62948104Syokota	    case MOUSE_SHOW:
63048104Syokota	    case MOUSE_HIDE:
63148104Syokota		break;
63248104Syokota	    case MOUSE_MOVEABS:
63348104Syokota	    case MOUSE_MOVEREL:
63448104Syokota	    case MOUSE_ACTION:
63548104Syokota		mouse->u.data.x = old_mouse->u.data.x;
63648104Syokota		mouse->u.data.y = old_mouse->u.data.y;
63748104Syokota		mouse->u.data.z = 0;
63848104Syokota		mouse->u.data.buttons = swapb[old_mouse->u.data.buttons & 0x7];
63948104Syokota		break;
64048104Syokota	    case MOUSE_GETINFO:
64148104Syokota		old_mouse->u.data.x = scp->mouse_xpos;
64248104Syokota		old_mouse->u.data.y = scp->mouse_ypos;
64348104Syokota		old_mouse->u.data.buttons = swapb[scp->mouse_buttons & 0x7];
64448104Syokota		break;
64548104Syokota	    default:
64648104Syokota		return EINVAL;
64748104Syokota	    }
64848104Syokota	}
64948104Syokota
65048104Syokota	cur_scp = scp->sc->cur_scp;
65148104Syokota
65248104Syokota	switch (mouse->operation) {
65348104Syokota	case MOUSE_MODE:
65448104Syokota	    if (ISSIGVALID(mouse->u.mode.signal)) {
65548104Syokota		scp->mouse_signal = mouse->u.mode.signal;
65648104Syokota		scp->mouse_proc = p;
65748104Syokota		scp->mouse_pid = p->p_pid;
65848104Syokota	    }
65948104Syokota	    else {
66048104Syokota		scp->mouse_signal = 0;
66148104Syokota		scp->mouse_proc = NULL;
66248104Syokota		scp->mouse_pid = 0;
66348104Syokota	    }
66448104Syokota	    return 0;
66548104Syokota
66648104Syokota	case MOUSE_SHOW:
66748104Syokota	    if (!ISMOUSEAVAIL(scp->sc->adp->va_flags))
66848104Syokota		return EINVAL;
66948104Syokota	    s = spltty();
67048104Syokota	    if (!(scp->sc->flags & SC_MOUSE_ENABLED)) {
67148104Syokota		scp->sc->flags |= SC_MOUSE_ENABLED;
67258872Syokota		cur_scp->status &= ~MOUSE_HIDDEN;
67358872Syokota		if (!ISGRAPHSC(cur_scp))
67448104Syokota		    mark_all(cur_scp);
67548104Syokota		splx(s);
67648104Syokota		return 0;
67748104Syokota	    } else {
67848104Syokota		splx(s);
67948104Syokota		return EINVAL;
68048104Syokota	    }
68148104Syokota	    break;
68248104Syokota
68348104Syokota	case MOUSE_HIDE:
68448104Syokota	    s = spltty();
68548104Syokota	    if (scp->sc->flags & SC_MOUSE_ENABLED) {
68648104Syokota		scp->sc->flags &= ~SC_MOUSE_ENABLED;
68748104Syokota		sc_remove_all_mouse(scp->sc);
68848104Syokota		splx(s);
68948104Syokota		return 0;
69048104Syokota	    } else {
69148104Syokota		splx(s);
69248104Syokota		return EINVAL;
69348104Syokota	    }
69448104Syokota	    break;
69548104Syokota
69648104Syokota	case MOUSE_MOVEABS:
69748104Syokota	    s = spltty();
69848104Syokota	    scp->mouse_xpos = mouse->u.data.x;
69948104Syokota	    scp->mouse_ypos = mouse->u.data.y;
70048104Syokota	    set_mouse_pos(scp);
70148104Syokota	    splx(s);
70248104Syokota	    break;
70348104Syokota
70448104Syokota	case MOUSE_MOVEREL:
70548104Syokota	    s = spltty();
70648104Syokota	    scp->mouse_xpos += mouse->u.data.x;
70748104Syokota	    scp->mouse_ypos += mouse->u.data.y;
70848104Syokota	    set_mouse_pos(scp);
70948104Syokota	    splx(s);
71048104Syokota	    break;
71148104Syokota
71248104Syokota	case MOUSE_GETINFO:
71348104Syokota	    mouse->u.data.x = scp->mouse_xpos;
71448104Syokota	    mouse->u.data.y = scp->mouse_ypos;
71548104Syokota	    mouse->u.data.z = 0;
71648104Syokota	    mouse->u.data.buttons = scp->mouse_buttons;
71748104Syokota	    return 0;
71848104Syokota
71948104Syokota	case MOUSE_ACTION:
72048104Syokota	case MOUSE_MOTION_EVENT:
72148104Syokota	    /* send out mouse event on /dev/sysmouse */
72248104Syokota#if 0
72348104Syokota	    /* this should maybe only be settable from /dev/consolectl SOS */
72448104Syokota	    if (SC_VTY(tp->t_dev) != SC_CONSOLECTL)
72548104Syokota		return ENOTTY;
72648104Syokota#endif
72753057Syokota	    s = spltty();
72853057Syokota	    if (mouse->u.data.x != 0 || mouse->u.data.y != 0) {
72953057Syokota		cur_scp->mouse_xpos += mouse->u.data.x;
73053057Syokota		cur_scp->mouse_ypos += mouse->u.data.y;
73153057Syokota		set_mouse_pos(cur_scp);
73253057Syokota	    }
73353057Syokota	    f = 0;
73453057Syokota	    if (mouse->operation == MOUSE_ACTION) {
73553057Syokota		f = cur_scp->mouse_buttons ^ mouse->u.data.buttons;
73653057Syokota		cur_scp->mouse_buttons = mouse->u.data.buttons;
73753057Syokota	    }
73853057Syokota	    splx(s);
73953057Syokota
74056043Syokota	    if (sysmouse_event(mouse) == 0)
74148104Syokota		return 0;
74248104Syokota
74348104Syokota	    /*
74448104Syokota	     * If any buttons are down or the mouse has moved a lot,
74548104Syokota	     * stop the screen saver.
74648104Syokota	     */
74748104Syokota	    if (((mouse->operation == MOUSE_ACTION) && mouse->u.data.buttons)
74848104Syokota		|| (mouse->u.data.x*mouse->u.data.x
74948104Syokota			+ mouse->u.data.y*mouse->u.data.y
75048104Syokota			>= SC_WAKEUP_DELTA*SC_WAKEUP_DELTA)) {
75148104Syokota		sc_touch_scrn_saver();
75248104Syokota	    }
75348104Syokota
75458872Syokota	    cur_scp->status &= ~MOUSE_HIDDEN;
75554182Syokota
75654182Syokota	    if (cur_scp->mouse_signal) {
75754182Syokota    		/* has controlling process died? */
75854182Syokota		if (cur_scp->mouse_proc &&
75954182Syokota		    (cur_scp->mouse_proc != pfind(cur_scp->mouse_pid))){
76054182Syokota		    	cur_scp->mouse_signal = 0;
76154182Syokota			cur_scp->mouse_proc = NULL;
76254182Syokota			cur_scp->mouse_pid = 0;
76354182Syokota		} else {
76454182Syokota		    psignal(cur_scp->mouse_proc, cur_scp->mouse_signal);
76554182Syokota		    break;
76654182Syokota		}
76754182Syokota	    }
76854182Syokota
76948104Syokota	    if (ISGRAPHSC(cur_scp) || (cut_buffer == NULL))
77048104Syokota		break;
77148104Syokota
77248104Syokota#ifndef SC_NO_CUTPASTE
77353057Syokota	    if ((mouse->operation == MOUSE_ACTION) && f) {
77448104Syokota		/* process button presses */
77553057Syokota		if (cur_scp->mouse_buttons & MOUSE_BUTTON1DOWN)
77653057Syokota		    mouse_cut_start(cur_scp);
77753057Syokota		else
77853057Syokota		    mouse_cut_end(cur_scp);
77953057Syokota		if (cur_scp->mouse_buttons & MOUSE_BUTTON2DOWN ||
78053057Syokota		    cur_scp->mouse_buttons & MOUSE_BUTTON3DOWN)
78153057Syokota		    mouse_paste(cur_scp);
78248104Syokota	    }
78348104Syokota#endif /* SC_NO_CUTPASTE */
78448104Syokota	    break;
78548104Syokota
78648104Syokota	case MOUSE_BUTTON_EVENT:
78748104Syokota	    if ((mouse->u.event.id & MOUSE_BUTTONS) == 0)
78848104Syokota		return EINVAL;
78948104Syokota	    if (mouse->u.event.value < 0)
79048104Syokota		return EINVAL;
79148104Syokota#if 0
79248104Syokota	    /* this should maybe only be settable from /dev/consolectl SOS */
79348104Syokota	    if (SC_VTY(tp->t_dev) != SC_CONSOLECTL)
79448104Syokota		return ENOTTY;
79548104Syokota#endif
79656043Syokota	    if (mouse->u.event.value > 0)
79748104Syokota		cur_scp->mouse_buttons |= mouse->u.event.id;
79856043Syokota	    else
79948104Syokota		cur_scp->mouse_buttons &= ~mouse->u.event.id;
80056043Syokota
80156043Syokota	    if (sysmouse_event(mouse) == 0)
80248104Syokota		return 0;
80348104Syokota
80454182Syokota	    /* if a button is held down, stop the screen saver */
80554182Syokota	    if (mouse->u.event.value > 0)
80654182Syokota		sc_touch_scrn_saver();
80754182Syokota
80858872Syokota	    cur_scp->status &= ~MOUSE_HIDDEN;
80954182Syokota
81048104Syokota	    if (cur_scp->mouse_signal) {
81148104Syokota		if (cur_scp->mouse_proc &&
81248104Syokota		    (cur_scp->mouse_proc != pfind(cur_scp->mouse_pid))){
81348104Syokota		    	cur_scp->mouse_signal = 0;
81448104Syokota			cur_scp->mouse_proc = NULL;
81548104Syokota			cur_scp->mouse_pid = 0;
81654182Syokota		} else {
81754182Syokota		    psignal(cur_scp->mouse_proc, cur_scp->mouse_signal);
81854182Syokota		    break;
81948104Syokota		}
82048104Syokota	    }
82148104Syokota
82248104Syokota	    if (ISGRAPHSC(cur_scp) || (cut_buffer == NULL))
82348104Syokota		break;
82448104Syokota
82548104Syokota#ifndef SC_NO_CUTPASTE
82648104Syokota	    switch (mouse->u.event.id) {
82748104Syokota	    case MOUSE_BUTTON1DOWN:
82848104Syokota	        switch (mouse->u.event.value % 4) {
82948104Syokota		case 0:	/* up */
83048104Syokota		    mouse_cut_end(cur_scp);
83148104Syokota		    break;
83248104Syokota		case 1: /* single click: start cut operation */
83348104Syokota		    mouse_cut_start(cur_scp);
83448104Syokota		    break;
83548104Syokota		case 2:	/* double click: cut a word */
83648104Syokota		    mouse_cut_word(cur_scp);
83748104Syokota		    mouse_cut_end(cur_scp);
83848104Syokota		    break;
83948104Syokota		case 3:	/* triple click: cut a line */
84048104Syokota		    mouse_cut_line(cur_scp);
84148104Syokota		    mouse_cut_end(cur_scp);
84248104Syokota		    break;
84348104Syokota		}
84448104Syokota		break;
84553011Syokota	    case SC_MOUSE_PASTEBUTTON:
84648104Syokota	        switch (mouse->u.event.value) {
84748104Syokota		case 0:	/* up */
84848104Syokota		    break;
84948104Syokota		default:
85048104Syokota		    mouse_paste(cur_scp);
85148104Syokota		    break;
85248104Syokota		}
85348104Syokota		break;
85453011Syokota	    case SC_MOUSE_EXTENDBUTTON:
85548104Syokota	        switch (mouse->u.event.value) {
85648104Syokota		case 0:	/* up */
85748104Syokota		    if (!(cur_scp->mouse_buttons & MOUSE_BUTTON1DOWN))
85848104Syokota		        mouse_cut_end(cur_scp);
85948104Syokota		    break;
86048104Syokota		default:
86148104Syokota		    mouse_cut_extend(cur_scp);
86248104Syokota		    break;
86348104Syokota		}
86448104Syokota		break;
86548104Syokota	    }
86648104Syokota#endif /* SC_NO_CUTPASTE */
86748104Syokota	    break;
86848104Syokota
86955849Syokota	case MOUSE_MOUSECHAR:
87055849Syokota	    if (mouse->u.mouse_char < 0) {
87155849Syokota		mouse->u.mouse_char = scp->sc->mouse_char;
87255849Syokota	    } else {
87355849Syokota		if (mouse->u.mouse_char >= UCHAR_MAX - 4)
87455849Syokota		    return EINVAL;
87556043Syokota		s = spltty();
87655849Syokota		sc_remove_all_mouse(scp->sc);
87755849Syokota#ifndef SC_NO_FONT_LOADING
87856328Syokota		if (ISTEXTSC(cur_scp) && (cur_scp->font != NULL))
87956043Syokota		    sc_load_font(cur_scp, 0, cur_scp->font_size, cur_scp->font,
88056043Syokota				 cur_scp->sc->mouse_char, 4);
88155849Syokota#endif
88255849Syokota		scp->sc->mouse_char = mouse->u.mouse_char;
88355849Syokota		splx(s);
88455849Syokota	    }
88555849Syokota	    break;
88655849Syokota
88748104Syokota	default:
88848104Syokota	    return EINVAL;
88948104Syokota	}
89048104Syokota
89148104Syokota	return 0;
89248104Syokota    }
89348104Syokota
89448104Syokota    return ENOIOCTL;
89548104Syokota}
89648104Syokota
89748104Syokota#endif /* SC_NO_SYSMOUSE */
898