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: src/sys/dev/syscons/scmouse.c,v 1.12.2.3 2001/07/28 12:51:47 yokota Exp $ 27 */ 28 29 #include "opt_syscons.h" 30 31 #include <sys/param.h> 32 #include <sys/systm.h> 33 #include <sys/kernel.h> 34 #include <sys/conf.h> 35 #include <sys/signalvar.h> 36 #include <sys/proc.h> 37 #include <sys/tty.h> 38 #include <sys/thread2.h> 39 #include <sys/mplock2.h> 40 41 #include <machine/console.h> 42 #include <sys/mouse.h> 43 44 #include "syscons.h" 45 46 #ifdef SC_TWOBUTTON_MOUSE 47 #define SC_MOUSE_PASTEBUTTON MOUSE_BUTTON3DOWN /* right button */ 48 #define SC_MOUSE_EXTENDBUTTON MOUSE_BUTTON2DOWN /* not really used */ 49 #else 50 #define SC_MOUSE_PASTEBUTTON MOUSE_BUTTON2DOWN /* middle button */ 51 #define SC_MOUSE_EXTENDBUTTON MOUSE_BUTTON3DOWN /* right button */ 52 #endif /* SC_TWOBUTTON_MOUSE */ 53 54 #define SC_WAKEUP_DELTA 20 55 56 #ifndef SC_NO_SYSMOUSE 57 58 static int cut_buffer_size; 59 static u_char *cut_buffer; 60 61 /* local functions */ 62 static void sc_mouse_init(void *); 63 static void sc_mouse_uninit(void *); 64 65 static void set_mouse_pos(scr_stat *scp); 66 #ifndef SC_NO_CUTPASTE 67 static int skip_spc_right(scr_stat *scp, int p); 68 static int skip_spc_left(scr_stat *scp, int p); 69 static void mouse_cut(scr_stat *scp); 70 static void mouse_cut_start(scr_stat *scp); 71 static void mouse_cut_end(scr_stat *scp); 72 static void mouse_cut_word(scr_stat *scp); 73 static void mouse_cut_line(scr_stat *scp); 74 static void mouse_cut_extend(scr_stat *scp); 75 static void mouse_paste(scr_stat *scp); 76 #endif /* SC_NO_CUTPASTE */ 77 78 #ifndef SC_NO_CUTPASTE 79 /* allocate a cut buffer */ 80 void 81 sc_alloc_cut_buffer(scr_stat *scp, int wait) 82 { 83 u_char *p; 84 85 if ((cut_buffer == NULL) 86 || (cut_buffer_size < scp->xsize * scp->ysize + 1)) { 87 p = cut_buffer; 88 cut_buffer = NULL; 89 if (p != NULL) 90 kfree(p, M_SYSCONS); 91 cut_buffer_size = scp->xsize * scp->ysize + 1; 92 p = kmalloc(cut_buffer_size, M_SYSCONS, (wait) ? M_WAITOK : M_NOWAIT); 93 if (p != NULL) 94 p[0] = '\0'; 95 cut_buffer = p; 96 } 97 } 98 #endif /* SC_NO_CUTPASTE */ 99 100 /* move mouse */ 101 void 102 sc_mouse_move(scr_stat *scp, int x, int y) 103 { 104 crit_enter(); 105 scp->mouse_xpos = scp->mouse_oldxpos = x; 106 scp->mouse_ypos = scp->mouse_oldypos = y; 107 if (scp->font_height <= 0) 108 scp->mouse_pos = scp->mouse_oldpos = 0; 109 else 110 scp->mouse_pos = scp->mouse_oldpos = 111 (y / scp->font_height - scp->yoff) * scp->xsize + 112 x / scp->font_width - scp->xoff; 113 scp->status |= MOUSE_MOVED; 114 crit_exit(); 115 } 116 117 /* adjust mouse position */ 118 static void 119 set_mouse_pos(scr_stat *scp) 120 { 121 if (scp->mouse_xpos < scp->xoff * scp->font_width) 122 scp->mouse_xpos = scp->xoff * scp->font_width; 123 if (scp->mouse_ypos < scp->yoff * scp->font_height) 124 scp->mouse_ypos = scp->yoff * scp->font_height; 125 if (ISGRAPHSC(scp)) { 126 if (scp->mouse_xpos > scp->xpixel - 1) 127 scp->mouse_xpos = scp->xpixel - 1; 128 if (scp->mouse_ypos > scp->ypixel - 1) 129 scp->mouse_ypos = scp->ypixel - 1; 130 return; 131 } else { 132 if (scp->mouse_xpos > (scp->xsize + scp->xoff) * scp->font_width - 1) 133 scp->mouse_xpos = (scp->xsize + scp->xoff) * scp->font_width - 1; 134 if (scp->mouse_ypos > (scp->ysize + scp->yoff) * scp->font_height - 1) 135 scp->mouse_ypos = (scp->ysize + scp->yoff) * scp->font_height - 1; 136 } 137 138 if (scp->mouse_xpos != scp->mouse_oldxpos || 139 scp->mouse_ypos != scp->mouse_oldypos) { 140 scp->status |= MOUSE_MOVED; 141 scp->mouse_pos = 142 (scp->mouse_ypos / scp->font_height - scp->yoff) * scp->xsize + 143 scp->mouse_xpos / scp->font_width - scp->xoff; 144 #ifndef SC_NO_CUTPASTE 145 if ((scp->status & MOUSE_VISIBLE) && (scp->status & MOUSE_CUTTING)) 146 mouse_cut(scp); 147 #endif 148 } 149 } 150 151 #ifndef SC_NO_CUTPASTE 152 153 void 154 sc_draw_mouse_image(scr_stat *scp) 155 { 156 if (ISGRAPHSC(scp)) 157 return; 158 159 atomic_add_int(&scp->sc->videoio_in_progress, 1); 160 (*scp->rndr->draw_mouse)(scp, scp->mouse_xpos, scp->mouse_ypos, TRUE); 161 scp->mouse_oldpos = scp->mouse_pos; 162 scp->mouse_oldxpos = scp->mouse_xpos; 163 scp->mouse_oldypos = scp->mouse_ypos; 164 scp->status |= MOUSE_VISIBLE; 165 atomic_add_int(&scp->sc->videoio_in_progress, -1); 166 } 167 168 void 169 sc_remove_mouse_image(scr_stat *scp) 170 { 171 int size; 172 int i; 173 174 if (ISGRAPHSC(scp)) 175 return; 176 177 atomic_add_int(&scp->sc->videoio_in_progress, 1); 178 (*scp->rndr->draw_mouse)(scp, 179 (scp->mouse_oldpos%scp->xsize + scp->xoff) * 180 scp->font_width, 181 (scp->mouse_oldpos/scp->xsize + scp->yoff) * 182 scp->font_height, 183 FALSE); 184 size = scp->xsize * scp->ysize; 185 i = scp->mouse_oldpos; 186 mark_for_update(scp, i); 187 mark_for_update(scp, i); 188 if (i + scp->xsize + 1 < size) { 189 mark_for_update(scp, i + scp->xsize + 1); 190 } else if (i + scp->xsize < size) { 191 mark_for_update(scp, i + scp->xsize); 192 } else if (i + 1 < size) { 193 mark_for_update(scp, i + 1); 194 } 195 scp->status &= ~MOUSE_VISIBLE; 196 atomic_add_int(&scp->sc->videoio_in_progress, -1); 197 } 198 199 int 200 sc_inside_cutmark(scr_stat *scp, int pos) 201 { 202 int start; 203 int end; 204 205 if (scp->mouse_cut_end < 0) 206 return FALSE; 207 if (scp->mouse_cut_start <= scp->mouse_cut_end) { 208 start = scp->mouse_cut_start; 209 end = scp->mouse_cut_end; 210 } else { 211 start = scp->mouse_cut_end; 212 end = scp->mouse_cut_start - 1; 213 } 214 return ((start <= pos) && (pos <= end)); 215 } 216 217 void 218 sc_remove_cutmarking(scr_stat *scp) 219 { 220 crit_enter(); 221 if (scp->mouse_cut_end >= 0) { 222 mark_for_update(scp, scp->mouse_cut_start); 223 mark_for_update(scp, scp->mouse_cut_end); 224 } 225 scp->mouse_cut_start = scp->xsize*scp->ysize; 226 scp->mouse_cut_end = -1; 227 crit_exit(); 228 scp->status &= ~MOUSE_CUTTING; 229 } 230 231 void 232 sc_remove_all_cutmarkings(sc_softc_t *sc) 233 { 234 scr_stat *scp; 235 int i; 236 237 /* delete cut markings in all vtys */ 238 for (i = 0; i < sc->vtys; ++i) { 239 scp = SC_STAT(sc->dev[i]); 240 if (scp == NULL) 241 continue; 242 sc_remove_cutmarking(scp); 243 } 244 } 245 246 void 247 sc_remove_all_mouse(sc_softc_t *sc) 248 { 249 scr_stat *scp; 250 int i; 251 252 for (i = 0; i < sc->vtys; ++i) { 253 scp = SC_STAT(sc->dev[i]); 254 if (scp == NULL) 255 continue; 256 if (scp->status & MOUSE_VISIBLE) { 257 scp->status &= ~MOUSE_VISIBLE; 258 mark_all(scp); 259 } 260 } 261 } 262 263 #define IS_SPACE_CHAR(c) (((c) & 0xff) == ' ') 264 265 /* skip spaces to right */ 266 static int 267 skip_spc_right(scr_stat *scp, int p) 268 { 269 int c; 270 int i; 271 272 for (i = p % scp->xsize; i < scp->xsize; ++i) { 273 c = sc_vtb_getc(&scp->vtb, p); 274 if (!IS_SPACE_CHAR(c)) 275 break; 276 ++p; 277 } 278 return i; 279 } 280 281 /* skip spaces to left */ 282 static int 283 skip_spc_left(scr_stat *scp, int p) 284 { 285 int c; 286 int i; 287 288 for (i = p-- % scp->xsize - 1; i >= 0; --i) { 289 c = sc_vtb_getc(&scp->vtb, p); 290 if (!IS_SPACE_CHAR(c)) 291 break; 292 --p; 293 } 294 return i; 295 } 296 297 /* copy marked region to the cut buffer */ 298 static void 299 mouse_cut(scr_stat *scp) 300 { 301 int start; 302 int end; 303 int from; 304 int to; 305 int blank; 306 int c; 307 int p; 308 int i; 309 310 start = scp->mouse_cut_start; 311 if (scp->mouse_pos >= start) { 312 from = start; 313 to = end = scp->mouse_pos; 314 } else { 315 from = end = scp->mouse_pos; 316 to = start - 1; 317 } 318 for (p = from, i = blank = 0; p <= to; ++p) { 319 cut_buffer[i] = sc_vtb_getc(&scp->vtb, p); 320 /* remember the position of the last non-space char */ 321 if (!IS_SPACE_CHAR(cut_buffer[i++])) 322 blank = i; /* the first space after the last non-space */ 323 /* trim trailing blank when crossing lines */ 324 if ((p % scp->xsize) == (scp->xsize - 1)) { 325 cut_buffer[blank] = '\r'; 326 i = blank + 1; 327 } 328 } 329 cut_buffer[i] = '\0'; 330 331 /* scan towards the end of the last line */ 332 --p; 333 for (i = p % scp->xsize; i < scp->xsize; ++i) { 334 c = sc_vtb_getc(&scp->vtb, p); 335 if (!IS_SPACE_CHAR(c)) 336 break; 337 ++p; 338 } 339 /* if there is nothing but blank chars, trim them, but mark towards eol */ 340 if (i >= scp->xsize) { 341 if (end >= start) 342 to = end = p - 1; 343 else 344 to = start = p; 345 cut_buffer[blank++] = '\r'; 346 cut_buffer[blank] = '\0'; 347 } 348 349 /* remove the current marking */ 350 crit_enter(); 351 if (scp->mouse_cut_start <= scp->mouse_cut_end) { 352 mark_for_update(scp, scp->mouse_cut_start); 353 mark_for_update(scp, scp->mouse_cut_end); 354 } else if (scp->mouse_cut_end >= 0) { 355 mark_for_update(scp, scp->mouse_cut_end); 356 mark_for_update(scp, scp->mouse_cut_start); 357 } 358 359 /* mark the new region */ 360 scp->mouse_cut_start = start; 361 scp->mouse_cut_end = end; 362 mark_for_update(scp, from); 363 mark_for_update(scp, to); 364 crit_exit(); 365 } 366 367 /* a mouse button is pressed, start cut operation */ 368 static void 369 mouse_cut_start(scr_stat *scp) 370 { 371 int i; 372 int j; 373 374 if (scp->status & MOUSE_VISIBLE) { 375 i = scp->mouse_cut_start; 376 j = scp->mouse_cut_end; 377 sc_remove_all_cutmarkings(scp->sc); 378 if (scp->mouse_pos == i && i == j) { 379 cut_buffer[0] = '\0'; 380 } else if (skip_spc_right(scp, scp->mouse_pos) >= scp->xsize) { 381 /* if the pointer is on trailing blank chars, mark towards eol */ 382 i = skip_spc_left(scp, scp->mouse_pos) + 1; 383 crit_enter(); 384 scp->mouse_cut_start = 385 (scp->mouse_pos / scp->xsize) * scp->xsize + i; 386 scp->mouse_cut_end = 387 (scp->mouse_pos / scp->xsize + 1) * scp->xsize - 1; 388 crit_exit(); 389 cut_buffer[0] = '\r'; 390 cut_buffer[1] = '\0'; 391 scp->status |= MOUSE_CUTTING; 392 } else { 393 crit_enter(); 394 scp->mouse_cut_start = scp->mouse_pos; 395 scp->mouse_cut_end = scp->mouse_cut_start; 396 crit_exit(); 397 cut_buffer[0] = sc_vtb_getc(&scp->vtb, scp->mouse_cut_start); 398 cut_buffer[1] = '\0'; 399 scp->status |= MOUSE_CUTTING; 400 } 401 mark_all(scp); /* this is probably overkill XXX */ 402 } 403 } 404 405 /* end of cut operation */ 406 static void 407 mouse_cut_end(scr_stat *scp) 408 { 409 if (scp->status & MOUSE_VISIBLE) 410 scp->status &= ~MOUSE_CUTTING; 411 } 412 413 /* copy a word under the mouse pointer */ 414 static void 415 mouse_cut_word(scr_stat *scp) 416 { 417 int start; 418 int end; 419 int sol; 420 int eol; 421 int c; 422 int i; 423 int j; 424 425 /* 426 * Because we don't have locale information in the kernel, 427 * we only distinguish space char and non-space chars. Punctuation 428 * chars, symbols and other regular chars are all treated alike. 429 */ 430 if (scp->status & MOUSE_VISIBLE) { 431 /* remove the current cut mark */ 432 crit_enter(); 433 if (scp->mouse_cut_start <= scp->mouse_cut_end) { 434 mark_for_update(scp, scp->mouse_cut_start); 435 mark_for_update(scp, scp->mouse_cut_end); 436 } else if (scp->mouse_cut_end >= 0) { 437 mark_for_update(scp, scp->mouse_cut_end); 438 mark_for_update(scp, scp->mouse_cut_start); 439 } 440 scp->mouse_cut_start = scp->xsize*scp->ysize; 441 scp->mouse_cut_end = -1; 442 crit_exit(); 443 444 sol = (scp->mouse_pos / scp->xsize) * scp->xsize; 445 eol = sol + scp->xsize; 446 c = sc_vtb_getc(&scp->vtb, scp->mouse_pos); 447 if (IS_SPACE_CHAR(c)) { 448 /* blank space */ 449 for (j = scp->mouse_pos; j >= sol; --j) { 450 c = sc_vtb_getc(&scp->vtb, j); 451 if (!IS_SPACE_CHAR(c)) 452 break; 453 } 454 start = ++j; 455 for (j = scp->mouse_pos; j < eol; ++j) { 456 c = sc_vtb_getc(&scp->vtb, j); 457 if (!IS_SPACE_CHAR(c)) 458 break; 459 } 460 end = j - 1; 461 } else { 462 /* non-space word */ 463 for (j = scp->mouse_pos; j >= sol; --j) { 464 c = sc_vtb_getc(&scp->vtb, j); 465 if (IS_SPACE_CHAR(c)) 466 break; 467 } 468 start = ++j; 469 for (j = scp->mouse_pos; j < eol; ++j) { 470 c = sc_vtb_getc(&scp->vtb, j); 471 if (IS_SPACE_CHAR(c)) 472 break; 473 } 474 end = j - 1; 475 } 476 477 /* copy the found word */ 478 for (i = 0, j = start; j <= end; ++j) 479 cut_buffer[i++] = sc_vtb_getc(&scp->vtb, j); 480 cut_buffer[i] = '\0'; 481 scp->status |= MOUSE_CUTTING; 482 483 /* mark the region */ 484 crit_enter(); 485 scp->mouse_cut_start = start; 486 scp->mouse_cut_end = end; 487 mark_for_update(scp, start); 488 mark_for_update(scp, end); 489 crit_exit(); 490 } 491 } 492 493 /* copy a line under the mouse pointer */ 494 static void 495 mouse_cut_line(scr_stat *scp) 496 { 497 int i; 498 int j; 499 500 if (scp->status & MOUSE_VISIBLE) { 501 /* remove the current cut mark */ 502 crit_enter(); 503 if (scp->mouse_cut_start <= scp->mouse_cut_end) { 504 mark_for_update(scp, scp->mouse_cut_start); 505 mark_for_update(scp, scp->mouse_cut_end); 506 } else if (scp->mouse_cut_end >= 0) { 507 mark_for_update(scp, scp->mouse_cut_end); 508 mark_for_update(scp, scp->mouse_cut_start); 509 } 510 511 /* mark the entire line */ 512 scp->mouse_cut_start = 513 (scp->mouse_pos / scp->xsize) * scp->xsize; 514 scp->mouse_cut_end = scp->mouse_cut_start + scp->xsize - 1; 515 mark_for_update(scp, scp->mouse_cut_start); 516 mark_for_update(scp, scp->mouse_cut_end); 517 crit_exit(); 518 519 /* copy the line into the cut buffer */ 520 for (i = 0, j = scp->mouse_cut_start; j <= scp->mouse_cut_end; ++j) 521 cut_buffer[i++] = sc_vtb_getc(&scp->vtb, j); 522 cut_buffer[i++] = '\r'; 523 cut_buffer[i] = '\0'; 524 scp->status |= MOUSE_CUTTING; 525 } 526 } 527 528 /* extend the marked region to the mouse pointer position */ 529 static void 530 mouse_cut_extend(scr_stat *scp) 531 { 532 int start; 533 int end; 534 535 if ((scp->status & MOUSE_VISIBLE) && !(scp->status & MOUSE_CUTTING) 536 && (scp->mouse_cut_end >= 0)) { 537 if (scp->mouse_cut_start <= scp->mouse_cut_end) { 538 start = scp->mouse_cut_start; 539 end = scp->mouse_cut_end; 540 } else { 541 start = scp->mouse_cut_end; 542 end = scp->mouse_cut_start - 1; 543 } 544 crit_enter(); 545 if (scp->mouse_pos > end) { 546 scp->mouse_cut_start = start; 547 scp->mouse_cut_end = end; 548 } else if (scp->mouse_pos < start) { 549 scp->mouse_cut_start = end + 1; 550 scp->mouse_cut_end = start; 551 } else { 552 if (scp->mouse_pos - start > end + 1 - scp->mouse_pos) { 553 scp->mouse_cut_start = start; 554 scp->mouse_cut_end = end; 555 } else { 556 scp->mouse_cut_start = end + 1; 557 scp->mouse_cut_end = start; 558 } 559 } 560 crit_exit(); 561 mouse_cut(scp); 562 scp->status |= MOUSE_CUTTING; 563 } 564 } 565 566 /* paste cut buffer contents into the current vty */ 567 static void 568 mouse_paste(scr_stat *scp) 569 { 570 if (scp->status & MOUSE_VISIBLE) 571 sc_paste(scp, cut_buffer, strlen(cut_buffer)); 572 } 573 574 #endif /* SC_NO_CUTPASTE */ 575 576 static void 577 sc_mouse_exit1_proc(struct proc *p) 578 { 579 scr_stat *scp; 580 581 scp = p->p_drv_priv; 582 KKASSERT(scp != NULL); 583 584 get_mplock(); 585 KKASSERT(scp->mouse_proc == p); 586 KKASSERT(scp->mouse_pid == p->p_pid); 587 588 scp->mouse_signal = 0; 589 scp->mouse_proc = NULL; 590 scp->mouse_pid = 0; 591 rel_mplock(); 592 593 PRELE(p); 594 p->p_flags &= ~P_SCMOUSE; 595 p->p_drv_priv = NULL; 596 } 597 598 /* 599 * sc_mouse_exit1: 600 * 601 * Handle exit1 for processes registered as MOUSE_MODE handlers. 602 * We must remove a process hold, established when MOUSE_MODE 603 * was enabled. 604 */ 605 static void 606 sc_mouse_exit1(struct thread *td) 607 { 608 struct proc *p; 609 610 p = td->td_proc; 611 KKASSERT(p != NULL); 612 613 if ((p->p_flags & P_SCMOUSE) == 0) 614 return; 615 616 617 sc_mouse_exit1_proc(p); 618 } 619 620 int 621 sc_mouse_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag) 622 { 623 mouse_info_t *mouse; 624 scr_stat *cur_scp; 625 scr_stat *scp; 626 int f; 627 628 scp = SC_STAT(tp->t_dev); 629 630 switch (cmd) { 631 632 case CONS_MOUSECTL: /* control mouse arrow */ 633 mouse = (mouse_info_t*) data; 634 cur_scp = scp->sc->cur_scp; 635 636 switch (mouse->operation) { 637 /* 638 * Setup a process to receive signals on mouse events. 639 */ 640 case MOUSE_MODE: 641 get_mplock(); 642 643 if (!ISSIGVALID(mouse->u.mode.signal)) { 644 /* Setting MOUSE_MODE w/ an invalid signal is used to disarm */ 645 if (scp->mouse_proc == curproc) { 646 sc_mouse_exit1_proc(curproc); 647 rel_mplock(); 648 return 0; 649 } else { 650 rel_mplock(); 651 return EINVAL; 652 } 653 } else { 654 /* Only one mouse process per syscons */ 655 if (scp->mouse_proc) { 656 rel_mplock(); 657 return EINVAL; 658 } 659 660 /* Only one syscons signal source per process */ 661 if (curproc->p_flags & P_SCMOUSE) { 662 rel_mplock(); 663 return EINVAL; 664 } 665 666 /* 667 * Process is stabilized by a hold, which is removed from 668 * sc_mouse_exit1. scp's mouse_{signal,proc,pid} fields 669 * are synchronized by the MP Lock. 670 */ 671 scp->mouse_signal = mouse->u.mode.signal; 672 scp->mouse_proc = curproc; 673 scp->mouse_pid = curproc->p_pid; 674 curproc->p_flags |= P_SCMOUSE; 675 KKASSERT(curproc->p_drv_priv == NULL); 676 curproc->p_drv_priv = scp; 677 PHOLD(curproc); 678 679 rel_mplock(); 680 return 0; 681 } 682 /*NOTREACHED*/ 683 break; 684 685 case MOUSE_SHOW: 686 crit_enter(); 687 if (!(scp->sc->flags & SC_MOUSE_ENABLED)) { 688 scp->sc->flags |= SC_MOUSE_ENABLED; 689 cur_scp->status &= ~MOUSE_HIDDEN; 690 if (!ISGRAPHSC(cur_scp)) 691 mark_all(cur_scp); 692 crit_exit(); 693 return 0; 694 } else { 695 crit_exit(); 696 return EINVAL; 697 } 698 break; 699 700 case MOUSE_HIDE: 701 crit_enter(); 702 if (scp->sc->flags & SC_MOUSE_ENABLED) { 703 scp->sc->flags &= ~SC_MOUSE_ENABLED; 704 sc_remove_all_mouse(scp->sc); 705 crit_exit(); 706 return 0; 707 } else { 708 crit_exit(); 709 return EINVAL; 710 } 711 break; 712 713 case MOUSE_MOVEABS: 714 crit_enter(); 715 scp->mouse_xpos = mouse->u.data.x; 716 scp->mouse_ypos = mouse->u.data.y; 717 set_mouse_pos(scp); 718 crit_exit(); 719 break; 720 721 case MOUSE_MOVEREL: 722 crit_enter(); 723 scp->mouse_xpos += mouse->u.data.x; 724 scp->mouse_ypos += mouse->u.data.y; 725 set_mouse_pos(scp); 726 crit_exit(); 727 break; 728 729 case MOUSE_GETINFO: 730 mouse->u.data.x = scp->mouse_xpos; 731 mouse->u.data.y = scp->mouse_ypos; 732 mouse->u.data.z = 0; 733 mouse->u.data.buttons = scp->mouse_buttons; 734 return 0; 735 736 case MOUSE_ACTION: 737 case MOUSE_MOTION_EVENT: 738 /* send out mouse event on /dev/sysmouse */ 739 #if 0 740 /* this should maybe only be settable from /dev/consolectl SOS */ 741 if (SC_VTY(tp->t_dev) != SC_CONSOLECTL) 742 return ENOTTY; 743 #endif 744 crit_enter(); 745 if (mouse->u.data.x != 0 || mouse->u.data.y != 0) { 746 cur_scp->mouse_xpos += mouse->u.data.x; 747 cur_scp->mouse_ypos += mouse->u.data.y; 748 set_mouse_pos(cur_scp); 749 } 750 f = 0; 751 if (mouse->operation == MOUSE_ACTION) { 752 f = cur_scp->mouse_buttons ^ mouse->u.data.buttons; 753 cur_scp->mouse_buttons = mouse->u.data.buttons; 754 } 755 crit_exit(); 756 757 if (sysmouse_event(mouse) == 0) 758 return 0; 759 760 /* 761 * If any buttons are down or the mouse has moved a lot, 762 * stop the screen saver. 763 */ 764 if (((mouse->operation == MOUSE_ACTION) && mouse->u.data.buttons) 765 || (mouse->u.data.x*mouse->u.data.x 766 + mouse->u.data.y*mouse->u.data.y 767 >= SC_WAKEUP_DELTA*SC_WAKEUP_DELTA)) { 768 sc_touch_scrn_saver(); 769 } 770 771 cur_scp->status &= ~MOUSE_HIDDEN; 772 773 get_mplock(); 774 if (cur_scp->mouse_signal) { 775 KKASSERT(cur_scp->mouse_proc != NULL); 776 ksignal(cur_scp->mouse_proc, cur_scp->mouse_signal); 777 rel_mplock(); 778 break; 779 } 780 rel_mplock(); 781 782 if (ISGRAPHSC(cur_scp) || (cut_buffer == NULL)) 783 break; 784 785 #ifndef SC_NO_CUTPASTE 786 if ((mouse->operation == MOUSE_ACTION) && f) { 787 /* process button presses */ 788 if (cur_scp->mouse_buttons & MOUSE_BUTTON1DOWN) 789 mouse_cut_start(cur_scp); 790 else 791 mouse_cut_end(cur_scp); 792 if (cur_scp->mouse_buttons & MOUSE_BUTTON2DOWN || 793 cur_scp->mouse_buttons & MOUSE_BUTTON3DOWN) 794 mouse_paste(cur_scp); 795 } 796 #endif /* SC_NO_CUTPASTE */ 797 break; 798 799 case MOUSE_BUTTON_EVENT: 800 if ((mouse->u.event.id & MOUSE_BUTTONS) == 0) 801 return EINVAL; 802 if (mouse->u.event.value < 0) 803 return EINVAL; 804 #if 0 805 /* this should maybe only be settable from /dev/consolectl SOS */ 806 if (SC_VTY(tp->t_dev) != SC_CONSOLECTL) 807 return ENOTTY; 808 #endif 809 if (mouse->u.event.value > 0) 810 cur_scp->mouse_buttons |= mouse->u.event.id; 811 else 812 cur_scp->mouse_buttons &= ~mouse->u.event.id; 813 814 if (sysmouse_event(mouse) == 0) 815 return 0; 816 817 /* if a button is held down, stop the screen saver */ 818 if (mouse->u.event.value > 0) 819 sc_touch_scrn_saver(); 820 821 cur_scp->status &= ~MOUSE_HIDDEN; 822 823 get_mplock(); 824 if (cur_scp->mouse_signal) { 825 KKASSERT(cur_scp->mouse_proc != NULL); 826 ksignal(cur_scp->mouse_proc, cur_scp->mouse_signal); 827 rel_mplock(); 828 break; 829 } 830 rel_mplock(); 831 832 if (ISGRAPHSC(cur_scp) || (cut_buffer == NULL)) 833 break; 834 835 #ifndef SC_NO_CUTPASTE 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 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 >= (unsigned char)-1 - 4) 884 return EINVAL; 885 crit_enter(); 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_height, 890 cur_scp->font, 891 cur_scp->sc->mouse_char, 4); 892 #endif 893 scp->sc->mouse_char = mouse->u.mouse_char; 894 crit_exit(); 895 } 896 break; 897 898 default: 899 return EINVAL; 900 } 901 902 return 0; 903 } 904 905 return ENOIOCTL; 906 } 907 908 void 909 sc_mouse_init(void *unused) 910 { 911 at_exit(sc_mouse_exit1); 912 } 913 914 void 915 sc_mouse_uninit(void *unused) 916 { 917 } 918 919 SYSINIT(sc_mouse_init, SI_SUB_DRIVERS, SI_ORDER_ANY, sc_mouse_init, NULL); 920 SYSUNINIT(sc_mouse_uninit, SI_SUB_DRIVERS, SI_ORDER_ANY, sc_mouse_uninit, NULL); 921 922 #endif /* SC_NO_SYSMOUSE */ 923