freebsd-dev/sys/dev/syscons/scmouse.c
Kazutaka YOKOTA 6e8394b8ba The second phase of syscons reorganization.
- Split syscons source code into manageable chunks and reorganize
  some of complicated functions.

- Many static variables are moved to the softc structure.

- Added a new key function, PREV.  When this key is pressed, the vty
  immediately before the current vty will become foreground.  Analogue
  to PREV, which is usually assigned to the PrntScrn key.
  PR: kern/10113
  Submitted by: Christian Weisgerber <naddy@mips.rhein-neckar.de>

- Modified the kernel console input function sccngetc() so that it
  handles function keys properly.

- Reorganized the screen update routine.

- VT switching code is reorganized.  It now should be slightly more
  robust than before.

- Added the DEVICE_RESUME function so that syscons no longer hooks the
  APM resume event directly.

- New kernel configuration options: SC_NO_CUTPASTE, SC_NO_FONT_LOADING,
  SC_NO_HISTORY and SC_NO_SYSMOUSE.
  Various parts of syscons can be omitted so that the kernel size is
  reduced.

  SC_PIXEL_MODE
  Made the VESA 800x600 mode an option, rather than a standard part of
  syscons.

  SC_DISABLE_DDBKEY
  Disables the `debug' key combination.

  SC_ALT_MOUSE_IMAGE
  Inverse the character cell at the mouse cursor position in the text
  console, rather than drawing an arrow on the screen.
  Submitted by: Nick Hibma (n_hibma@FreeBSD.ORG)

  SC_DFLT_FONT
  makeoptions "SC_DFLT_FONT=_font_name_"
  Include the named font as the default font of syscons.  16-line,
  14-line and 8-line font data will be compiled in.  This option replaces
  the existing STD8X16FONT option, which loads 16-line font data only.

- The VGA driver is split into /sys/dev/fb/vga.c and /sys/isa/vga_isa.c.

- The video driver provides a set of ioctl commands to manipulate the
  frame buffer.

- New kernel configuration option: VGA_WIDTH90
  Enables 90 column modes: 90x25, 90x30, 90x43, 90x50, 90x60.  These
  modes are mot always supported by the video card.
  PR: i386/7510
  Submitted by: kbyanc@freedomnet.com and alexv@sui.gda.itesm.mx.

- The header file machine/console.h is reorganized; its contents is now
  split into sys/fbio.h, sys/kbio.h (a new file) and sys/consio.h
  (another new file).  machine/console.h is still maintained for
  compatibility reasons.

- Kernel console selection/installation routines are fixed and
  slightly rebumped so that it should now be possible to switch between
  the interanl kernel console (sc or vt) and a remote kernel console
  (sio) again, as it was in 2.x, 3.0 and 3.1.

- Screen savers and splash screen decoders
  Because of the header file reorganization described above, screen
  savers and splash screen decoders are slightly modified.  After this
  update, /sys/modules/syscons/saver.h is no longer necessary and is
  removed.
1999-06-22 14:14:06 +00:00

1084 lines
27 KiB
C

/*-
* Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer as
* the first lines of this file unmodified.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id:$
*/
#include "sc.h"
#include "opt_syscons.h"
#if NSC > 0
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/signalvar.h>
#include <sys/proc.h>
#include <sys/tty.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <machine/console.h>
#include <machine/mouse.h>
#include <dev/syscons/syscons.h>
#define SC_WAKEUP_DELTA 20
/* for backward compatibility */
#define OLD_CONS_MOUSECTL _IOWR('c', 10, old_mouse_info_t)
typedef struct old_mouse_data {
int x;
int y;
int buttons;
} old_mouse_data_t;
typedef struct old_mouse_info {
int operation;
union {
struct old_mouse_data data;
struct mouse_mode mode;
} u;
} old_mouse_info_t;
/* local variables */
#ifndef SC_NO_SYSMOUSE
static int mouse_level; /* sysmouse protocol level */
static mousestatus_t mouse_status = { 0, 0, 0, 0, 0, 0 };
static int cut_buffer_size;
static u_char *cut_buffer;
#endif /* SC_NO_SYSMOUE */
/* local functions */
#ifndef SC_NO_SYSMOUSE
static void set_mouse_pos(scr_stat *scp);
#ifndef SC_NO_CUTPASTE
static int skip_spc_right(scr_stat *scp, int p);
static int skip_spc_left(scr_stat *scp, int p);
static void mouse_cut(scr_stat *scp);
static void mouse_cut_start(scr_stat *scp);
static void mouse_cut_end(scr_stat *scp);
static void mouse_cut_word(scr_stat *scp);
static void mouse_cut_line(scr_stat *scp);
static void mouse_cut_extend(scr_stat *scp);
static void mouse_paste(scr_stat *scp);
#endif /* SC_NO_CUTPASTE */
#endif /* SC_NO_SYSMOUE */
#ifndef SC_NO_CUTPASTE
/* allocate a cut buffer */
void
sc_alloc_cut_buffer(scr_stat *scp, int wait)
{
u_char *p;
if ((cut_buffer == NULL)
|| (cut_buffer_size < scp->xsize * scp->ysize + 1)) {
p = cut_buffer;
cut_buffer = NULL;
if (p != NULL)
free(p, M_DEVBUF);
cut_buffer_size = scp->xsize * scp->ysize + 1;
p = (u_char *)malloc(cut_buffer_size,
M_DEVBUF, (wait) ? M_WAITOK : M_NOWAIT);
if (p != NULL)
p[0] = '\0';
cut_buffer = p;
}
}
#endif /* SC_NO_CUTPASTE */
#ifndef SC_NO_SYSMOUSE
/* modify the sysmouse software level */
void
sc_mouse_set_level(int level)
{
mouse_level = level;
}
/* move mouse */
void
sc_mouse_move(scr_stat *scp, int x, int y)
{
int s;
s = spltty();
scp->mouse_xpos = x;
scp->mouse_ypos = y;
scp->mouse_pos = scp->mouse_oldpos =
(y/scp->font_size - scp->yoff)*scp->xsize + x/8 - scp->xoff;
splx(s);
}
/* adjust mouse position */
static void
set_mouse_pos(scr_stat *scp)
{
static int last_xpos = -1, last_ypos = -1;
if (scp->mouse_xpos < scp->xoff*8)
scp->mouse_xpos = scp->xoff*8;
if (scp->mouse_ypos < scp->yoff*scp->font_size)
scp->mouse_ypos = scp->yoff*scp->font_size;
if (ISGRAPHSC(scp)) {
if (scp->mouse_xpos > scp->xpixel-1)
scp->mouse_xpos = scp->xpixel-1;
if (scp->mouse_ypos > scp->ypixel-1)
scp->mouse_ypos = scp->ypixel-1;
return;
} else {
if (scp->mouse_xpos > (scp->xsize + scp->xoff)*8 - 1)
scp->mouse_xpos = (scp->xsize + scp->xoff)*8 - 1;
if (scp->mouse_ypos > (scp->ysize + scp->yoff)*scp->font_size - 1)
scp->mouse_ypos = (scp->ysize + scp->yoff)*scp->font_size - 1;
}
if (scp->mouse_xpos != last_xpos || scp->mouse_ypos != last_ypos) {
scp->status |= MOUSE_MOVED;
scp->mouse_pos =
(scp->mouse_ypos/scp->font_size - scp->yoff)*scp->xsize
+ scp->mouse_xpos/8 - scp->xoff;
#ifndef SC_NO_CUTPASTE
if ((scp->status & MOUSE_VISIBLE) && (scp->status & MOUSE_CUTTING))
mouse_cut(scp);
#endif
}
}
#ifndef SC_NO_CUTPASTE
void
sc_draw_mouse_image(scr_stat *scp)
{
if (ISGRAPHSC(scp))
return;
++scp->sc->videoio_in_progress;
(*scp->rndr->draw_mouse)(scp, scp->mouse_xpos, scp->mouse_ypos, TRUE);
scp->mouse_oldpos = scp->mouse_pos;
--scp->sc->videoio_in_progress;
}
void
sc_remove_mouse_image(scr_stat *scp)
{
int size;
int i;
if (ISGRAPHSC(scp))
return;
++scp->sc->videoio_in_progress;
(*scp->rndr->draw_mouse)(scp,
(scp->mouse_oldpos%scp->xsize + scp->xoff)*8,
(scp->mouse_oldpos/scp->xsize + scp->yoff)
* scp->font_size,
FALSE);
size = scp->xsize*scp->ysize;
i = scp->mouse_oldpos;
mark_for_update(scp, i);
mark_for_update(scp, i);
#ifndef PC98
if (i + scp->xsize + 1 < size) {
mark_for_update(scp, i + scp->xsize + 1);
} else if (i + scp->xsize < size) {
mark_for_update(scp, i + scp->xsize);
} else if (i + 1 < size) {
mark_for_update(scp, i + 1);
}
#endif /* PC98 */
--scp->sc->videoio_in_progress;
}
int
sc_inside_cutmark(scr_stat *scp, int pos)
{
int start;
int end;
if (scp->mouse_cut_end < 0)
return FALSE;
if (scp->mouse_cut_start <= scp->mouse_cut_end) {
start = scp->mouse_cut_start;
end = scp->mouse_cut_end;
} else {
start = scp->mouse_cut_end;
end = scp->mouse_cut_start - 1;
}
return ((start <= pos) && (pos <= end));
}
void
sc_remove_cutmarking(scr_stat *scp)
{
int s;
s = spltty();
if (scp->mouse_cut_end >= 0) {
mark_for_update(scp, scp->mouse_cut_start);
mark_for_update(scp, scp->mouse_cut_end);
}
scp->mouse_cut_start = scp->xsize*scp->ysize;
scp->mouse_cut_end = -1;
splx(s);
scp->status &= ~MOUSE_CUTTING;
}
void
sc_remove_all_cutmarkings(sc_softc_t *sc)
{
int i;
/* delete cut markings in all vtys */
for (i = 0; i < sc->vtys; ++i) {
if (sc->console[i] == NULL)
continue;
sc_remove_cutmarking(sc->console[i]);
}
}
void
sc_remove_all_mouse(sc_softc_t *sc)
{
int i;
for (i = 0; i < sc->vtys; ++i) {
if (sc->console[i] == NULL)
continue;
if (sc->console[i]->status & MOUSE_VISIBLE) {
sc->console[i]->status &= ~MOUSE_VISIBLE;
mark_all(sc->console[i]);
}
}
}
#define isspace(c) (((c) & 0xff) == ' ')
/* skip spaces to right */
static int
skip_spc_right(scr_stat *scp, int p)
{
int c;
int i;
for (i = p % scp->xsize; i < scp->xsize; ++i) {
c = sc_vtb_getc(&scp->vtb, p);
if (!isspace(c))
break;
++p;
}
return i;
}
/* skip spaces to left */
static int
skip_spc_left(scr_stat *scp, int p)
{
int c;
int i;
for (i = p-- % scp->xsize - 1; i >= 0; --i) {
c = sc_vtb_getc(&scp->vtb, p);
if (!isspace(c))
break;
--p;
}
return i;
}
/* copy marked region to the cut buffer */
static void
mouse_cut(scr_stat *scp)
{
int start;
int end;
int from;
int to;
int blank;
int c;
int p;
int s;
int i;
start = scp->mouse_cut_start;
end = scp->mouse_cut_end;
if (scp->mouse_pos >= start) {
from = start;
to = end = scp->mouse_pos;
} else {
from = end = scp->mouse_pos;
to = start - 1;
}
for (p = from, i = blank = 0; p <= to; ++p) {
cut_buffer[i] = sc_vtb_getc(&scp->vtb, p);
/* remember the position of the last non-space char */
if (!isspace(cut_buffer[i++]))
blank = i; /* the first space after the last non-space */
/* trim trailing blank when crossing lines */
if ((p % scp->xsize) == (scp->xsize - 1)) {
cut_buffer[blank] = '\r';
i = blank + 1;
}
}
cut_buffer[i] = '\0';
/* scan towards the end of the last line */
--p;
for (i = p % scp->xsize; i < scp->xsize; ++i) {
c = sc_vtb_getc(&scp->vtb, p);
if (!isspace(c))
break;
++p;
}
/* if there is nothing but blank chars, trim them, but mark towards eol */
if (i >= scp->xsize) {
if (end >= start)
to = end = p - 1;
else
to = start = p;
cut_buffer[blank++] = '\r';
cut_buffer[blank] = '\0';
}
/* remove the current marking */
s = spltty();
if (scp->mouse_cut_start <= scp->mouse_cut_end) {
mark_for_update(scp, scp->mouse_cut_start);
mark_for_update(scp, scp->mouse_cut_end);
} else if (scp->mouse_cut_end >= 0) {
mark_for_update(scp, scp->mouse_cut_end);
mark_for_update(scp, scp->mouse_cut_start);
}
/* mark the new region */
scp->mouse_cut_start = start;
scp->mouse_cut_end = end;
mark_for_update(scp, from);
mark_for_update(scp, to);
splx(s);
}
/* a mouse button is pressed, start cut operation */
static void
mouse_cut_start(scr_stat *scp)
{
int i;
int j;
int s;
if (scp->status & MOUSE_VISIBLE) {
i = scp->mouse_cut_start;
j = scp->mouse_cut_end;
sc_remove_all_cutmarkings(scp->sc);
if (scp->mouse_pos == i && i == j) {
cut_buffer[0] = '\0';
} else if (skip_spc_right(scp, scp->mouse_pos) >= scp->xsize) {
/* if the pointer is on trailing blank chars, mark towards eol */
i = skip_spc_left(scp, scp->mouse_pos) + 1;
s = spltty();
scp->mouse_cut_start =
(scp->mouse_pos / scp->xsize) * scp->xsize + i;
scp->mouse_cut_end =
(scp->mouse_pos / scp->xsize + 1) * scp->xsize - 1;
splx(s);
cut_buffer[0] = '\r';
cut_buffer[1] = '\0';
scp->status |= MOUSE_CUTTING;
} else {
s = spltty();
scp->mouse_cut_start = scp->mouse_pos;
scp->mouse_cut_end = scp->mouse_cut_start;
splx(s);
cut_buffer[0] = sc_vtb_getc(&scp->vtb, scp->mouse_cut_start);
cut_buffer[1] = '\0';
scp->status |= MOUSE_CUTTING;
}
mark_all(scp); /* this is probably overkill XXX */
}
}
/* end of cut operation */
static void
mouse_cut_end(scr_stat *scp)
{
if (scp->status & MOUSE_VISIBLE)
scp->status &= ~MOUSE_CUTTING;
}
/* copy a word under the mouse pointer */
static void
mouse_cut_word(scr_stat *scp)
{
int start;
int end;
int sol;
int eol;
int c;
int s;
int i;
int j;
/*
* Because we don't have locale information in the kernel,
* we only distinguish space char and non-space chars. Punctuation
* chars, symbols and other regular chars are all treated alike.
*/
if (scp->status & MOUSE_VISIBLE) {
/* remove the current cut mark */
s = spltty();
if (scp->mouse_cut_start <= scp->mouse_cut_end) {
mark_for_update(scp, scp->mouse_cut_start);
mark_for_update(scp, scp->mouse_cut_end);
} else if (scp->mouse_cut_end >= 0) {
mark_for_update(scp, scp->mouse_cut_end);
mark_for_update(scp, scp->mouse_cut_start);
}
scp->mouse_cut_start = scp->xsize*scp->ysize;
scp->mouse_cut_end = -1;
splx(s);
sol = (scp->mouse_pos / scp->xsize) * scp->xsize;
eol = sol + scp->xsize;
c = sc_vtb_getc(&scp->vtb, scp->mouse_pos);
if (isspace(c)) {
/* blank space */
for (j = scp->mouse_pos; j >= sol; --j) {
c = sc_vtb_getc(&scp->vtb, j);
if (!isspace(c))
break;
}
start = ++j;
for (j = scp->mouse_pos; j < eol; ++j) {
c = sc_vtb_getc(&scp->vtb, j);
if (!isspace(c))
break;
}
end = j - 1;
} else {
/* non-space word */
for (j = scp->mouse_pos; j >= sol; --j) {
c = sc_vtb_getc(&scp->vtb, j);
if (isspace(c))
break;
}
start = ++j;
for (j = scp->mouse_pos; j < eol; ++j) {
c = sc_vtb_getc(&scp->vtb, j);
if (isspace(c))
break;
}
end = j - 1;
}
/* copy the found word */
for (i = 0, j = start; j <= end; ++j)
cut_buffer[i++] = sc_vtb_getc(&scp->vtb, j);
cut_buffer[i] = '\0';
scp->status |= MOUSE_CUTTING;
/* mark the region */
s = spltty();
scp->mouse_cut_start = start;
scp->mouse_cut_end = end;
mark_for_update(scp, start);
mark_for_update(scp, end);
splx(s);
}
}
/* copy a line under the mouse pointer */
static void
mouse_cut_line(scr_stat *scp)
{
int s;
int i;
int j;
if (scp->status & MOUSE_VISIBLE) {
/* remove the current cut mark */
s = spltty();
if (scp->mouse_cut_start <= scp->mouse_cut_end) {
mark_for_update(scp, scp->mouse_cut_start);
mark_for_update(scp, scp->mouse_cut_end);
} else if (scp->mouse_cut_end >= 0) {
mark_for_update(scp, scp->mouse_cut_end);
mark_for_update(scp, scp->mouse_cut_start);
}
/* mark the entire line */
scp->mouse_cut_start =
(scp->mouse_pos / scp->xsize) * scp->xsize;
scp->mouse_cut_end = scp->mouse_cut_start + scp->xsize - 1;
mark_for_update(scp, scp->mouse_cut_start);
mark_for_update(scp, scp->mouse_cut_end);
splx(s);
/* copy the line into the cut buffer */
for (i = 0, j = scp->mouse_cut_start; j <= scp->mouse_cut_end; ++j)
cut_buffer[i++] = sc_vtb_getc(&scp->vtb, j);
cut_buffer[i++] = '\r';
cut_buffer[i] = '\0';
scp->status |= MOUSE_CUTTING;
}
}
/* extend the marked region to the mouse pointer position */
static void
mouse_cut_extend(scr_stat *scp)
{
int start;
int end;
int s;
if ((scp->status & MOUSE_VISIBLE) && !(scp->status & MOUSE_CUTTING)
&& (scp->mouse_cut_end >= 0)) {
if (scp->mouse_cut_start <= scp->mouse_cut_end) {
start = scp->mouse_cut_start;
end = scp->mouse_cut_end;
} else {
start = scp->mouse_cut_end;
end = scp->mouse_cut_start - 1;
}
s = spltty();
if (scp->mouse_pos > end) {
scp->mouse_cut_start = start;
scp->mouse_cut_end = end;
} else if (scp->mouse_pos < start) {
scp->mouse_cut_start = end + 1;
scp->mouse_cut_end = start;
} else {
if (scp->mouse_pos - start > end + 1 - scp->mouse_pos) {
scp->mouse_cut_start = start;
scp->mouse_cut_end = end;
} else {
scp->mouse_cut_start = end + 1;
scp->mouse_cut_end = start;
}
}
splx(s);
mouse_cut(scp);
scp->status |= MOUSE_CUTTING;
}
}
/* paste cut buffer contents into the current vty */
static void
mouse_paste(scr_stat *scp)
{
if (scp->status & MOUSE_VISIBLE)
sc_paste(scp, cut_buffer, strlen(cut_buffer));
}
#endif /* SC_NO_CUTPASTE */
int
sc_mouse_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag,
struct proc *p)
{
scr_stat *scp;
int s;
int i;
/* scp == NULL, if tp == sc_get_mouse_tty() (/dev/sysmouse) */
scp = sc_get_scr_stat(tp->t_dev);
switch (cmd) {
case CONS_MOUSECTL: /* control mouse arrow */
case OLD_CONS_MOUSECTL:
{
/* MOUSE_BUTTON?DOWN -> MOUSE_MSC_BUTTON?UP */
static int butmap[8] = {
MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP,
MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP,
MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON3UP,
MOUSE_MSC_BUTTON3UP,
MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP,
MOUSE_MSC_BUTTON2UP,
MOUSE_MSC_BUTTON1UP,
0,
};
mouse_info_t *mouse = (mouse_info_t*)data;
mouse_info_t buf;
scr_stat *cur_scp;
struct tty *mtty;
if (scp == NULL)
return ENOTTY;
if (cmd == OLD_CONS_MOUSECTL) {
static u_char swapb[] = { 0, 4, 2, 6, 1, 5, 3, 7 };
old_mouse_info_t *old_mouse = (old_mouse_info_t *)data;
mouse = &buf;
mouse->operation = old_mouse->operation;
switch (mouse->operation) {
case MOUSE_MODE:
mouse->u.mode = old_mouse->u.mode;
break;
case MOUSE_SHOW:
case MOUSE_HIDE:
break;
case MOUSE_MOVEABS:
case MOUSE_MOVEREL:
case MOUSE_ACTION:
mouse->u.data.x = old_mouse->u.data.x;
mouse->u.data.y = old_mouse->u.data.y;
mouse->u.data.z = 0;
mouse->u.data.buttons = swapb[old_mouse->u.data.buttons & 0x7];
break;
case MOUSE_GETINFO:
old_mouse->u.data.x = scp->mouse_xpos;
old_mouse->u.data.y = scp->mouse_ypos;
old_mouse->u.data.buttons = swapb[scp->mouse_buttons & 0x7];
break;
default:
return EINVAL;
}
}
cur_scp = scp->sc->cur_scp;
switch (mouse->operation) {
case MOUSE_MODE:
if (ISSIGVALID(mouse->u.mode.signal)) {
scp->mouse_signal = mouse->u.mode.signal;
scp->mouse_proc = p;
scp->mouse_pid = p->p_pid;
}
else {
scp->mouse_signal = 0;
scp->mouse_proc = NULL;
scp->mouse_pid = 0;
}
return 0;
case MOUSE_SHOW:
if (!ISMOUSEAVAIL(scp->sc->adp->va_flags))
return EINVAL;
s = spltty();
if (!(scp->sc->flags & SC_MOUSE_ENABLED)) {
scp->sc->flags |= SC_MOUSE_ENABLED;
if (!ISGRAPHSC(cur_scp)) {
cur_scp->status |= MOUSE_VISIBLE;
mark_all(cur_scp);
}
splx(s);
return 0;
} else {
splx(s);
return EINVAL;
}
break;
#if 0
if (!(scp->status & MOUSE_ENABLED)) {
scp->mouse_oldpos = scp->mouse_pos;
scp->status |= MOUSE_ENABLED;
if (!ISGRAPHSC(scp))
scp->status |= MOUSE_VISIBLE;
splx(s);
mark_all(scp);
return 0;
} else {
splx(s);
return EINVAL;
}
break;
#endif
case MOUSE_HIDE:
s = spltty();
if (scp->sc->flags & SC_MOUSE_ENABLED) {
scp->sc->flags &= ~SC_MOUSE_ENABLED;
sc_remove_all_mouse(scp->sc);
splx(s);
return 0;
} else {
splx(s);
return EINVAL;
}
break;
#if 0
if (scp->status & MOUSE_ENABLED) {
scp->status &= ~(MOUSE_ENABLED | MOUSE_VISIBLE);
mark_all(scp);
splx(s);
return 0;
} else {
splx(s);
return EINVAL;
}
break;
#endif
case MOUSE_MOVEABS:
s = spltty();
scp->mouse_xpos = mouse->u.data.x;
scp->mouse_ypos = mouse->u.data.y;
set_mouse_pos(scp);
splx(s);
break;
case MOUSE_MOVEREL:
s = spltty();
scp->mouse_xpos += mouse->u.data.x;
scp->mouse_ypos += mouse->u.data.y;
set_mouse_pos(scp);
splx(s);
break;
case MOUSE_GETINFO:
mouse->u.data.x = scp->mouse_xpos;
mouse->u.data.y = scp->mouse_ypos;
mouse->u.data.z = 0;
mouse->u.data.buttons = scp->mouse_buttons;
return 0;
case MOUSE_ACTION:
case MOUSE_MOTION_EVENT:
/* send out mouse event on /dev/sysmouse */
#if 0
/* this should maybe only be settable from /dev/consolectl SOS */
if (SC_VTY(tp->t_dev) != SC_CONSOLECTL)
return ENOTTY;
#endif
mouse_status.dx += mouse->u.data.x;
mouse_status.dy += mouse->u.data.y;
mouse_status.dz += mouse->u.data.z;
if (mouse->operation == MOUSE_ACTION)
mouse_status.button = mouse->u.data.buttons;
mouse_status.flags |=
((mouse->u.data.x || mouse->u.data.y || mouse->u.data.z) ?
MOUSE_POSCHANGED : 0)
| (mouse_status.obutton ^ mouse_status.button);
if (mouse_status.flags == 0)
return 0;
mtty = sc_get_mouse_tty();
if (mtty->t_state & TS_ISOPEN) {
u_char buf[MOUSE_SYS_PACKETSIZE];
/* the first five bytes are compatible with MouseSystems' */
buf[0] = MOUSE_MSC_SYNC
| butmap[mouse_status.button & MOUSE_STDBUTTONS];
i = imax(imin(mouse->u.data.x, 255), -256);
buf[1] = i >> 1;
buf[3] = i - buf[1];
i = -imax(imin(mouse->u.data.y, 255), -256);
buf[2] = i >> 1;
buf[4] = i - buf[2];
for (i = 0; i < MOUSE_MSC_PACKETSIZE; i++)
(*linesw[mtty->t_line].l_rint)(buf[i], mtty);
if (mouse_level >= 1) { /* extended part */
i = imax(imin(mouse->u.data.z, 127), -128);
buf[5] = (i >> 1) & 0x7f;
buf[6] = (i - (i >> 1)) & 0x7f;
/* buttons 4-10 */
buf[7] = (~mouse_status.button >> 3) & 0x7f;
for (i = MOUSE_MSC_PACKETSIZE;
i < MOUSE_SYS_PACKETSIZE; i++)
(*linesw[mtty->t_line].l_rint)(buf[i], mtty);
}
}
if (cur_scp->mouse_signal) {
cur_scp->mouse_buttons = mouse->u.data.buttons;
/* has controlling process died? */
if (cur_scp->mouse_proc &&
(cur_scp->mouse_proc != pfind(cur_scp->mouse_pid))){
cur_scp->mouse_signal = 0;
cur_scp->mouse_proc = NULL;
cur_scp->mouse_pid = 0;
}
else
psignal(cur_scp->mouse_proc, cur_scp->mouse_signal);
break;
}
/*
* If any buttons are down or the mouse has moved a lot,
* stop the screen saver.
*/
if (((mouse->operation == MOUSE_ACTION) && mouse->u.data.buttons)
|| (mouse->u.data.x*mouse->u.data.x
+ mouse->u.data.y*mouse->u.data.y
>= SC_WAKEUP_DELTA*SC_WAKEUP_DELTA)) {
sc_touch_scrn_saver();
}
if (ISGRAPHSC(cur_scp) || (cut_buffer == NULL))
break;
#ifndef SC_NO_CUTPASTE
if (cur_scp->sc->flags & SC_MOUSE_ENABLED)
cur_scp->status |= MOUSE_VISIBLE;
if (mouse->operation == MOUSE_ACTION) {
/* process button presses */
if (cur_scp->mouse_buttons ^ mouse->u.data.buttons) {
cur_scp->mouse_buttons = mouse->u.data.buttons;
if (cur_scp->mouse_buttons & MOUSE_BUTTON1DOWN)
mouse_cut_start(cur_scp);
else
mouse_cut_end(cur_scp);
if (cur_scp->mouse_buttons & MOUSE_BUTTON2DOWN ||
cur_scp->mouse_buttons & MOUSE_BUTTON3DOWN)
mouse_paste(cur_scp);
}
}
#else /* SC_NO_CUTPASTE */
if (mouse->operation == MOUSE_ACTION)
cur_scp->mouse_buttons = mouse->u.data.buttons;
#endif /* SC_NO_CUTPASTE */
if (mouse->u.data.x != 0 || mouse->u.data.y != 0) {
s = spltty();
cur_scp->mouse_xpos += mouse->u.data.x;
cur_scp->mouse_ypos += mouse->u.data.y;
set_mouse_pos(cur_scp);
splx(s);
}
break;
case MOUSE_BUTTON_EVENT:
if ((mouse->u.event.id & MOUSE_BUTTONS) == 0)
return EINVAL;
if (mouse->u.event.value < 0)
return EINVAL;
#if 0
/* this should maybe only be settable from /dev/consolectl SOS */
if (SC_VTY(tp->t_dev) != SC_CONSOLECTL)
return ENOTTY;
#endif
if (mouse->u.event.value > 0) {
cur_scp->mouse_buttons |= mouse->u.event.id;
mouse_status.button |= mouse->u.event.id;
} else {
cur_scp->mouse_buttons &= ~mouse->u.event.id;
mouse_status.button &= ~mouse->u.event.id;
}
mouse_status.flags |= mouse_status.obutton ^ mouse_status.button;
if (mouse_status.flags == 0)
return 0;
mtty = sc_get_mouse_tty();
if (mtty->t_state & TS_ISOPEN) {
u_char buf[MOUSE_SYS_PACKETSIZE];
buf[0] = MOUSE_MSC_SYNC
| butmap[mouse_status.button & MOUSE_STDBUTTONS];
buf[7] = (~mouse_status.button >> 3) & 0x7f;
buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
for (i = 0;
i < ((mouse_level >= 1) ? MOUSE_SYS_PACKETSIZE
: MOUSE_MSC_PACKETSIZE); i++)
(*linesw[mtty->t_line].l_rint)(buf[i], mtty);
}
if (cur_scp->mouse_signal) {
if (cur_scp->mouse_proc &&
(cur_scp->mouse_proc != pfind(cur_scp->mouse_pid))){
cur_scp->mouse_signal = 0;
cur_scp->mouse_proc = NULL;
cur_scp->mouse_pid = 0;
}
else
psignal(cur_scp->mouse_proc, cur_scp->mouse_signal);
break;
}
/* if a button is held down, stop the screen saver */
if (mouse->u.event.value > 0)
sc_touch_scrn_saver();
if (ISGRAPHSC(cur_scp) || (cut_buffer == NULL))
break;
#ifndef SC_NO_CUTPASTE
if (cur_scp->sc->flags & SC_MOUSE_ENABLED)
cur_scp->status |= MOUSE_VISIBLE;
switch (mouse->u.event.id) {
case MOUSE_BUTTON1DOWN:
switch (mouse->u.event.value % 4) {
case 0: /* up */
mouse_cut_end(cur_scp);
break;
case 1: /* single click: start cut operation */
mouse_cut_start(cur_scp);
break;
case 2: /* double click: cut a word */
mouse_cut_word(cur_scp);
mouse_cut_end(cur_scp);
break;
case 3: /* triple click: cut a line */
mouse_cut_line(cur_scp);
mouse_cut_end(cur_scp);
break;
}
break;
case MOUSE_BUTTON2DOWN:
switch (mouse->u.event.value) {
case 0: /* up */
break;
default:
mouse_paste(cur_scp);
break;
}
break;
case MOUSE_BUTTON3DOWN:
switch (mouse->u.event.value) {
case 0: /* up */
if (!(cur_scp->mouse_buttons & MOUSE_BUTTON1DOWN))
mouse_cut_end(cur_scp);
break;
default:
mouse_cut_extend(cur_scp);
break;
}
break;
}
#endif /* SC_NO_CUTPASTE */
break;
default:
return EINVAL;
}
return 0;
}
/* MOUSE_XXX: /dev/sysmouse ioctls */
case MOUSE_GETHWINFO: /* get device information */
{
mousehw_t *hw = (mousehw_t *)data;
if (tp != sc_get_mouse_tty())
return ENOTTY;
hw->buttons = 10; /* XXX unknown */
hw->iftype = MOUSE_IF_SYSMOUSE;
hw->type = MOUSE_MOUSE;
hw->model = MOUSE_MODEL_GENERIC;
hw->hwid = 0;
return 0;
}
case MOUSE_GETMODE: /* get protocol/mode */
{
mousemode_t *mode = (mousemode_t *)data;
if (tp != sc_get_mouse_tty())
return ENOTTY;
mode->level = mouse_level;
switch (mode->level) {
case 0:
/* at this level, sysmouse emulates MouseSystems protocol */
mode->protocol = MOUSE_PROTO_MSC;
mode->rate = -1; /* unknown */
mode->resolution = -1; /* unknown */
mode->accelfactor = 0; /* disabled */
mode->packetsize = MOUSE_MSC_PACKETSIZE;
mode->syncmask[0] = MOUSE_MSC_SYNCMASK;
mode->syncmask[1] = MOUSE_MSC_SYNC;
break;
case 1:
/* at this level, sysmouse uses its own protocol */
mode->protocol = MOUSE_PROTO_SYSMOUSE;
mode->rate = -1;
mode->resolution = -1;
mode->accelfactor = 0;
mode->packetsize = MOUSE_SYS_PACKETSIZE;
mode->syncmask[0] = MOUSE_SYS_SYNCMASK;
mode->syncmask[1] = MOUSE_SYS_SYNC;
break;
}
return 0;
}
case MOUSE_SETMODE: /* set protocol/mode */
{
mousemode_t *mode = (mousemode_t *)data;
if (tp != sc_get_mouse_tty())
return ENOTTY;
if ((mode->level < 0) || (mode->level > 1))
return EINVAL;
sc_mouse_set_level(mode->level);
return 0;
}
case MOUSE_GETLEVEL: /* get operation level */
if (tp != sc_get_mouse_tty())
return ENOTTY;
*(int *)data = mouse_level;
return 0;
case MOUSE_SETLEVEL: /* set operation level */
if (tp != sc_get_mouse_tty())
return ENOTTY;
if ((*(int *)data < 0) || (*(int *)data > 1))
return EINVAL;
sc_mouse_set_level(*(int *)data);
return 0;
case MOUSE_GETSTATUS: /* get accumulated mouse events */
if (tp != sc_get_mouse_tty())
return ENOTTY;
s = spltty();
*(mousestatus_t *)data = mouse_status;
mouse_status.flags = 0;
mouse_status.obutton = mouse_status.button;
mouse_status.dx = 0;
mouse_status.dy = 0;
mouse_status.dz = 0;
splx(s);
return 0;
#if notyet
case MOUSE_GETVARS: /* get internal mouse variables */
case MOUSE_SETVARS: /* set internal mouse variables */
if (tp != sc_get_mouse_tty())
return ENOTTY;
return ENODEV;
#endif
case MOUSE_READSTATE: /* read status from the device */
case MOUSE_READDATA: /* read data from the device */
if (tp != sc_get_mouse_tty())
return ENOTTY;
return ENODEV;
}
return ENOIOCTL;
}
#endif /* SC_NO_SYSMOUSE */
#endif /* NSC */