1 /* 2 SDL - Simple DirectMedia Layer 3 Copyright (C) 1997-2006 Sam Lantinga 4 5 This library is free software; you can redistribute it and/or 6 modify it under the terms of the GNU Lesser General Public 7 License as published by the Free Software Foundation; either 8 version 2.1 of the License, or (at your option) any later version. 9 10 This library is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General Public 16 License along with this library; if not, write to the Free Software 17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 19 Sam Lantinga 20 slouken (at) libsdl.org 21 */ 22 #include "SDL_config.h" 23 24 /* Handle the event stream, converting console events into SDL events */ 25 26 #include <sys/types.h> 27 #include <sys/time.h> 28 #include <sys/ioctl.h> 29 #include <unistd.h> 30 #include <fcntl.h> 31 #include <errno.h> 32 #include <limits.h> 33 34 /* For parsing /proc */ 35 #include <dirent.h> 36 #include <ctype.h> 37 38 #include <linux/vt.h> 39 #include <linux/kd.h> 40 #include <linux/keyboard.h> 41 42 #include "SDL_mutex.h" 43 #include "../SDL_sysvideo.h" 44 #include "../../events/SDL_sysevents.h" 45 #include "../../events/SDL_events_c.h" 46 #include "SDL_gsvideo.h" 47 #include "SDL_gsevents_c.h" 48 #include "SDL_gskeys.h" 49 50 #ifndef GPM_NODE_FIFO 51 #define GPM_NODE_FIFO "/dev/gpmdata" 52 #endif 53 54 /* The translation tables from a console scancode to a SDL keysym */ 55 #define NUM_VGAKEYMAPS (1<<KG_CAPSSHIFT) 56 static Uint16 vga_keymap[NUM_VGAKEYMAPS][NR_KEYS]; 57 static SDLKey keymap[128]; 58 static Uint16 keymap_temp[128]; /* only used at startup */ 59 static SDL_keysym *TranslateKey(int scancode, SDL_keysym *keysym); 60 61 /* Ugh, we have to duplicate the kernel's keysym mapping code... 62 Oh, it's not so bad. :-) 63 64 FIXME: Add keyboard LED handling code 65 */ 66 static void GS_vgainitkeymaps(int fd) 67 { 68 struct kbentry entry; 69 int map, i; 70 71 /* Don't do anything if we are passed a closed keyboard */ 72 if ( fd < 0 ) { 73 return; 74 } 75 76 /* Load all the keysym mappings */ 77 for ( map=0; map<NUM_VGAKEYMAPS; ++map ) { 78 SDL_memset(vga_keymap[map], 0, NR_KEYS*sizeof(Uint16)); 79 for ( i=0; i<NR_KEYS; ++i ) { 80 entry.kb_table = map; 81 entry.kb_index = i; 82 if ( ioctl(fd, KDGKBENT, &entry) == 0 ) { 83 /* fill keytemp. This replaces SDL_fbkeys.h */ 84 if ( (map == 0) && (i<128) ) { 85 keymap_temp[i] = entry.kb_value; 86 } 87 /* The "Enter" key is a special case */ 88 if ( entry.kb_value == K_ENTER ) { 89 entry.kb_value = K(KT_ASCII,13); 90 } 91 /* Handle numpad specially as well */ 92 if ( KTYP(entry.kb_value) == KT_PAD ) { 93 switch ( entry.kb_value ) { 94 case K_P0: 95 case K_P1: 96 case K_P2: 97 case K_P3: 98 case K_P4: 99 case K_P5: 100 case K_P6: 101 case K_P7: 102 case K_P8: 103 case K_P9: 104 vga_keymap[map][i]=entry.kb_value; 105 vga_keymap[map][i]+= '0'; 106 break; 107 case K_PPLUS: 108 vga_keymap[map][i]=K(KT_ASCII,'+'); 109 break; 110 case K_PMINUS: 111 vga_keymap[map][i]=K(KT_ASCII,'-'); 112 break; 113 case K_PSTAR: 114 vga_keymap[map][i]=K(KT_ASCII,'*'); 115 break; 116 case K_PSLASH: 117 vga_keymap[map][i]=K(KT_ASCII,'/'); 118 break; 119 case K_PENTER: 120 vga_keymap[map][i]=K(KT_ASCII,'\r'); 121 break; 122 case K_PCOMMA: 123 vga_keymap[map][i]=K(KT_ASCII,','); 124 break; 125 case K_PDOT: 126 vga_keymap[map][i]=K(KT_ASCII,'.'); 127 break; 128 default: 129 break; 130 } 131 } 132 /* Do the normal key translation */ 133 if ( (KTYP(entry.kb_value) == KT_LATIN) || 134 (KTYP(entry.kb_value) == KT_ASCII) || 135 (KTYP(entry.kb_value) == KT_LETTER) ) { 136 vga_keymap[map][i] = entry.kb_value; 137 } 138 } 139 } 140 } 141 } 142 143 int GS_InGraphicsMode(_THIS) 144 { 145 return((keyboard_fd >= 0) && (saved_kbd_mode >= 0)); 146 } 147 148 int GS_EnterGraphicsMode(_THIS) 149 { 150 struct termios keyboard_termios; 151 152 /* Set medium-raw keyboard mode */ 153 if ( (keyboard_fd >= 0) && !GS_InGraphicsMode(this) ) { 154 155 /* Switch to the correct virtual terminal */ 156 if ( current_vt > 0 ) { 157 struct vt_stat vtstate; 158 159 if ( ioctl(keyboard_fd, VT_GETSTATE, &vtstate) == 0 ) { 160 saved_vt = vtstate.v_active; 161 } 162 if ( ioctl(keyboard_fd, VT_ACTIVATE, current_vt) == 0 ) { 163 ioctl(keyboard_fd, VT_WAITACTIVE, current_vt); 164 } 165 } 166 167 /* Set the terminal input mode */ 168 if ( tcgetattr(keyboard_fd, &saved_kbd_termios) < 0 ) { 169 SDL_SetError("Unable to get terminal attributes"); 170 if ( keyboard_fd > 0 ) { 171 close(keyboard_fd); 172 } 173 keyboard_fd = -1; 174 return(-1); 175 } 176 if ( ioctl(keyboard_fd, KDGKBMODE, &saved_kbd_mode) < 0 ) { 177 SDL_SetError("Unable to get current keyboard mode"); 178 if ( keyboard_fd > 0 ) { 179 close(keyboard_fd); 180 } 181 keyboard_fd = -1; 182 return(-1); 183 } 184 keyboard_termios = saved_kbd_termios; 185 keyboard_termios.c_lflag &= ~(ICANON | ECHO | ISIG); 186 keyboard_termios.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON); 187 keyboard_termios.c_cc[VMIN] = 0; 188 keyboard_termios.c_cc[VTIME] = 0; 189 if (tcsetattr(keyboard_fd, TCSAFLUSH, &keyboard_termios) < 0) { 190 GS_CloseKeyboard(this); 191 SDL_SetError("Unable to set terminal attributes"); 192 return(-1); 193 } 194 /* This will fail if we aren't root or this isn't our tty */ 195 if ( ioctl(keyboard_fd, KDSKBMODE, K_MEDIUMRAW) < 0 ) { 196 GS_CloseKeyboard(this); 197 SDL_SetError("Unable to set keyboard in raw mode"); 198 return(-1); 199 } 200 if ( ioctl(keyboard_fd, KDSETMODE, KD_GRAPHICS) < 0 ) { 201 GS_CloseKeyboard(this); 202 SDL_SetError("Unable to set keyboard in graphics mode"); 203 return(-1); 204 } 205 } 206 return(keyboard_fd); 207 } 208 209 void GS_LeaveGraphicsMode(_THIS) 210 { 211 if ( GS_InGraphicsMode(this) ) { 212 ioctl(keyboard_fd, KDSETMODE, KD_TEXT); 213 ioctl(keyboard_fd, KDSKBMODE, saved_kbd_mode); 214 tcsetattr(keyboard_fd, TCSAFLUSH, &saved_kbd_termios); 215 saved_kbd_mode = -1; 216 217 /* Head back over to the original virtual terminal */ 218 if ( saved_vt > 0 ) { 219 ioctl(keyboard_fd, VT_ACTIVATE, saved_vt); 220 } 221 } 222 } 223 224 void GS_CloseKeyboard(_THIS) 225 { 226 if ( keyboard_fd >= 0 ) { 227 GS_LeaveGraphicsMode(this); 228 if ( keyboard_fd > 0 ) { 229 close(keyboard_fd); 230 } 231 } 232 keyboard_fd = -1; 233 } 234 235 int GS_OpenKeyboard(_THIS) 236 { 237 /* Open only if not already opened */ 238 if ( keyboard_fd < 0 ) { 239 char *tty0[] = { "/dev/tty0", "/dev/vc/0", NULL }; 240 char *vcs[] = { "/dev/vc/%d", "/dev/tty%d", NULL }; 241 int i, tty0_fd; 242 243 /* Try to query for a free virtual terminal */ 244 tty0_fd = -1; 245 for ( i=0; tty0[i] && (tty0_fd < 0); ++i ) { 246 tty0_fd = open(tty0[i], O_WRONLY, 0); 247 } 248 if ( tty0_fd < 0 ) { 249 tty0_fd = dup(0); /* Maybe stdin is a VT? */ 250 } 251 ioctl(tty0_fd, VT_OPENQRY, ¤t_vt); 252 close(tty0_fd); 253 if ( (geteuid() == 0) && (current_vt > 0) ) { 254 for ( i=0; vcs[i] && (keyboard_fd < 0); ++i ) { 255 char vtpath[12]; 256 257 SDL_snprintf(vtpath, SDL_arraysize(vtpath), vcs[i], current_vt); 258 keyboard_fd = open(vtpath, O_RDWR, 0); 259 #ifdef DEBUG_KEYBOARD 260 fprintf(stderr, "vtpath = %s, fd = %d\n", 261 vtpath, keyboard_fd); 262 #endif /* DEBUG_KEYBOARD */ 263 264 /* This needs to be our controlling tty 265 so that the kernel ioctl() calls work 266 */ 267 if ( keyboard_fd >= 0 ) { 268 tty0_fd = open("/dev/tty", O_RDWR, 0); 269 if ( tty0_fd >= 0 ) { 270 ioctl(tty0_fd, TIOCNOTTY, 0); 271 close(tty0_fd); 272 } 273 } 274 } 275 } 276 if ( keyboard_fd < 0 ) { 277 /* Last resort, maybe our tty is a usable VT */ 278 current_vt = 0; 279 keyboard_fd = open("/dev/tty", O_RDWR); 280 } 281 #ifdef DEBUG_KEYBOARD 282 fprintf(stderr, "Current VT: %d\n", current_vt); 283 #endif 284 saved_kbd_mode = -1; 285 286 /* Make sure that our input is a console terminal */ 287 { int dummy; 288 if ( ioctl(keyboard_fd, KDGKBMODE, &dummy) < 0 ) { 289 close(keyboard_fd); 290 keyboard_fd = -1; 291 SDL_SetError("Unable to open a console terminal"); 292 } 293 } 294 295 /* Set up keymap */ 296 GS_vgainitkeymaps(keyboard_fd); 297 } 298 return(keyboard_fd); 299 } 300 301 static enum { 302 MOUSE_NONE = -1, 303 MOUSE_GPM, /* Note: GPM uses the MSC protocol */ 304 MOUSE_PS2, 305 MOUSE_IMPS2, 306 MOUSE_MS, 307 MOUSE_BM, 308 NUM_MOUSE_DRVS 309 } mouse_drv = MOUSE_NONE; 310 311 void GS_CloseMouse(_THIS) 312 { 313 if ( mouse_fd > 0 ) { 314 close(mouse_fd); 315 } 316 mouse_fd = -1; 317 } 318 319 /* Returns processes listed in /proc with the desired name */ 320 static int find_pid(DIR *proc, const char *wanted_name) 321 { 322 struct dirent *entry; 323 int pid; 324 325 /* First scan proc for the gpm process */ 326 pid = 0; 327 while ( (pid == 0) && ((entry=readdir(proc)) != NULL) ) { 328 if ( isdigit(entry->d_name[0]) ) { 329 FILE *status; 330 char path[PATH_MAX]; 331 char name[PATH_MAX]; 332 333 SDL_snprintf(path, SDL_arraysize(path), "/proc/%s/status", entry->d_name); 334 status=fopen(path, "r"); 335 if ( status ) { 336 name[0] = '\0'; 337 fscanf(status, "Name: %s", name); 338 if ( SDL_strcmp(name, wanted_name) == 0 ) { 339 pid = atoi(entry->d_name); 340 } 341 fclose(status); 342 } 343 } 344 } 345 return pid; 346 } 347 348 /* Returns true if /dev/gpmdata is being written to by gpm */ 349 static int gpm_available(void) 350 { 351 int available; 352 DIR *proc; 353 int pid; 354 int cmdline, len, arglen; 355 char path[PATH_MAX]; 356 char args[PATH_MAX], *arg; 357 358 /* Don't bother looking if the fifo isn't there */ 359 if ( access(GPM_NODE_FIFO, F_OK) < 0 ) { 360 return(0); 361 } 362 363 available = 0; 364 proc = opendir("/proc"); 365 if ( proc ) { 366 while ( (pid=find_pid(proc, "gpm")) > 0 ) { 367 SDL_snprintf(path, SDL_arraysize(path), "/proc/%d/cmdline", pid); 368 cmdline = open(path, O_RDONLY, 0); 369 if ( cmdline >= 0 ) { 370 len = read(cmdline, args, sizeof(args)); 371 arg = args; 372 while ( len > 0 ) { 373 if ( SDL_strcmp(arg, "-R") == 0 ) { 374 available = 1; 375 } 376 arglen = SDL_strlen(arg)+1; 377 len -= arglen; 378 arg += arglen; 379 } 380 close(cmdline); 381 } 382 } 383 closedir(proc); 384 } 385 return available; 386 } 387 388 389 /* rcg06112001 Set up IMPS/2 mode, if possible. This gives 390 * us access to the mousewheel, etc. Returns zero if 391 * writes to device failed, but you still need to query the 392 * device to see which mode it's actually in. 393 */ 394 static int set_imps2_mode(int fd) 395 { 396 /* If you wanted to control the mouse mode (and we do :) ) ... 397 Set IMPS/2 protocol: 398 {0xf3,200,0xf3,100,0xf3,80} 399 Reset mouse device: 400 {0xFF} 401 */ 402 Uint8 set_imps2[] = {0xf3, 200, 0xf3, 100, 0xf3, 80}; 403 Uint8 reset = 0xff; 404 fd_set fdset; 405 struct timeval tv; 406 int retval = 0; 407 408 if ( write(fd, &set_imps2, sizeof(set_imps2)) == sizeof(set_imps2) ) { 409 if (write(fd, &reset, sizeof (reset)) == sizeof (reset) ) { 410 retval = 1; 411 } 412 } 413 414 /* Get rid of any chatter from the above */ 415 FD_ZERO(&fdset); 416 FD_SET(fd, &fdset); 417 tv.tv_sec = 0; 418 tv.tv_usec = 0; 419 while ( select(fd+1, &fdset, 0, 0, &tv) > 0 ) { 420 char temp[32]; 421 read(fd, temp, sizeof(temp)); 422 } 423 424 return retval; 425 } 426 427 428 /* Returns true if the mouse uses the IMPS/2 protocol */ 429 static int detect_imps2(int fd) 430 { 431 int imps2; 432 433 imps2 = 0; 434 435 if ( SDL_getenv("SDL_MOUSEDEV_IMPS2") ) { 436 imps2 = 1; 437 } 438 if ( ! imps2 ) { 439 Uint8 query_ps2 = 0xF2; 440 fd_set fdset; 441 struct timeval tv; 442 443 /* Get rid of any mouse motion noise */ 444 FD_ZERO(&fdset); 445 FD_SET(fd, &fdset); 446 tv.tv_sec = 0; 447 tv.tv_usec = 0; 448 while ( select(fd+1, &fdset, 0, 0, &tv) > 0 ) { 449 char temp[32]; 450 read(fd, temp, sizeof(temp)); 451 } 452 453 /* Query for the type of mouse protocol */ 454 if ( write(fd, &query_ps2, sizeof (query_ps2)) == sizeof (query_ps2)) { 455 Uint8 ch = 0; 456 457 /* Get the mouse protocol response */ 458 do { 459 FD_ZERO(&fdset); 460 FD_SET(fd, &fdset); 461 tv.tv_sec = 1; 462 tv.tv_usec = 0; 463 if ( select(fd+1, &fdset, 0, 0, &tv) < 1 ) { 464 break; 465 } 466 } while ( (read(fd, &ch, sizeof (ch)) == sizeof (ch)) && 467 ((ch == 0xFA) || (ch == 0xAA)) ); 468 469 /* Experimental values (Logitech wheelmouse) */ 470 #ifdef DEBUG_MOUSE 471 fprintf(stderr, "Last mouse mode: 0x%x\n", ch); 472 #endif 473 if ( ch == 3 ) { 474 imps2 = 1; 475 } 476 } 477 } 478 return imps2; 479 } 480 481 int GS_OpenMouse(_THIS) 482 { 483 int i; 484 const char *mousedev; 485 const char *mousedrv; 486 487 mousedrv = SDL_getenv("SDL_MOUSEDRV"); 488 mousedev = SDL_getenv("SDL_MOUSEDEV"); 489 mouse_fd = -1; 490 491 /* STD MICE */ 492 493 if ( mousedev == NULL ) { 494 /* FIXME someday... allow multiple mice in this driver */ 495 char *ps2mice[] = { 496 "/dev/input/mice", "/dev/usbmouse", "/dev/psaux", NULL 497 }; 498 /* First try to use GPM in repeater mode */ 499 if ( mouse_fd < 0 ) { 500 if ( gpm_available() ) { 501 mouse_fd = open(GPM_NODE_FIFO, O_RDONLY, 0); 502 if ( mouse_fd >= 0 ) { 503 #ifdef DEBUG_MOUSE 504 fprintf(stderr, "Using GPM mouse\n"); 505 #endif 506 mouse_drv = MOUSE_GPM; 507 } 508 } 509 } 510 /* Now try to use a modern PS/2 mouse */ 511 for ( i=0; (mouse_fd < 0) && ps2mice[i]; ++i ) { 512 mouse_fd = open(ps2mice[i], O_RDWR, 0); 513 if (mouse_fd < 0) { 514 mouse_fd = open(ps2mice[i], O_RDONLY, 0); 515 } 516 if (mouse_fd >= 0) { 517 /* rcg06112001 Attempt to set IMPS/2 mode */ 518 if ( i == 0 ) { 519 set_imps2_mode(mouse_fd); 520 } 521 if (detect_imps2(mouse_fd)) { 522 #ifdef DEBUG_MOUSE 523 fprintf(stderr, "Using IMPS2 mouse\n"); 524 #endif 525 mouse_drv = MOUSE_IMPS2; 526 } else { 527 mouse_drv = MOUSE_PS2; 528 #ifdef DEBUG_MOUSE 529 fprintf(stderr, "Using PS2 mouse\n"); 530 #endif 531 } 532 } 533 } 534 /* Next try to use a PPC ADB port mouse */ 535 if ( mouse_fd < 0 ) { 536 mouse_fd = open("/dev/adbmouse", O_RDONLY, 0); 537 if ( mouse_fd >= 0 ) { 538 #ifdef DEBUG_MOUSE 539 fprintf(stderr, "Using ADB mouse\n"); 540 #endif 541 mouse_drv = MOUSE_BM; 542 } 543 } 544 } 545 /* Default to a serial Microsoft mouse */ 546 if ( mouse_fd < 0 ) { 547 if ( mousedev == NULL ) { 548 mousedev = "/dev/mouse"; 549 } 550 mouse_fd = open(mousedev, O_RDONLY, 0); 551 if ( mouse_fd >= 0 ) { 552 struct termios mouse_termios; 553 554 /* Set the sampling speed to 1200 baud */ 555 tcgetattr(mouse_fd, &mouse_termios); 556 mouse_termios.c_iflag = IGNBRK | IGNPAR; 557 mouse_termios.c_oflag = 0; 558 mouse_termios.c_lflag = 0; 559 mouse_termios.c_line = 0; 560 mouse_termios.c_cc[VTIME] = 0; 561 mouse_termios.c_cc[VMIN] = 1; 562 mouse_termios.c_cflag = CREAD | CLOCAL | HUPCL; 563 mouse_termios.c_cflag |= CS8; 564 mouse_termios.c_cflag |= B1200; 565 tcsetattr(mouse_fd, TCSAFLUSH, &mouse_termios); 566 #ifdef DEBUG_MOUSE 567 fprintf(stderr, "Using Microsoft mouse on %s\n", mousedev); 568 #endif 569 mouse_drv = MOUSE_MS; 570 } 571 } 572 if ( mouse_fd < 0 ) { 573 mouse_drv = MOUSE_NONE; 574 } 575 return(mouse_fd); 576 } 577 578 static int posted = 0; 579 580 void GS_vgamousecallback(int button, int dx, int dy) 581 { 582 int button_1, button_3; 583 int button_state; 584 int state_changed; 585 int i; 586 Uint8 state; 587 588 if ( dx || dy ) { 589 posted += SDL_PrivateMouseMotion(0, 1, dx, dy); 590 } 591 592 /* Swap button 1 and 3 */ 593 button_1 = (button & 0x04) >> 2; 594 button_3 = (button & 0x01) << 2; 595 button &= ~0x05; 596 button |= (button_1|button_3); 597 598 /* See what changed */ 599 button_state = SDL_GetMouseState(NULL, NULL); 600 state_changed = button_state ^ button; 601 for ( i=0; i<8; ++i ) { 602 if ( state_changed & (1<<i) ) { 603 if ( button & (1<<i) ) { 604 state = SDL_PRESSED; 605 } else { 606 state = SDL_RELEASED; 607 } 608 posted += SDL_PrivateMouseButton(state, i+1, 0, 0); 609 } 610 } 611 } 612 613 /* For now, use GPM, PS/2, and MS protocols 614 Driver adapted from the SVGAlib mouse driver code (taken from gpm, etc.) 615 */ 616 static void handle_mouse(_THIS) 617 { 618 static int start = 0; 619 static unsigned char mousebuf[BUFSIZ]; 620 int i, nread; 621 int button = 0; 622 int dx = 0, dy = 0; 623 int packetsize = 0; 624 625 /* Figure out the mouse packet size */ 626 switch (mouse_drv) { 627 case MOUSE_NONE: 628 /* Ack! */ 629 read(mouse_fd, mousebuf, BUFSIZ); 630 return; 631 case MOUSE_GPM: 632 packetsize = 5; 633 break; 634 case MOUSE_IMPS2: 635 packetsize = 4; 636 break; 637 case MOUSE_PS2: 638 case MOUSE_MS: 639 case MOUSE_BM: 640 packetsize = 3; 641 break; 642 case NUM_MOUSE_DRVS: 643 /* Uh oh.. */ 644 packetsize = 0; 645 break; 646 } 647 648 /* Read as many packets as possible */ 649 nread = read(mouse_fd, &mousebuf[start], BUFSIZ-start); 650 if ( nread < 0 ) { 651 return; 652 } 653 nread += start; 654 #ifdef DEBUG_MOUSE 655 fprintf(stderr, "Read %d bytes from mouse, start = %d\n", nread, start); 656 #endif 657 for ( i=0; i<(nread-(packetsize-1)); i += packetsize ) { 658 switch (mouse_drv) { 659 case MOUSE_NONE: 660 break; 661 case MOUSE_GPM: 662 /* GPM protocol has 0x80 in high byte */ 663 if ( (mousebuf[i] & 0xF8) != 0x80 ) { 664 /* Go to next byte */ 665 i -= (packetsize-1); 666 continue; 667 } 668 /* Get current mouse state */ 669 button = (~mousebuf[i]) & 0x07; 670 dx = (signed char)(mousebuf[i+1]) + 671 (signed char)(mousebuf[i+3]); 672 dy = -((signed char)(mousebuf[i+2]) + 673 (signed char)(mousebuf[i+4])); 674 break; 675 case MOUSE_PS2: 676 /* PS/2 protocol has nothing in high byte */ 677 if ( (mousebuf[i] & 0xC0) != 0 ) { 678 /* Go to next byte */ 679 i -= (packetsize-1); 680 continue; 681 } 682 /* Get current mouse state */ 683 button = (mousebuf[i] & 0x04) >> 1 | /*Middle*/ 684 (mousebuf[i] & 0x02) >> 1 | /*Right*/ 685 (mousebuf[i] & 0x01) << 2; /*Left*/ 686 dx = (mousebuf[i] & 0x10) ? 687 mousebuf[i+1] - 256 : mousebuf[i+1]; 688 dy = (mousebuf[i] & 0x20) ? 689 -(mousebuf[i+2] - 256) : -mousebuf[i+2]; 690 break; 691 case MOUSE_IMPS2: 692 /* Get current mouse state */ 693 button = (mousebuf[i] & 0x04) >> 1 | /*Middle*/ 694 (mousebuf[i] & 0x02) >> 1 | /*Right*/ 695 (mousebuf[i] & 0x01) << 2 | /*Left*/ 696 (mousebuf[i] & 0x40) >> 3 | /* 4 */ 697 (mousebuf[i] & 0x80) >> 3; /* 5 */ 698 dx = (mousebuf[i] & 0x10) ? 699 mousebuf[i+1] - 256 : mousebuf[i+1]; 700 dy = (mousebuf[i] & 0x20) ? 701 -(mousebuf[i+2] - 256) : -mousebuf[i+2]; 702 switch (mousebuf[i+3]&0x0F) { 703 case 0x0E: /* DX = +1 */ 704 case 0x02: /* DX = -1 */ 705 break; 706 case 0x0F: /* DY = +1 (map button 4) */ 707 FB_vgamousecallback(button | (1<<3), 708 1, 0, 0); 709 break; 710 case 0x01: /* DY = -1 (map button 5) */ 711 FB_vgamousecallback(button | (1<<4), 712 1, 0, 0); 713 break; 714 } 715 break; 716 case MOUSE_MS: 717 /* Microsoft protocol has 0x40 in high byte */ 718 if ( (mousebuf[i] & 0x40) != 0x40 ) { 719 /* Go to next byte */ 720 i -= (packetsize-1); 721 continue; 722 } 723 /* Get current mouse state */ 724 button = ((mousebuf[i] & 0x20) >> 3) | 725 ((mousebuf[i] & 0x10) >> 4); 726 dx = (signed char)(((mousebuf[i] & 0x03) << 6) | 727 (mousebuf[i + 1] & 0x3F)); 728 dy = (signed char)(((mousebuf[i] & 0x0C) << 4) | 729 (mousebuf[i + 2] & 0x3F)); 730 break; 731 case MOUSE_BM: 732 /* BusMouse protocol has 0xF8 in high byte */ 733 if ( (mousebuf[i] & 0xF8) != 0x80 ) { 734 /* Go to next byte */ 735 i -= (packetsize-1); 736 continue; 737 } 738 /* Get current mouse state */ 739 button = (~mousebuf[i]) & 0x07; 740 dx = (signed char)mousebuf[i+1]; 741 dy = -(signed char)mousebuf[i+2]; 742 break; 743 case NUM_MOUSE_DRVS: 744 /* Uh oh.. */ 745 dx = 0; 746 dy = 0; 747 break; 748 } 749 GS_vgamousecallback(button, dx, dy); 750 } 751 if ( i < nread ) { 752 SDL_memcpy(mousebuf, &mousebuf[i], (nread-i)); 753 start = (nread-i); 754 } else { 755 start = 0; 756 } 757 return; 758 } 759 760 static void handle_keyboard(_THIS) 761 { 762 unsigned char keybuf[BUFSIZ]; 763 int i, nread; 764 int pressed; 765 int scancode; 766 SDL_keysym keysym; 767 768 nread = read(keyboard_fd, keybuf, BUFSIZ); 769 for ( i=0; i<nread; ++i ) { 770 scancode = keybuf[i] & 0x7F; 771 if ( keybuf[i] & 0x80 ) { 772 pressed = SDL_RELEASED; 773 } else { 774 pressed = SDL_PRESSED; 775 } 776 TranslateKey(scancode, &keysym); 777 posted += SDL_PrivateKeyboard(pressed, &keysym); 778 } 779 } 780 781 void GS_PumpEvents(_THIS) 782 { 783 fd_set fdset; 784 int max_fd; 785 static struct timeval zero; 786 787 do { 788 posted = 0; 789 790 FD_ZERO(&fdset); 791 max_fd = 0; 792 if ( keyboard_fd >= 0 ) { 793 FD_SET(keyboard_fd, &fdset); 794 if ( max_fd < keyboard_fd ) { 795 max_fd = keyboard_fd; 796 } 797 } 798 if ( mouse_fd >= 0 ) { 799 FD_SET(mouse_fd, &fdset); 800 if ( max_fd < mouse_fd ) { 801 max_fd = mouse_fd; 802 } 803 } 804 if ( select(max_fd+1, &fdset, NULL, NULL, &zero) > 0 ) { 805 if ( keyboard_fd >= 0 ) { 806 if ( FD_ISSET(keyboard_fd, &fdset) ) { 807 handle_keyboard(this); 808 } 809 } 810 if ( mouse_fd >= 0 ) { 811 if ( FD_ISSET(mouse_fd, &fdset) ) { 812 handle_mouse(this); 813 } 814 } 815 } 816 } while ( posted ); 817 } 818 819 void GS_InitOSKeymap(_THIS) 820 { 821 int i; 822 823 /* Initialize the Linux key translation table */ 824 825 /* First get the ascii keys and others not well handled */ 826 for (i=0; i<SDL_arraysize(keymap); ++i) { 827 switch(i) { 828 /* These aren't handled by the x86 kernel keymapping (?) */ 829 case SCANCODE_PRINTSCREEN: 830 keymap[i] = SDLK_PRINT; 831 break; 832 case SCANCODE_BREAK: 833 keymap[i] = SDLK_BREAK; 834 break; 835 case SCANCODE_BREAK_ALTERNATIVE: 836 keymap[i] = SDLK_PAUSE; 837 break; 838 case SCANCODE_LEFTSHIFT: 839 keymap[i] = SDLK_LSHIFT; 840 break; 841 case SCANCODE_RIGHTSHIFT: 842 keymap[i] = SDLK_RSHIFT; 843 break; 844 case SCANCODE_LEFTCONTROL: 845 keymap[i] = SDLK_LCTRL; 846 break; 847 case SCANCODE_RIGHTCONTROL: 848 keymap[i] = SDLK_RCTRL; 849 break; 850 case SCANCODE_RIGHTWIN: 851 keymap[i] = SDLK_RSUPER; 852 break; 853 case SCANCODE_LEFTWIN: 854 keymap[i] = SDLK_LSUPER; 855 break; 856 case 127: 857 keymap[i] = SDLK_MENU; 858 break; 859 /* this should take care of all standard ascii keys */ 860 default: 861 keymap[i] = KVAL(vga_keymap[0][i]); 862 break; 863 } 864 } 865 for (i=0; i<SDL_arraysize(keymap); ++i) { 866 switch(keymap_temp[i]) { 867 case K_F1: keymap[i] = SDLK_F1; break; 868 case K_F2: keymap[i] = SDLK_F2; break; 869 case K_F3: keymap[i] = SDLK_F3; break; 870 case K_F4: keymap[i] = SDLK_F4; break; 871 case K_F5: keymap[i] = SDLK_F5; break; 872 case K_F6: keymap[i] = SDLK_F6; break; 873 case K_F7: keymap[i] = SDLK_F7; break; 874 case K_F8: keymap[i] = SDLK_F8; break; 875 case K_F9: keymap[i] = SDLK_F9; break; 876 case K_F10: keymap[i] = SDLK_F10; break; 877 case K_F11: keymap[i] = SDLK_F11; break; 878 case K_F12: keymap[i] = SDLK_F12; break; 879 880 case K_DOWN: keymap[i] = SDLK_DOWN; break; 881 case K_LEFT: keymap[i] = SDLK_LEFT; break; 882 case K_RIGHT: keymap[i] = SDLK_RIGHT; break; 883 case K_UP: keymap[i] = SDLK_UP; break; 884 885 case K_P0: keymap[i] = SDLK_KP0; break; 886 case K_P1: keymap[i] = SDLK_KP1; break; 887 case K_P2: keymap[i] = SDLK_KP2; break; 888 case K_P3: keymap[i] = SDLK_KP3; break; 889 case K_P4: keymap[i] = SDLK_KP4; break; 890 case K_P5: keymap[i] = SDLK_KP5; break; 891 case K_P6: keymap[i] = SDLK_KP6; break; 892 case K_P7: keymap[i] = SDLK_KP7; break; 893 case K_P8: keymap[i] = SDLK_KP8; break; 894 case K_P9: keymap[i] = SDLK_KP9; break; 895 case K_PPLUS: keymap[i] = SDLK_KP_PLUS; break; 896 case K_PMINUS: keymap[i] = SDLK_KP_MINUS; break; 897 case K_PSTAR: keymap[i] = SDLK_KP_MULTIPLY; break; 898 case K_PSLASH: keymap[i] = SDLK_KP_DIVIDE; break; 899 case K_PENTER: keymap[i] = SDLK_KP_ENTER; break; 900 case K_PDOT: keymap[i] = SDLK_KP_PERIOD; break; 901 902 case K_SHIFT: if ( keymap[i] != SDLK_RSHIFT ) 903 keymap[i] = SDLK_LSHIFT; 904 break; 905 case K_SHIFTL: keymap[i] = SDLK_LSHIFT; break; 906 case K_SHIFTR: keymap[i] = SDLK_RSHIFT; break; 907 case K_CTRL: if ( keymap[i] != SDLK_RCTRL ) 908 keymap[i] = SDLK_LCTRL; 909 break; 910 case K_CTRLL: keymap[i] = SDLK_LCTRL; break; 911 case K_CTRLR: keymap[i] = SDLK_RCTRL; break; 912 case K_ALT: keymap[i] = SDLK_LALT; break; 913 case K_ALTGR: keymap[i] = SDLK_RALT; break; 914 915 case K_INSERT: keymap[i] = SDLK_INSERT; break; 916 case K_REMOVE: keymap[i] = SDLK_DELETE; break; 917 case K_PGUP: keymap[i] = SDLK_PAGEUP; break; 918 case K_PGDN: keymap[i] = SDLK_PAGEDOWN; break; 919 case K_FIND: keymap[i] = SDLK_HOME; break; 920 case K_SELECT: keymap[i] = SDLK_END; break; 921 922 case K_NUM: keymap[i] = SDLK_NUMLOCK; break; 923 case K_CAPS: keymap[i] = SDLK_CAPSLOCK; break; 924 925 case K_F13: keymap[i] = SDLK_PRINT; break; 926 case K_HOLD: keymap[i] = SDLK_SCROLLOCK; break; 927 case K_PAUSE: keymap[i] = SDLK_PAUSE; break; 928 929 case 127: keymap[i] = SDLK_BACKSPACE; break; 930 931 default: break; 932 } 933 } 934 } 935 936 static SDL_keysym *TranslateKey(int scancode, SDL_keysym *keysym) 937 { 938 /* Set the keysym information */ 939 keysym->scancode = scancode; 940 keysym->sym = keymap[scancode]; 941 keysym->mod = KMOD_NONE; 942 943 /* If UNICODE is on, get the UNICODE value for the key */ 944 keysym->unicode = 0; 945 if ( SDL_TranslateUNICODE ) { 946 int map; 947 SDLMod modstate; 948 949 modstate = SDL_GetModState(); 950 map = 0; 951 if ( modstate & KMOD_SHIFT ) { 952 map |= (1<<KG_SHIFT); 953 } 954 if ( modstate & KMOD_CTRL ) { 955 map |= (1<<KG_CTRL); 956 } 957 if ( modstate & KMOD_ALT ) { 958 map |= (1<<KG_ALT); 959 } 960 if ( modstate & KMOD_MODE ) { 961 map |= (1<<KG_ALTGR); 962 } 963 if ( KTYP(vga_keymap[map][scancode]) == KT_LETTER ) { 964 if ( modstate & KMOD_CAPS ) { 965 map ^= (1<<KG_SHIFT); 966 } 967 } 968 if ( KTYP(vga_keymap[map][scancode]) == KT_PAD ) { 969 if ( modstate & KMOD_NUM ) { 970 keysym->unicode=KVAL(vga_keymap[map][scancode]); 971 } 972 } else { 973 keysym->unicode = KVAL(vga_keymap[map][scancode]); 974 } 975 } 976 return(keysym); 977 } 978