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