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 "sc.h" 30 #include "opt_syscons.h" 31 32 #if NSC > 0 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/conf.h> 37 #include <sys/signalvar.h> 38 #include <sys/proc.h> 39 #include <sys/tty.h> 40 #include <sys/kernel.h> 41 #include <sys/malloc.h> 42 43 #include <machine/console.h> 44 #include <machine/mouse.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 /* local variables */ 76 #ifndef SC_NO_SYSMOUSE 77 static int mouse_level; /* sysmouse protocol level */ 78 static mousestatus_t mouse_status = { 0, 0, 0, 0, 0, 0 }; 79 static int cut_buffer_size; 80 static u_char *cut_buffer; 81 #endif /* SC_NO_SYSMOUE */ 82 83 /* local functions */ 84 #ifndef SC_NO_SYSMOUSE 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 static void mouse_paste(scr_stat *scp); 96 #endif /* SC_NO_CUTPASTE */ 97 #endif /* SC_NO_SYSMOUE */ 98 99 #ifndef SC_NO_CUTPASTE 100 /* allocate a cut buffer */ 101 void 102 sc_alloc_cut_buffer(scr_stat *scp, int wait) 103 { 104 u_char *p; 105 106 if ((cut_buffer == NULL) 107 || (cut_buffer_size < scp->xsize * scp->ysize + 1)) { 108 p = cut_buffer; 109 cut_buffer = NULL; 110 if (p != NULL) 111 free(p, M_DEVBUF); 112 cut_buffer_size = scp->xsize * scp->ysize + 1; 113 p = (u_char *)malloc(cut_buffer_size, 114 M_DEVBUF, (wait) ? M_WAITOK : M_NOWAIT); 115 if (p != NULL) 116 p[0] = '\0'; 117 cut_buffer = p; 118 } 119 } 120 #endif /* SC_NO_CUTPASTE */ 121 122 #ifndef SC_NO_SYSMOUSE 123 124 /* modify the sysmouse software level */ 125 void 126 sc_mouse_set_level(int level) 127 { 128 mouse_level = level; 129 } 130 131 /* move mouse */ 132 void 133 sc_mouse_move(scr_stat *scp, int x, int y) 134 { 135 int s; 136 137 s = spltty(); 138 scp->mouse_xpos = x; 139 scp->mouse_ypos = y; 140 scp->mouse_pos = scp->mouse_oldpos = 141 (y/scp->font_size - scp->yoff)*scp->xsize + x/8 - scp->xoff; 142 splx(s); 143 } 144 145 /* adjust mouse position */ 146 static void 147 set_mouse_pos(scr_stat *scp) 148 { 149 static int last_xpos = -1, last_ypos = -1; 150 151 if (scp->mouse_xpos < scp->xoff*8) 152 scp->mouse_xpos = scp->xoff*8; 153 if (scp->mouse_ypos < scp->yoff*scp->font_size) 154 scp->mouse_ypos = scp->yoff*scp->font_size; 155 if (ISGRAPHSC(scp)) { 156 if (scp->mouse_xpos > scp->xpixel-1) 157 scp->mouse_xpos = scp->xpixel-1; 158 if (scp->mouse_ypos > scp->ypixel-1) 159 scp->mouse_ypos = scp->ypixel-1; 160 return; 161 } else { 162 if (scp->mouse_xpos > (scp->xsize + scp->xoff)*8 - 1) 163 scp->mouse_xpos = (scp->xsize + scp->xoff)*8 - 1; 164 if (scp->mouse_ypos > (scp->ysize + scp->yoff)*scp->font_size - 1) 165 scp->mouse_ypos = (scp->ysize + scp->yoff)*scp->font_size - 1; 166 } 167 168 if (scp->mouse_xpos != last_xpos || scp->mouse_ypos != last_ypos) { 169 scp->status |= MOUSE_MOVED; 170 scp->mouse_pos = 171 (scp->mouse_ypos/scp->font_size - scp->yoff)*scp->xsize 172 + scp->mouse_xpos/8 - scp->xoff; 173 #ifndef SC_NO_CUTPASTE 174 if ((scp->status & MOUSE_VISIBLE) && (scp->status & MOUSE_CUTTING)) 175 mouse_cut(scp); 176 #endif 177 } 178 } 179 180 #ifndef SC_NO_CUTPASTE 181 182 void 183 sc_draw_mouse_image(scr_stat *scp) 184 { 185 if (ISGRAPHSC(scp)) 186 return; 187 188 ++scp->sc->videoio_in_progress; 189 (*scp->rndr->draw_mouse)(scp, scp->mouse_xpos, scp->mouse_ypos, TRUE); 190 scp->mouse_oldpos = scp->mouse_pos; 191 --scp->sc->videoio_in_progress; 192 } 193 194 void 195 sc_remove_mouse_image(scr_stat *scp) 196 { 197 int size; 198 int i; 199 200 if (ISGRAPHSC(scp)) 201 return; 202 203 ++scp->sc->videoio_in_progress; 204 (*scp->rndr->draw_mouse)(scp, 205 (scp->mouse_oldpos%scp->xsize + scp->xoff)*8, 206 (scp->mouse_oldpos/scp->xsize + scp->yoff) 207 * scp->font_size, 208 FALSE); 209 size = scp->xsize*scp->ysize; 210 i = scp->mouse_oldpos; 211 mark_for_update(scp, i); 212 mark_for_update(scp, i); 213 #ifndef PC98 214 if (i + scp->xsize + 1 < size) { 215 mark_for_update(scp, i + scp->xsize + 1); 216 } else if (i + scp->xsize < size) { 217 mark_for_update(scp, i + scp->xsize); 218 } else if (i + 1 < size) { 219 mark_for_update(scp, i + 1); 220 } 221 #endif /* PC98 */ 222 --scp->sc->videoio_in_progress; 223 } 224 225 int 226 sc_inside_cutmark(scr_stat *scp, int pos) 227 { 228 int start; 229 int end; 230 231 if (scp->mouse_cut_end < 0) 232 return FALSE; 233 if (scp->mouse_cut_start <= scp->mouse_cut_end) { 234 start = scp->mouse_cut_start; 235 end = scp->mouse_cut_end; 236 } else { 237 start = scp->mouse_cut_end; 238 end = scp->mouse_cut_start - 1; 239 } 240 return ((start <= pos) && (pos <= end)); 241 } 242 243 void 244 sc_remove_cutmarking(scr_stat *scp) 245 { 246 int s; 247 248 s = spltty(); 249 if (scp->mouse_cut_end >= 0) { 250 mark_for_update(scp, scp->mouse_cut_start); 251 mark_for_update(scp, scp->mouse_cut_end); 252 } 253 scp->mouse_cut_start = scp->xsize*scp->ysize; 254 scp->mouse_cut_end = -1; 255 splx(s); 256 scp->status &= ~MOUSE_CUTTING; 257 } 258 259 void 260 sc_remove_all_cutmarkings(sc_softc_t *sc) 261 { 262 scr_stat *scp; 263 int i; 264 265 /* delete cut markings in all vtys */ 266 for (i = 0; i < sc->vtys; ++i) { 267 scp = SC_STAT(sc->dev[i]); 268 if (scp == NULL) 269 continue; 270 sc_remove_cutmarking(scp); 271 } 272 } 273 274 void 275 sc_remove_all_mouse(sc_softc_t *sc) 276 { 277 scr_stat *scp; 278 int i; 279 280 for (i = 0; i < sc->vtys; ++i) { 281 scp = SC_STAT(sc->dev[i]); 282 if (scp == NULL) 283 continue; 284 if (scp->status & MOUSE_VISIBLE) { 285 scp->status &= ~MOUSE_VISIBLE; 286 mark_all(scp); 287 } 288 } 289 } 290 291 #define IS_SPACE_CHAR(c) (((c) & 0xff) == ' ') 292 293 /* skip spaces to right */ 294 static int 295 skip_spc_right(scr_stat *scp, int p) 296 { 297 int c; 298 int i; 299 300 for (i = p % scp->xsize; i < scp->xsize; ++i) { 301 c = sc_vtb_getc(&scp->vtb, p); 302 if (!IS_SPACE_CHAR(c)) 303 break; 304 ++p; 305 } 306 return i; 307 } 308 309 /* skip spaces to left */ 310 static int 311 skip_spc_left(scr_stat *scp, int p) 312 { 313 int c; 314 int i; 315 316 for (i = p-- % scp->xsize - 1; i >= 0; --i) { 317 c = sc_vtb_getc(&scp->vtb, p); 318 if (!IS_SPACE_CHAR(c)) 319 break; 320 --p; 321 } 322 return i; 323 } 324 325 /* copy marked region to the cut buffer */ 326 static void 327 mouse_cut(scr_stat *scp) 328 { 329 int start; 330 int end; 331 int from; 332 int to; 333 int blank; 334 int c; 335 int p; 336 int s; 337 int i; 338 339 start = scp->mouse_cut_start; 340 end = scp->mouse_cut_end; 341 if (scp->mouse_pos >= start) { 342 from = start; 343 to = end = scp->mouse_pos; 344 } else { 345 from = end = scp->mouse_pos; 346 to = start - 1; 347 } 348 for (p = from, i = blank = 0; p <= to; ++p) { 349 cut_buffer[i] = sc_vtb_getc(&scp->vtb, p); 350 /* remember the position of the last non-space char */ 351 if (!IS_SPACE_CHAR(cut_buffer[i++])) 352 blank = i; /* the first space after the last non-space */ 353 /* trim trailing blank when crossing lines */ 354 if ((p % scp->xsize) == (scp->xsize - 1)) { 355 cut_buffer[blank] = '\r'; 356 i = blank + 1; 357 } 358 } 359 cut_buffer[i] = '\0'; 360 361 /* scan towards the end of the last line */ 362 --p; 363 for (i = p % scp->xsize; i < scp->xsize; ++i) { 364 c = sc_vtb_getc(&scp->vtb, p); 365 if (!IS_SPACE_CHAR(c)) 366 break; 367 ++p; 368 } 369 /* if there is nothing but blank chars, trim them, but mark towards eol */ 370 if (i >= scp->xsize) { 371 if (end >= start) 372 to = end = p - 1; 373 else 374 to = start = p; 375 cut_buffer[blank++] = '\r'; 376 cut_buffer[blank] = '\0'; 377 } 378 379 /* remove the current marking */ 380 s = spltty(); 381 if (scp->mouse_cut_start <= scp->mouse_cut_end) { 382 mark_for_update(scp, scp->mouse_cut_start); 383 mark_for_update(scp, scp->mouse_cut_end); 384 } else if (scp->mouse_cut_end >= 0) { 385 mark_for_update(scp, scp->mouse_cut_end); 386 mark_for_update(scp, scp->mouse_cut_start); 387 } 388 389 /* mark the new region */ 390 scp->mouse_cut_start = start; 391 scp->mouse_cut_end = end; 392 mark_for_update(scp, from); 393 mark_for_update(scp, to); 394 splx(s); 395 } 396 397 /* a mouse button is pressed, start cut operation */ 398 static void 399 mouse_cut_start(scr_stat *scp) 400 { 401 int i; 402 int j; 403 int s; 404 405 if (scp->status & MOUSE_VISIBLE) { 406 i = scp->mouse_cut_start; 407 j = scp->mouse_cut_end; 408 sc_remove_all_cutmarkings(scp->sc); 409 if (scp->mouse_pos == i && i == j) { 410 cut_buffer[0] = '\0'; 411 } else if (skip_spc_right(scp, scp->mouse_pos) >= scp->xsize) { 412 /* if the pointer is on trailing blank chars, mark towards eol */ 413 i = skip_spc_left(scp, scp->mouse_pos) + 1; 414 s = spltty(); 415 scp->mouse_cut_start = 416 (scp->mouse_pos / scp->xsize) * scp->xsize + i; 417 scp->mouse_cut_end = 418 (scp->mouse_pos / scp->xsize + 1) * scp->xsize - 1; 419 splx(s); 420 cut_buffer[0] = '\r'; 421 cut_buffer[1] = '\0'; 422 scp->status |= MOUSE_CUTTING; 423 } else { 424 s = spltty(); 425 scp->mouse_cut_start = scp->mouse_pos; 426 scp->mouse_cut_end = scp->mouse_cut_start; 427 splx(s); 428 cut_buffer[0] = sc_vtb_getc(&scp->vtb, scp->mouse_cut_start); 429 cut_buffer[1] = '\0'; 430 scp->status |= MOUSE_CUTTING; 431 } 432 mark_all(scp); /* this is probably overkill XXX */ 433 } 434 } 435 436 /* end of cut operation */ 437 static void 438 mouse_cut_end(scr_stat *scp) 439 { 440 if (scp->status & MOUSE_VISIBLE) 441 scp->status &= ~MOUSE_CUTTING; 442 } 443 444 /* copy a word under the mouse pointer */ 445 static void 446 mouse_cut_word(scr_stat *scp) 447 { 448 int start; 449 int end; 450 int sol; 451 int eol; 452 int c; 453 int s; 454 int i; 455 int j; 456 457 /* 458 * Because we don't have locale information in the kernel, 459 * we only distinguish space char and non-space chars. Punctuation 460 * chars, symbols and other regular chars are all treated alike. 461 */ 462 if (scp->status & MOUSE_VISIBLE) { 463 /* remove the current cut mark */ 464 s = spltty(); 465 if (scp->mouse_cut_start <= scp->mouse_cut_end) { 466 mark_for_update(scp, scp->mouse_cut_start); 467 mark_for_update(scp, scp->mouse_cut_end); 468 } else if (scp->mouse_cut_end >= 0) { 469 mark_for_update(scp, scp->mouse_cut_end); 470 mark_for_update(scp, scp->mouse_cut_start); 471 } 472 scp->mouse_cut_start = scp->xsize*scp->ysize; 473 scp->mouse_cut_end = -1; 474 splx(s); 475 476 sol = (scp->mouse_pos / scp->xsize) * scp->xsize; 477 eol = sol + scp->xsize; 478 c = sc_vtb_getc(&scp->vtb, scp->mouse_pos); 479 if (IS_SPACE_CHAR(c)) { 480 /* blank space */ 481 for (j = scp->mouse_pos; j >= sol; --j) { 482 c = sc_vtb_getc(&scp->vtb, j); 483 if (!IS_SPACE_CHAR(c)) 484 break; 485 } 486 start = ++j; 487 for (j = scp->mouse_pos; j < eol; ++j) { 488 c = sc_vtb_getc(&scp->vtb, j); 489 if (!IS_SPACE_CHAR(c)) 490 break; 491 } 492 end = j - 1; 493 } else { 494 /* non-space word */ 495 for (j = scp->mouse_pos; j >= sol; --j) { 496 c = sc_vtb_getc(&scp->vtb, j); 497 if (IS_SPACE_CHAR(c)) 498 break; 499 } 500 start = ++j; 501 for (j = scp->mouse_pos; j < eol; ++j) { 502 c = sc_vtb_getc(&scp->vtb, j); 503 if (IS_SPACE_CHAR(c)) 504 break; 505 } 506 end = j - 1; 507 } 508 509 /* copy the found word */ 510 for (i = 0, j = start; j <= end; ++j) 511 cut_buffer[i++] = sc_vtb_getc(&scp->vtb, j); 512 cut_buffer[i] = '\0'; 513 scp->status |= MOUSE_CUTTING; 514 515 /* mark the region */ 516 s = spltty(); 517 scp->mouse_cut_start = start; 518 scp->mouse_cut_end = end; 519 mark_for_update(scp, start); 520 mark_for_update(scp, end); 521 splx(s); 522 } 523 } 524 525 /* copy a line under the mouse pointer */ 526 static void 527 mouse_cut_line(scr_stat *scp) 528 { 529 int s; 530 int i; 531 int j; 532 533 if (scp->status & MOUSE_VISIBLE) { 534 /* remove the current cut mark */ 535 s = spltty(); 536 if (scp->mouse_cut_start <= scp->mouse_cut_end) { 537 mark_for_update(scp, scp->mouse_cut_start); 538 mark_for_update(scp, scp->mouse_cut_end); 539 } else if (scp->mouse_cut_end >= 0) { 540 mark_for_update(scp, scp->mouse_cut_end); 541 mark_for_update(scp, scp->mouse_cut_start); 542 } 543 544 /* mark the entire line */ 545 scp->mouse_cut_start = 546 (scp->mouse_pos / scp->xsize) * scp->xsize; 547 scp->mouse_cut_end = scp->mouse_cut_start + scp->xsize - 1; 548 mark_for_update(scp, scp->mouse_cut_start); 549 mark_for_update(scp, scp->mouse_cut_end); 550 splx(s); 551 552 /* copy the line into the cut buffer */ 553 for (i = 0, j = scp->mouse_cut_start; j <= scp->mouse_cut_end; ++j) 554 cut_buffer[i++] = sc_vtb_getc(&scp->vtb, j); 555 cut_buffer[i++] = '\r'; 556 cut_buffer[i] = '\0'; 557 scp->status |= MOUSE_CUTTING; 558 } 559 } 560 561 /* extend the marked region to the mouse pointer position */ 562 static void 563 mouse_cut_extend(scr_stat *scp) 564 { 565 int start; 566 int end; 567 int s; 568 569 if ((scp->status & MOUSE_VISIBLE) && !(scp->status & MOUSE_CUTTING) 570 && (scp->mouse_cut_end >= 0)) { 571 if (scp->mouse_cut_start <= scp->mouse_cut_end) { 572 start = scp->mouse_cut_start; 573 end = scp->mouse_cut_end; 574 } else { 575 start = scp->mouse_cut_end; 576 end = scp->mouse_cut_start - 1; 577 } 578 s = spltty(); 579 if (scp->mouse_pos > end) { 580 scp->mouse_cut_start = start; 581 scp->mouse_cut_end = end; 582 } else if (scp->mouse_pos < start) { 583 scp->mouse_cut_start = end + 1; 584 scp->mouse_cut_end = start; 585 } else { 586 if (scp->mouse_pos - start > end + 1 - scp->mouse_pos) { 587 scp->mouse_cut_start = start; 588 scp->mouse_cut_end = end; 589 } else { 590 scp->mouse_cut_start = end + 1; 591 scp->mouse_cut_end = start; 592 } 593 } 594 splx(s); 595 mouse_cut(scp); 596 scp->status |= MOUSE_CUTTING; 597 } 598 } 599 600 /* paste cut buffer contents into the current vty */ 601 static void 602 mouse_paste(scr_stat *scp) 603 { 604 if (scp->status & MOUSE_VISIBLE) 605 sc_paste(scp, cut_buffer, strlen(cut_buffer)); 606 } 607 608 #endif /* SC_NO_CUTPASTE */ 609 610 int 611 sc_mouse_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag, 612 struct proc *p) 613 { 614 615 scr_stat *scp; 616 int s; 617 int i; 618 619 /* scp == NULL, if tp == sc_get_mouse_tty() (/dev/sysmouse) */ 620 scp = SC_STAT(tp->t_dev); 621 622 switch (cmd) { 623 624 case CONS_MOUSECTL: /* control mouse arrow */ 625 case OLD_CONS_MOUSECTL: 626 { 627 /* MOUSE_BUTTON?DOWN -> MOUSE_MSC_BUTTON?UP */ 628 static int butmap[8] = { 629 MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP, 630 MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP, 631 MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON3UP, 632 MOUSE_MSC_BUTTON3UP, 633 MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP, 634 MOUSE_MSC_BUTTON2UP, 635 MOUSE_MSC_BUTTON1UP, 636 0, 637 }; 638 mouse_info_t *mouse = (mouse_info_t*)data; 639 mouse_info_t buf; 640 scr_stat *cur_scp; 641 struct tty *mtty; 642 int f; 643 644 if (scp == NULL) 645 return ENOTTY; 646 647 if (cmd == OLD_CONS_MOUSECTL) { 648 static u_char swapb[] = { 0, 4, 2, 6, 1, 5, 3, 7 }; 649 old_mouse_info_t *old_mouse = (old_mouse_info_t *)data; 650 651 mouse = &buf; 652 mouse->operation = old_mouse->operation; 653 switch (mouse->operation) { 654 case MOUSE_MODE: 655 mouse->u.mode = old_mouse->u.mode; 656 break; 657 case MOUSE_SHOW: 658 case MOUSE_HIDE: 659 break; 660 case MOUSE_MOVEABS: 661 case MOUSE_MOVEREL: 662 case MOUSE_ACTION: 663 mouse->u.data.x = old_mouse->u.data.x; 664 mouse->u.data.y = old_mouse->u.data.y; 665 mouse->u.data.z = 0; 666 mouse->u.data.buttons = swapb[old_mouse->u.data.buttons & 0x7]; 667 break; 668 case MOUSE_GETINFO: 669 old_mouse->u.data.x = scp->mouse_xpos; 670 old_mouse->u.data.y = scp->mouse_ypos; 671 old_mouse->u.data.buttons = swapb[scp->mouse_buttons & 0x7]; 672 break; 673 default: 674 return EINVAL; 675 } 676 } 677 678 cur_scp = scp->sc->cur_scp; 679 680 switch (mouse->operation) { 681 case MOUSE_MODE: 682 if (ISSIGVALID(mouse->u.mode.signal)) { 683 scp->mouse_signal = mouse->u.mode.signal; 684 scp->mouse_proc = p; 685 scp->mouse_pid = p->p_pid; 686 } 687 else { 688 scp->mouse_signal = 0; 689 scp->mouse_proc = NULL; 690 scp->mouse_pid = 0; 691 } 692 return 0; 693 694 case MOUSE_SHOW: 695 if (!ISMOUSEAVAIL(scp->sc->adp->va_flags)) 696 return EINVAL; 697 s = spltty(); 698 if (!(scp->sc->flags & SC_MOUSE_ENABLED)) { 699 scp->sc->flags |= SC_MOUSE_ENABLED; 700 if (!ISGRAPHSC(cur_scp)) { 701 cur_scp->status |= MOUSE_VISIBLE; 702 mark_all(cur_scp); 703 } 704 splx(s); 705 return 0; 706 } else { 707 splx(s); 708 return EINVAL; 709 } 710 break; 711 712 case MOUSE_HIDE: 713 s = spltty(); 714 if (scp->sc->flags & SC_MOUSE_ENABLED) { 715 scp->sc->flags &= ~SC_MOUSE_ENABLED; 716 sc_remove_all_mouse(scp->sc); 717 splx(s); 718 return 0; 719 } else { 720 splx(s); 721 return EINVAL; 722 } 723 break; 724 725 case MOUSE_MOVEABS: 726 s = spltty(); 727 scp->mouse_xpos = mouse->u.data.x; 728 scp->mouse_ypos = mouse->u.data.y; 729 set_mouse_pos(scp); 730 splx(s); 731 break; 732 733 case MOUSE_MOVEREL: 734 s = spltty(); 735 scp->mouse_xpos += mouse->u.data.x; 736 scp->mouse_ypos += mouse->u.data.y; 737 set_mouse_pos(scp); 738 splx(s); 739 break; 740 741 case MOUSE_GETINFO: 742 mouse->u.data.x = scp->mouse_xpos; 743 mouse->u.data.y = scp->mouse_ypos; 744 mouse->u.data.z = 0; 745 mouse->u.data.buttons = scp->mouse_buttons; 746 return 0; 747 748 case MOUSE_ACTION: 749 case MOUSE_MOTION_EVENT: 750 /* send out mouse event on /dev/sysmouse */ 751 #if 0 752 /* this should maybe only be settable from /dev/consolectl SOS */ 753 if (SC_VTY(tp->t_dev) != SC_CONSOLECTL) 754 return ENOTTY; 755 #endif 756 s = spltty(); 757 if (mouse->u.data.x != 0 || mouse->u.data.y != 0) { 758 cur_scp->mouse_xpos += mouse->u.data.x; 759 cur_scp->mouse_ypos += mouse->u.data.y; 760 set_mouse_pos(cur_scp); 761 } 762 f = 0; 763 if (mouse->operation == MOUSE_ACTION) { 764 f = cur_scp->mouse_buttons ^ mouse->u.data.buttons; 765 cur_scp->mouse_buttons = mouse->u.data.buttons; 766 } 767 splx(s); 768 769 mouse_status.dx += mouse->u.data.x; 770 mouse_status.dy += mouse->u.data.y; 771 mouse_status.dz += mouse->u.data.z; 772 if (mouse->operation == MOUSE_ACTION) 773 mouse_status.button = mouse->u.data.buttons; 774 mouse_status.flags |= 775 ((mouse->u.data.x || mouse->u.data.y || mouse->u.data.z) ? 776 MOUSE_POSCHANGED : 0) 777 | (mouse_status.obutton ^ mouse_status.button); 778 if (mouse_status.flags == 0) 779 return 0; 780 781 mtty = sc_get_mouse_tty(); 782 if (mtty->t_state & TS_ISOPEN) { 783 u_char buf[MOUSE_SYS_PACKETSIZE]; 784 785 /* the first five bytes are compatible with MouseSystems' */ 786 buf[0] = MOUSE_MSC_SYNC 787 | butmap[mouse_status.button & MOUSE_STDBUTTONS]; 788 i = imax(imin(mouse->u.data.x, 255), -256); 789 buf[1] = i >> 1; 790 buf[3] = i - buf[1]; 791 i = -imax(imin(mouse->u.data.y, 255), -256); 792 buf[2] = i >> 1; 793 buf[4] = i - buf[2]; 794 for (i = 0; i < MOUSE_MSC_PACKETSIZE; i++) 795 (*linesw[mtty->t_line].l_rint)(buf[i], mtty); 796 if (mouse_level >= 1) { /* extended part */ 797 i = imax(imin(mouse->u.data.z, 127), -128); 798 buf[5] = (i >> 1) & 0x7f; 799 buf[6] = (i - (i >> 1)) & 0x7f; 800 /* buttons 4-10 */ 801 buf[7] = (~mouse_status.button >> 3) & 0x7f; 802 for (i = MOUSE_MSC_PACKETSIZE; 803 i < MOUSE_SYS_PACKETSIZE; i++) 804 (*linesw[mtty->t_line].l_rint)(buf[i], mtty); 805 } 806 } 807 808 /* 809 * If any buttons are down or the mouse has moved a lot, 810 * stop the screen saver. 811 */ 812 if (((mouse->operation == MOUSE_ACTION) && mouse->u.data.buttons) 813 || (mouse->u.data.x*mouse->u.data.x 814 + mouse->u.data.y*mouse->u.data.y 815 >= SC_WAKEUP_DELTA*SC_WAKEUP_DELTA)) { 816 sc_touch_scrn_saver(); 817 } 818 819 #ifndef SC_NO_CUTPASTE 820 if (!ISGRAPHSC(cur_scp) && (cur_scp->sc->flags & SC_MOUSE_ENABLED)) 821 cur_scp->status |= MOUSE_VISIBLE; 822 #endif /* SC_NO_CUTPASTE */ 823 824 if (cur_scp->mouse_signal) { 825 /* has controlling process died? */ 826 if (cur_scp->mouse_proc && 827 (cur_scp->mouse_proc != pfind(cur_scp->mouse_pid))){ 828 cur_scp->mouse_signal = 0; 829 cur_scp->mouse_proc = NULL; 830 cur_scp->mouse_pid = 0; 831 } else { 832 psignal(cur_scp->mouse_proc, cur_scp->mouse_signal); 833 break; 834 } 835 } 836 837 if (ISGRAPHSC(cur_scp) || (cut_buffer == NULL)) 838 break; 839 840 #ifndef SC_NO_CUTPASTE 841 if ((mouse->operation == MOUSE_ACTION) && f) { 842 /* process button presses */ 843 if (cur_scp->mouse_buttons & MOUSE_BUTTON1DOWN) 844 mouse_cut_start(cur_scp); 845 else 846 mouse_cut_end(cur_scp); 847 if (cur_scp->mouse_buttons & MOUSE_BUTTON2DOWN || 848 cur_scp->mouse_buttons & MOUSE_BUTTON3DOWN) 849 mouse_paste(cur_scp); 850 } 851 #endif /* SC_NO_CUTPASTE */ 852 break; 853 854 case MOUSE_BUTTON_EVENT: 855 if ((mouse->u.event.id & MOUSE_BUTTONS) == 0) 856 return EINVAL; 857 if (mouse->u.event.value < 0) 858 return EINVAL; 859 #if 0 860 /* this should maybe only be settable from /dev/consolectl SOS */ 861 if (SC_VTY(tp->t_dev) != SC_CONSOLECTL) 862 return ENOTTY; 863 #endif 864 if (mouse->u.event.value > 0) { 865 cur_scp->mouse_buttons |= mouse->u.event.id; 866 mouse_status.button |= mouse->u.event.id; 867 } else { 868 cur_scp->mouse_buttons &= ~mouse->u.event.id; 869 mouse_status.button &= ~mouse->u.event.id; 870 } 871 mouse_status.flags |= mouse_status.obutton ^ mouse_status.button; 872 if (mouse_status.flags == 0) 873 return 0; 874 875 mtty = sc_get_mouse_tty(); 876 if (mtty->t_state & TS_ISOPEN) { 877 u_char buf[MOUSE_SYS_PACKETSIZE]; 878 879 buf[0] = MOUSE_MSC_SYNC 880 | butmap[mouse_status.button & MOUSE_STDBUTTONS]; 881 buf[7] = (~mouse_status.button >> 3) & 0x7f; 882 buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0; 883 for (i = 0; 884 i < ((mouse_level >= 1) ? MOUSE_SYS_PACKETSIZE 885 : MOUSE_MSC_PACKETSIZE); i++) 886 (*linesw[mtty->t_line].l_rint)(buf[i], mtty); 887 } 888 889 /* if a button is held down, stop the screen saver */ 890 if (mouse->u.event.value > 0) 891 sc_touch_scrn_saver(); 892 893 #ifndef SC_NO_CUTPASTE 894 if (!ISGRAPHSC(cur_scp) && (cur_scp->sc->flags & SC_MOUSE_ENABLED)) 895 cur_scp->status |= MOUSE_VISIBLE; 896 #endif /* SC_NO_CUTPASTE */ 897 898 if (cur_scp->mouse_signal) { 899 if (cur_scp->mouse_proc && 900 (cur_scp->mouse_proc != pfind(cur_scp->mouse_pid))){ 901 cur_scp->mouse_signal = 0; 902 cur_scp->mouse_proc = NULL; 903 cur_scp->mouse_pid = 0; 904 } else { 905 psignal(cur_scp->mouse_proc, cur_scp->mouse_signal); 906 break; 907 } 908 } 909 910 if (ISGRAPHSC(cur_scp) || (cut_buffer == NULL)) 911 break; 912 913 #ifndef SC_NO_CUTPASTE 914 switch (mouse->u.event.id) { 915 case MOUSE_BUTTON1DOWN: 916 switch (mouse->u.event.value % 4) { 917 case 0: /* up */ 918 mouse_cut_end(cur_scp); 919 break; 920 case 1: /* single click: start cut operation */ 921 mouse_cut_start(cur_scp); 922 break; 923 case 2: /* double click: cut a word */ 924 mouse_cut_word(cur_scp); 925 mouse_cut_end(cur_scp); 926 break; 927 case 3: /* triple click: cut a line */ 928 mouse_cut_line(cur_scp); 929 mouse_cut_end(cur_scp); 930 break; 931 } 932 break; 933 case SC_MOUSE_PASTEBUTTON: 934 switch (mouse->u.event.value) { 935 case 0: /* up */ 936 break; 937 default: 938 mouse_paste(cur_scp); 939 break; 940 } 941 break; 942 case SC_MOUSE_EXTENDBUTTON: 943 switch (mouse->u.event.value) { 944 case 0: /* up */ 945 if (!(cur_scp->mouse_buttons & MOUSE_BUTTON1DOWN)) 946 mouse_cut_end(cur_scp); 947 break; 948 default: 949 mouse_cut_extend(cur_scp); 950 break; 951 } 952 break; 953 } 954 #endif /* SC_NO_CUTPASTE */ 955 break; 956 957 default: 958 return EINVAL; 959 } 960 961 return 0; 962 } 963 964 /* MOUSE_XXX: /dev/sysmouse ioctls */ 965 case MOUSE_GETHWINFO: /* get device information */ 966 { 967 mousehw_t *hw = (mousehw_t *)data; 968 969 if (tp != sc_get_mouse_tty()) 970 return ENOTTY; 971 hw->buttons = 10; /* XXX unknown */ 972 hw->iftype = MOUSE_IF_SYSMOUSE; 973 hw->type = MOUSE_MOUSE; 974 hw->model = MOUSE_MODEL_GENERIC; 975 hw->hwid = 0; 976 return 0; 977 } 978 979 case MOUSE_GETMODE: /* get protocol/mode */ 980 { 981 mousemode_t *mode = (mousemode_t *)data; 982 983 if (tp != sc_get_mouse_tty()) 984 return ENOTTY; 985 mode->level = mouse_level; 986 switch (mode->level) { 987 case 0: 988 /* at this level, sysmouse emulates MouseSystems protocol */ 989 mode->protocol = MOUSE_PROTO_MSC; 990 mode->rate = -1; /* unknown */ 991 mode->resolution = -1; /* unknown */ 992 mode->accelfactor = 0; /* disabled */ 993 mode->packetsize = MOUSE_MSC_PACKETSIZE; 994 mode->syncmask[0] = MOUSE_MSC_SYNCMASK; 995 mode->syncmask[1] = MOUSE_MSC_SYNC; 996 break; 997 998 case 1: 999 /* at this level, sysmouse uses its own protocol */ 1000 mode->protocol = MOUSE_PROTO_SYSMOUSE; 1001 mode->rate = -1; 1002 mode->resolution = -1; 1003 mode->accelfactor = 0; 1004 mode->packetsize = MOUSE_SYS_PACKETSIZE; 1005 mode->syncmask[0] = MOUSE_SYS_SYNCMASK; 1006 mode->syncmask[1] = MOUSE_SYS_SYNC; 1007 break; 1008 } 1009 return 0; 1010 } 1011 1012 case MOUSE_SETMODE: /* set protocol/mode */ 1013 { 1014 mousemode_t *mode = (mousemode_t *)data; 1015 1016 if (tp != sc_get_mouse_tty()) 1017 return ENOTTY; 1018 if ((mode->level < 0) || (mode->level > 1)) 1019 return EINVAL; 1020 sc_mouse_set_level(mode->level); 1021 return 0; 1022 } 1023 1024 case MOUSE_GETLEVEL: /* get operation level */ 1025 if (tp != sc_get_mouse_tty()) 1026 return ENOTTY; 1027 *(int *)data = mouse_level; 1028 return 0; 1029 1030 case MOUSE_SETLEVEL: /* set operation level */ 1031 if (tp != sc_get_mouse_tty()) 1032 return ENOTTY; 1033 if ((*(int *)data < 0) || (*(int *)data > 1)) 1034 return EINVAL; 1035 sc_mouse_set_level(*(int *)data); 1036 return 0; 1037 1038 case MOUSE_GETSTATUS: /* get accumulated mouse events */ 1039 if (tp != sc_get_mouse_tty()) 1040 return ENOTTY; 1041 s = spltty(); 1042 *(mousestatus_t *)data = mouse_status; 1043 mouse_status.flags = 0; 1044 mouse_status.obutton = mouse_status.button; 1045 mouse_status.dx = 0; 1046 mouse_status.dy = 0; 1047 mouse_status.dz = 0; 1048 splx(s); 1049 return 0; 1050 1051 #if notyet 1052 case MOUSE_GETVARS: /* get internal mouse variables */ 1053 case MOUSE_SETVARS: /* set internal mouse variables */ 1054 if (tp != sc_get_mouse_tty()) 1055 return ENOTTY; 1056 return ENODEV; 1057 #endif 1058 1059 case MOUSE_READSTATE: /* read status from the device */ 1060 case MOUSE_READDATA: /* read data from the device */ 1061 if (tp != sc_get_mouse_tty()) 1062 return ENOTTY; 1063 return ENODEV; 1064 } 1065 1066 return ENOIOCTL; 1067 } 1068 1069 #endif /* SC_NO_SYSMOUSE */ 1070 1071 #endif /* NSC */ 1072