/* Public Domain Curses */ #if defined(__EMX__) || defined(__WATCOMC__) || defined(__IBMC__) || \ defined(__TURBOC__) # define HAVE_SIGNAL # include <signal.h> #endif #include "pdcos2.h" RCSID("$Id: pdckbd.c,v 1.89 2008/07/14 04:24:51 wmcbrine Exp $") /*man-start************************************************************** Name: pdckbd Synopsis: unsigned long PDC_get_input_fd(void); Description: PDC_get_input_fd() returns the file descriptor that PDCurses reads its input from. It can be used for select(). Portability X/Open BSD SYS V PDC_get_input_fd - - - **man-end****************************************************************/ #ifdef EMXVIDEO # include <termios.h> static int tahead = -1; #else static KBDINFO kbdinfo; /* default keyboard mode */ static HMOU mouse_handle = 0; static MOUSE_STATUS old_mouse_status; static USHORT old_shift = 0; static bool key_pressed = FALSE; static int mouse_events = 0; #endif /************************************************************************ * Table for key code translation of function keys in keypad mode * * These values are for strict IBM keyboard compatibles only * ************************************************************************/ static short key_table[] = { -1, ALT_ESC, -1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ALT_BKSP, KEY_BTAB, ALT_Q, ALT_W, ALT_E, ALT_R, ALT_T, ALT_Y, ALT_U, ALT_I, ALT_O, ALT_P, ALT_LBRACKET, ALT_RBRACKET, ALT_ENTER, -1, ALT_A, ALT_S, ALT_D, ALT_F, ALT_G, ALT_H, ALT_J, ALT_K, ALT_L, ALT_SEMICOLON, ALT_FQUOTE, ALT_BQUOTE, -1, ALT_BSLASH, ALT_Z, ALT_X, ALT_C, ALT_V, ALT_B, ALT_N, ALT_M, ALT_COMMA, ALT_STOP, ALT_FSLASH, -1, ALT_PADSTAR, -1, -1, -1, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5), KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), -1, -1, KEY_HOME, KEY_UP, KEY_PPAGE, ALT_PADMINUS, KEY_LEFT, KEY_B2, KEY_RIGHT, ALT_PADPLUS, KEY_END, KEY_DOWN, KEY_NPAGE, KEY_IC, KEY_DC, KEY_F(13), KEY_F(14), KEY_F(15), KEY_F(16), KEY_F(17), KEY_F(18), KEY_F(19), KEY_F(20), KEY_F(21), KEY_F(22), KEY_F(25), KEY_F(26), KEY_F(27), KEY_F(28), KEY_F(29), KEY_F(30), KEY_F(31), KEY_F(32), KEY_F(33), KEY_F(34), KEY_F(37), KEY_F(38), KEY_F(39), KEY_F(40), KEY_F(41), KEY_F(42), KEY_F(43), KEY_F(44), KEY_F(45), KEY_F(46), -1, CTL_LEFT, CTL_RIGHT, CTL_END, CTL_PGDN, CTL_HOME, ALT_1, ALT_2, ALT_3, ALT_4, ALT_5, ALT_6, ALT_7, ALT_8, ALT_9, ALT_0, ALT_MINUS, ALT_EQUAL, CTL_PGUP, KEY_F(11), KEY_F(12), KEY_F(23), KEY_F(24), KEY_F(35), KEY_F(36), KEY_F(47), KEY_F(48), CTL_UP, CTL_PADMINUS, CTL_PADCENTER, CTL_PADPLUS, CTL_DOWN, CTL_INS, CTL_DEL, CTL_TAB, CTL_PADSLASH, CTL_PADSTAR, ALT_HOME, ALT_UP, ALT_PGUP, -1, ALT_LEFT, -1, ALT_RIGHT, -1, ALT_END, ALT_DOWN, ALT_PGDN, ALT_INS, ALT_DEL, ALT_PADSLASH, ALT_TAB, ALT_PADENTER, -1 }; unsigned long pdc_key_modifiers = 0L; unsigned long PDC_get_input_fd(void) { PDC_LOG(("PDC_get_input_fd() - called\n")); return (unsigned long)fileno(stdin); } #ifndef EMXVIDEO void PDC_get_keyboard_info(void) { kbdinfo.cb = sizeof(kbdinfo); KbdGetStatus(&kbdinfo, 0); } void PDC_set_keyboard_default(void) { KbdSetStatus(&kbdinfo, 0); } #endif /* ifndef EMXVIDEO */ void PDC_set_keyboard_binary(bool on) { PDC_LOG(("PDC_set_keyboard_binary() - called\n")); #ifndef EMXVIDEO if (on) { kbdinfo.fsMask &= ~(KEYBOARD_ASCII_MODE); kbdinfo.fsMask |= KEYBOARD_BINARY_MODE; } else { kbdinfo.fsMask &= ~(KEYBOARD_BINARY_MODE); kbdinfo.fsMask |= KEYBOARD_ASCII_MODE; } KbdSetStatus(&kbdinfo, 0); #endif #ifdef HAVE_SIGNAL signal(SIGBREAK, on ? SIG_IGN : SIG_DFL); #endif } /* check if a key or mouse event is waiting */ bool PDC_check_key(void) { #if !defined(_MSC_VER) && !defined(EMXVIDEO) KBDKEYINFO keyInfo = {0}; #endif #ifdef EMXVIDEO if (tahead == -1) /* Nothing typed yet */ { tahead = _read_kbd(0, 0, 0); /* Read additional */ if (tahead == 0) tahead = _read_kbd(0, 1, 0) << 8; } return (tahead != -1); #else # ifndef _MSC_VER KbdGetStatus(&kbdinfo, 0); if (mouse_handle) { MOUQUEINFO queue; MouGetNumQueEl(&queue, mouse_handle); mouse_events = queue.cEvents; if (mouse_events) return TRUE; } if (old_shift && !kbdinfo.fsState) /* modifier released */ { if (!key_pressed && SP->return_key_modifiers) return TRUE; } else if (!old_shift && kbdinfo.fsState) /* modifier pressed */ key_pressed = FALSE; old_shift = kbdinfo.fsState; KbdPeek(&keyInfo, 0); /* peek at keyboard */ return (keyInfo.fbStatus != 0); # else return kbhit(); # endif #endif } #ifndef EMXVIDEO static int _process_mouse_events(void) { MOUEVENTINFO event; static const USHORT button_mask[] = {6, 96, 24}, move_mask[] = {2, 32, 8}, press_mask[] = {4, 64, 16}; USHORT count = 1; short shift_flags = 0; int i; MouReadEventQue(&event, &count, mouse_handle); mouse_events--; for (i = 0; i < 3; i++) { pdc_mouse_status.button[i] = ((event.fs & move_mask[i]) ? BUTTON_MOVED : 0) | ((event.fs & press_mask[i]) ? BUTTON_PRESSED : 0); /* PRESS events are sometimes mistakenly reported as MOVE events. A MOVE should always follow a PRESS, so treat a MOVE immediately after a RELEASE as a PRESS. */ if ((pdc_mouse_status.button[i] == BUTTON_MOVED) && (old_mouse_status.button[i] == BUTTON_RELEASED)) { pdc_mouse_status.button[i] = BUTTON_PRESSED; } if (pdc_mouse_status.button[i] == BUTTON_PRESSED && SP->mouse_wait) { /* Check for a click -- a PRESS followed immediately by a release */ if (!mouse_events) { MOUQUEINFO queue; napms(SP->mouse_wait); MouGetNumQueEl(&queue, mouse_handle); mouse_events = queue.cEvents; } if (mouse_events) { MouReadEventQue(&event, &count, mouse_handle); if (!(event.fs & button_mask[i])) pdc_mouse_status.button[i] = BUTTON_CLICKED; } } } pdc_mouse_status.x = event.col; pdc_mouse_status.y = event.row; pdc_mouse_status.changes = 0; for (i = 0; i < 3; i++) { if (old_mouse_status.button[i] != pdc_mouse_status.button[i]) pdc_mouse_status.changes |= (1 << i); if (pdc_mouse_status.button[i] == BUTTON_MOVED) { /* Discard non-moved "moves" */ if (pdc_mouse_status.x == old_mouse_status.x && pdc_mouse_status.y == old_mouse_status.y) return -1; /* Motion events always flag the button as changed */ pdc_mouse_status.changes |= (1 << i); pdc_mouse_status.changes |= PDC_MOUSE_MOVED; break; } } old_mouse_status = pdc_mouse_status; /* Treat click events as release events for comparison purposes */ for (i = 0; i < 3; i++) { if (old_mouse_status.button[i] == BUTTON_CLICKED) old_mouse_status.button[i] = BUTTON_RELEASED; } /* Check for SHIFT/CONTROL/ALT */ if (kbdinfo.fsState & KBDSTF_ALT) shift_flags |= BUTTON_ALT; if (kbdinfo.fsState & KBDSTF_CONTROL) shift_flags |= BUTTON_CONTROL; if (kbdinfo.fsState & (KBDSTF_LEFTSHIFT|KBDSTF_RIGHTSHIFT)) shift_flags |= BUTTON_SHIFT; if (shift_flags) { for (i = 0; i < 3; i++) { if (pdc_mouse_status.changes & (1 << i)) pdc_mouse_status.button[i] |= shift_flags; } } old_shift = kbdinfo.fsState; key_pressed = TRUE; SP->key_code = TRUE; return KEY_MOUSE; } #endif /* return the next available key or mouse event */ int PDC_get_key(void) { int key, scan; #ifndef EMXVIDEO KBDKEYINFO keyInfo = {0}; #endif #ifdef EMXVIDEO if (tahead == -1) { tahead = _read_kbd(0, 1, 0); /* Read additional */ if (tahead == 0) tahead = _read_kbd(0, 1, 0) << 8; } key = tahead & 0xff; scan = tahead >> 8; pdc_key_modifiers = 0L; tahead = -1; #else pdc_key_modifiers = 0L; if (mouse_handle && mouse_events) return _process_mouse_events(); if (old_shift && !kbdinfo.fsState) { key = -1; if (old_shift & KBDSTF_LEFTALT) { key = KEY_ALT_L; } else if (old_shift & KBDSTF_RIGHTALT) { key = KEY_ALT_R; } else if (old_shift & KBDSTF_LEFTCONTROL) { key = KEY_CONTROL_L; } else if (old_shift & KBDSTF_RIGHTCONTROL) { key = KEY_CONTROL_R; } else if (old_shift & KBDSTF_LEFTSHIFT) { key = KEY_SHIFT_L; } else if (old_shift & KBDSTF_RIGHTSHIFT) { key = KEY_SHIFT_R; } key_pressed = FALSE; old_shift = kbdinfo.fsState; SP->key_code = TRUE; return key; } KbdCharIn(&keyInfo, IO_WAIT, 0); /* get a character */ key = keyInfo.chChar; scan = keyInfo.chScan; if (SP->save_key_modifiers) { if (keyInfo.fsState & KBDSTF_ALT) pdc_key_modifiers |= PDC_KEY_MODIFIER_ALT; if (keyInfo.fsState & KBDSTF_CONTROL) pdc_key_modifiers |= PDC_KEY_MODIFIER_CONTROL; if (keyInfo.fsState & KBDSTF_NUMLOCK_ON) pdc_key_modifiers |= PDC_KEY_MODIFIER_NUMLOCK; if (keyInfo.fsState & (KBDSTF_LEFTSHIFT|KBDSTF_RIGHTSHIFT)) pdc_key_modifiers |= PDC_KEY_MODIFIER_SHIFT; } #endif if (scan == 0x1c && key == 0x0a) /* ^Enter */ key = CTL_ENTER; else if (scan == 0xe0 && key == 0x0d) /* PadEnter */ key = PADENTER; else if (scan == 0xe0 && key == 0x0a) /* ^PadEnter */ key = CTL_PADENTER; else if (scan == 0x37 && key == 0x2a) /* Star */ key = PADSTAR; else if (scan == 0x4a && key == 0x2d) /* Minus */ key = PADMINUS; else if (scan == 0x4e && key == 0x2b) /* Plus */ key = PADPLUS; else if (scan == 0xe0 && key == 0x2f) /* Slash */ key = PADSLASH; else if (key == 0x00 || (key == 0xe0 && scan > 53 && scan != 86)) key = (scan > 0xa7) ? -1 : key_table[scan]; if (keyInfo.fsState & (KBDSTF_LEFTSHIFT|KBDSTF_RIGHTSHIFT)) { switch (key) { case KEY_HOME: /* Shift Home */ key = KEY_SHOME; break; case KEY_UP: /* Shift Up */ key = KEY_SUP; break; case KEY_PPAGE: /* Shift PgUp */ key = KEY_SPREVIOUS; break; case KEY_LEFT: /* Shift Left */ key = KEY_SLEFT; break; case KEY_RIGHT: /* Shift Right */ key = KEY_SRIGHT; break; case KEY_END: /* Shift End */ key = KEY_SEND; break; case KEY_DOWN: /* Shift Down */ key = KEY_SDOWN; break; case KEY_NPAGE: /* Shift PgDn */ key = KEY_SNEXT; break; case KEY_IC: /* Shift Ins */ key = KEY_SIC; break; case KEY_DC: /* Shift Del */ key = KEY_SDC; } } key_pressed = TRUE; SP->key_code = ((unsigned)key >= 256); return key; } /* discard any pending keyboard or mouse input -- this is the core routine for flushinp() */ void PDC_flushinp(void) { PDC_LOG(("PDC_flushinp() - called\n")); #ifdef EMXVIDEO tcflush(0, TCIFLUSH); #else if (mouse_handle) MouFlushQue(mouse_handle); KbdFlushBuffer(0); #endif } int PDC_mouse_set(void) { #ifndef EMXVIDEO unsigned long mbe = SP->_trap_mbe; if (mbe && !mouse_handle) { memset(&old_mouse_status, 0, sizeof(MOUSE_STATUS)); MouOpen(NULL, &mouse_handle); if (mouse_handle) MouDrawPtr(mouse_handle); } else if (!mbe && mouse_handle) { MouClose(mouse_handle); mouse_handle = 0; } if (mbe && mouse_handle) { USHORT mask = ((mbe & (BUTTON1_PRESSED | BUTTON1_CLICKED | BUTTON1_MOVED)) ? 6 : 0) | ((mbe & (BUTTON3_PRESSED | BUTTON3_CLICKED | BUTTON3_MOVED)) ? 24 : 0) | ((mbe & (BUTTON2_PRESSED | BUTTON2_CLICKED | BUTTON2_MOVED)) ? 96 : 0); MouSetEventMask(&mask, mouse_handle); } #endif return OK; } int PDC_modifiers_set(void) { key_pressed = FALSE; return OK; }