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