A+
--
Eric Pouech
Name: wc_cursed ChangeLog: - fixed mouse event generation - better management of some keys - now generating several wincon-events for a given curses-event - added basic support for V-scrolling (disabled by default) - fixed printing of some unsupported characters License: X11 GenDate: 2003/02/13 20:10:37 UTC ModifiedFiles: programs/wineconsole/curses.c AddedFiles: =================================================================== RCS file: /home/cvs/cvsroot/wine/wine/programs/wineconsole/curses.c,v retrieving revision 1.4 diff -u -u -r1.4 curses.c --- programs/wineconsole/curses.c 23 Jan 2003 22:51:04 -0000 1.4 +++ programs/wineconsole/curses.c 9 Feb 2003 21:42:31 -0000 @@ -23,6 +23,8 @@ * - not all key mapping functions have been written * - allow dyn loading of curses library (extreme care should be taken for * functions which can be implemented as macros) + * - finish buffer scrolling (mainly, need to decide of a nice way for + * requesting the UP/DOWN operations */ #include "config.h" @@ -54,6 +56,7 @@ HANDLE hInput; WINDOW* pad; chtype* line; + int allow_scroll; }; /****************************************************************** @@ -161,8 +164,8 @@ { WideCharToMultiByte(CP_ACP, 0, &cell[x].Char.UnicodeChar, 1, &ch, 1, NULL, NULL); - attr = (BYTE)ch; - + attr = ((BYTE)ch < 32 || (BYTE)ch > 127) ? 32 : (BYTE)ch; + if (cell[x].Attributes & FOREGROUND_RED) attr |= COLOR_PAIR(COLOR_RED); if (cell[x].Attributes & FOREGROUND_BLUE) attr |= COLOR_PAIR(COLOR_BLUE); if (cell[x].Attributes & FOREGROUND_GREEN) attr |= COLOR_PAIR(COLOR_GREEN); @@ -209,6 +212,27 @@ /* FIXME: really not much to do ? */ } +/****************************************************************** + * WCCURSES_ScrollV + * + * + */ +static void WCCURSES_ScrollV(struct inner_data* data, int delta) +{ + int pos = data->curcfg.win_pos.Y; + + pos += delta; + if (pos < 0) pos = 0; + if (pos > data->curcfg.sb_height - data->curcfg.win_height) + pos = data->curcfg.sb_height - data->curcfg.win_height; + if (pos != data->curcfg.win_pos.Y) + { + data->curcfg.win_pos.Y = pos; + WCCURSES_PosCursor(data); + WINECON_NotifyWindowChange(data); + } +} + /* Ascii -> VK, generated by calling VkKeyScanA(i) */ static int vkkeyscan_table[256] = { @@ -238,50 +262,90 @@ }; /****************************************************************** + * WCCURSES_InitComplexChar + * + * + */ +static inline void WCCURSES_InitComplexChar(INPUT_RECORD* ir, BOOL down, WORD vk, WORD kc, DWORD cks) +{ + ir->EventType = KEY_EVENT; + ir->Event.KeyEvent.bKeyDown = down; + ir->Event.KeyEvent.wRepeatCount = 1; + + ir->Event.KeyEvent.wVirtualScanCode = vk; + ir->Event.KeyEvent.wVirtualKeyCode = kc; + ir->Event.KeyEvent.dwControlKeyState = cks; + ir->Event.KeyEvent.uChar.UnicodeChar = 0; +} + +/****************************************************************** * WCCURSES_FillSimpleChar * * */ -static unsigned WCCURSES_FillSimpleChar(INPUT_RECORD* ir, unsigned inchar) +static unsigned WCCURSES_FillSimpleChar(INPUT_RECORD* ir, unsigned real_inchar) { - unsigned vk; - unsigned second; - DWORD cks = 0; - - switch (inchar) - { - case 127: inchar = '\b'; break; - case 10: inchar = '\r'; break; - case 27: - /* we assume that ESC & and the second character are atomically generated - * otherwise, we'll have a race here - */ - if ((second = wgetch(stdscr)) != ERR) - { - /* we got a alt-something key... */ - /* FIXME: we don't generate the keydown message for the Alt key */ - cks = LEFT_ALT_PRESSED; - inchar = second; - } - break; - } - - ir->EventType = KEY_EVENT; - ir->Event.KeyEvent.bKeyDown = 1; - ir->Event.KeyEvent.wRepeatCount = 1; - ir->Event.KeyEvent.dwControlKeyState = cks; - vk = vkkeyscan_table[inchar]; - if (vk & 0x0100) - ir->Event.KeyEvent.dwControlKeyState |= SHIFT_PRESSED; - if (vk & 0x0200 || (unsigned char)inchar <= 26) - ir->Event.KeyEvent.dwControlKeyState |= LEFT_CTRL_PRESSED; - if (vk & 0x0400) - ir->Event.KeyEvent.dwControlKeyState |= LEFT_ALT_PRESSED; - ir->Event.KeyEvent.wVirtualKeyCode = vk; - ir->Event.KeyEvent.wVirtualScanCode = mapvkey_0[vk & 0x00ff]; /* VirtualKeyCodes to ScanCode */ - ir->Event.KeyEvent.uChar.UnicodeChar = (unsigned char)inchar; + unsigned vk; + unsigned inchar; + unsigned numEvent = 0; + DWORD cks = 0; + + switch (real_inchar) + { + case 127: inchar = '\b'; break; + case 10: inchar = '\r'; real_inchar = 27; /* so that we don't think key is ctrl- something */ break; + case 27: + /* we assume that ESC & and the second character are atomically generated + * otherwise, we'll have a race here + */ + if ((inchar = wgetch(stdscr)) != ERR) + { + /* we got a alt-something key... */ + cks = LEFT_ALT_PRESSED; + } + else + inchar = 27; + break; + default: + inchar = real_inchar; + break; + } + if ((inchar & ~0xFF) != 0) WINE_FIXME("What a char (%u)\n", inchar); + vk = vkkeyscan_table[inchar]; + if (vk & 0x0100) + WCCURSES_InitComplexChar(&ir[numEvent++], 1, 0x2a, 0x10, SHIFT_PRESSED); + if ((vk & 0x0200) || (unsigned char)real_inchar <= 26) + WCCURSES_InitComplexChar(&ir[numEvent++], 1, 0x1d, 0x11, LEFT_CTRL_PRESSED); + if (vk & 0x0400) + WCCURSES_InitComplexChar(&ir[numEvent++], 1, 0x38, 0x12, LEFT_ALT_PRESSED); + + ir[numEvent].EventType = KEY_EVENT; + ir[numEvent].Event.KeyEvent.bKeyDown = 1; + ir[numEvent].Event.KeyEvent.wRepeatCount = 1; + ir[numEvent].Event.KeyEvent.dwControlKeyState = cks; + if (vk & 0x0100) + ir[numEvent].Event.KeyEvent.dwControlKeyState |= SHIFT_PRESSED; + if ((vk & 0x0200) || (unsigned char)real_inchar <= 26) + ir[numEvent].Event.KeyEvent.dwControlKeyState |= LEFT_CTRL_PRESSED; + if (vk & 0x0400) + ir[numEvent].Event.KeyEvent.dwControlKeyState |= LEFT_ALT_PRESSED; + ir[numEvent].Event.KeyEvent.wVirtualKeyCode = vk; + ir[numEvent].Event.KeyEvent.wVirtualScanCode = mapvkey_0[vk & 0x00ff]; /* VirtualKeyCodes to ScanCode */ + ir[numEvent].Event.KeyEvent.uChar.UnicodeChar = (unsigned char)inchar; + + ir[numEvent + 1] = ir[numEvent]; + ir[numEvent + 1].Event.KeyEvent.bKeyDown = 0; + + numEvent += 2; + + if (vk & 0x0400) + WCCURSES_InitComplexChar(&ir[numEvent++], 0, 0x38, 0x12, LEFT_ALT_PRESSED); + if ((vk & 0x0200) || (unsigned char)real_inchar <= 26) + WCCURSES_InitComplexChar(&ir[numEvent++], 0, 0x1d, 0x11, 0); + if (vk & 0x0100) + WCCURSES_InitComplexChar(&ir[numEvent++], 0, 0x2a, 0x10, 0); - return TRUE; + return numEvent; } /****************************************************************** @@ -289,19 +353,12 @@ * * */ -static unsigned WCCURSES_FillComplexChar(INPUT_RECORD* ir, WORD vk, WORD kc) +static unsigned WCCURSES_FillComplexChar(INPUT_RECORD* ir, WORD vk, WORD kc, DWORD cks) { - ir->EventType = KEY_EVENT; - ir->Event.KeyEvent.bKeyDown = 1; - ir->Event.KeyEvent.wRepeatCount = 1; - ir->Event.KeyEvent.dwControlKeyState = 0; - - ir->Event.KeyEvent.wVirtualScanCode = vk; - ir->Event.KeyEvent.wVirtualKeyCode = kc; - ir->Event.KeyEvent.dwControlKeyState |= ENHANCED_KEY; - ir->Event.KeyEvent.uChar.UnicodeChar = 0; - - return TRUE; + WCCURSES_InitComplexChar(&ir[0], 1, vk, kc, ENHANCED_KEY | cks); + WCCURSES_InitComplexChar(&ir[1], 0, vk, kc, ENHANCED_KEY | cks); + + return 2; } /****************************************************************** @@ -311,58 +368,58 @@ */ static unsigned WCCURSES_FillMouse(INPUT_RECORD* ir) { - static unsigned bstate /* = 0 */; - static COORD pos /* = {0, 0} */; - - MEVENT mevt; - - if (getmouse(&mevt) == ERR) - return FALSE; - - WINE_TRACE("[%u]: (%d, %d) %08lx\n", - mevt.id, mevt.x, mevt.y, (unsigned long)mevt.bstate); - - /* macros to ease mapping ncurse button numbering to windows's one */ + static unsigned bstate /* = 0 */; + static COORD pos /* = {0, 0} */; + + MEVENT mevt; + + if (getmouse(&mevt) == ERR) + return 0; + + WINE_TRACE("[%u]: (%d, %d) %08lx\n", + mevt.id, mevt.x, mevt.y, (unsigned long)mevt.bstate); + + /* macros to ease mapping ncurse button numbering to windows's one */ #define BTN1_BIT FROM_LEFT_1ST_BUTTON_PRESSED #define BTN2_BIT RIGHTMOST_BUTTON_PRESSED #define BTN3_BIT FROM_LEFT_2ND_BUTTON_PRESSED #define BTN4_BIT 0 /* not done yet */ - - if (mevt.bstate & BUTTON1_PRESSED) bstate |= BTN1_BIT; - if (mevt.bstate & BUTTON1_RELEASED) bstate &= ~BTN1_BIT; - if (mevt.bstate & BUTTON2_PRESSED) bstate |= BTN2_BIT; - if (mevt.bstate & BUTTON2_RELEASED) bstate &= ~BTN2_BIT; - if (mevt.bstate & BUTTON3_PRESSED) bstate |= BTN3_BIT; - if (mevt.bstate & BUTTON3_RELEASED) bstate &= ~BTN3_BIT; - - ir->EventType = MOUSE_EVENT; - ir->Event.MouseEvent.dwMousePosition.X = mevt.x; - ir->Event.MouseEvent.dwMousePosition.Y = mevt.y; - - ir->Event.MouseEvent.dwButtonState = bstate; - - /* partial conversion */ - ir->Event.MouseEvent.dwControlKeyState = 0; - if (mevt.bstate & BUTTON_SHIFT) ir->Event.MouseEvent.dwControlKeyState |= SHIFT_PRESSED; - /* choose to map to left ctrl... could use both ? */ - if (mevt.bstate & BUTTON_CTRL) ir->Event.MouseEvent.dwControlKeyState |= LEFT_CTRL_PRESSED; - /* choose to map to left alt... could use both ? */ - if (mevt.bstate & BUTTON_ALT) ir->Event.MouseEvent.dwControlKeyState |= LEFT_ALT_PRESSED; - /* FIXME: unsupported yet flags: CAPSLOCK_ON, ENHANCED_KEY (??), NUMLOCK_ON, SCROLLLOCK_ON - * could be reported from the key events... - */ - - ir->Event.MouseEvent.dwEventFlags = 0; - /* FIXME: we no longer generate double click events */ - - if (!(mevt.bstate & (BUTTON1_PRESSED|BUTTON1_RELEASED|BUTTON2_PRESSED|BUTTON2_RELEASED|BUTTON3_PRESSED|BUTTON3_RELEASED)) && - (mevt.x != pos.X || mevt.y != pos.Y)) - { - ir->Event.MouseEvent.dwEventFlags |= MOUSE_MOVED; - } - pos.X = mevt.x; pos.Y = mevt.y; - return FALSE; + if (mevt.bstate & BUTTON1_PRESSED) bstate |= BTN1_BIT; + if (mevt.bstate & BUTTON1_RELEASED) bstate &= ~BTN1_BIT; + if (mevt.bstate & BUTTON2_PRESSED) bstate |= BTN2_BIT; + if (mevt.bstate & BUTTON2_RELEASED) bstate &= ~BTN2_BIT; + if (mevt.bstate & BUTTON3_PRESSED) bstate |= BTN3_BIT; + if (mevt.bstate & BUTTON3_RELEASED) bstate &= ~BTN3_BIT; + + ir->EventType = MOUSE_EVENT; + ir->Event.MouseEvent.dwMousePosition.X = mevt.x; + ir->Event.MouseEvent.dwMousePosition.Y = mevt.y; + + ir->Event.MouseEvent.dwButtonState = bstate; + + /* partial conversion */ + ir->Event.MouseEvent.dwControlKeyState = 0; + if (mevt.bstate & BUTTON_SHIFT) ir->Event.MouseEvent.dwControlKeyState |= SHIFT_PRESSED; + /* choose to map to left ctrl... could use both ? */ + if (mevt.bstate & BUTTON_CTRL) ir->Event.MouseEvent.dwControlKeyState |= LEFT_CTRL_PRESSED; + /* choose to map to left alt... could use both ? */ + if (mevt.bstate & BUTTON_ALT) ir->Event.MouseEvent.dwControlKeyState |= LEFT_ALT_PRESSED; + /* FIXME: unsupported yet flags: CAPSLOCK_ON, ENHANCED_KEY (??), NUMLOCK_ON, SCROLLLOCK_ON + * could be reported from the key events... + */ + + ir->Event.MouseEvent.dwEventFlags = 0; + /* FIXME: we no longer generate double click events */ + + if (!(mevt.bstate & (BUTTON1_PRESSED|BUTTON1_RELEASED|BUTTON2_PRESSED|BUTTON2_RELEASED|BUTTON3_PRESSED|BUTTON3_RELEASED)) && + (mevt.x != pos.X || mevt.y != pos.Y)) + { + ir->Event.MouseEvent.dwEventFlags |= MOUSE_MOVED; + } + pos.X = mevt.x; pos.Y = mevt.y; + + return 1; } /****************************************************************** @@ -370,31 +427,31 @@ * * */ -static unsigned WCCURSES_FillCode(INPUT_RECORD* ir, int inchar) +static unsigned WCCURSES_FillCode(struct inner_data* data, INPUT_RECORD* ir, int inchar) { - unsigned secondEvent = 0; - + unsigned numEvent = 0; + switch (inchar) { case KEY_BREAK: goto notFound; case KEY_DOWN: - secondEvent = WCCURSES_FillComplexChar(ir, 0x50, 0x28); + numEvent = WCCURSES_FillComplexChar(ir, 0x50, 0x28, 0); break; case KEY_UP: - secondEvent = WCCURSES_FillComplexChar(ir, 0x48, 0x26); + numEvent = WCCURSES_FillComplexChar(ir, 0x48, 0x26, 0); break; case KEY_LEFT: - secondEvent = WCCURSES_FillComplexChar(ir, 0x4b, 0x25); + numEvent = WCCURSES_FillComplexChar(ir, 0x4b, 0x25, 0); break; case KEY_RIGHT: - secondEvent = WCCURSES_FillComplexChar(ir, 0x4d, 0x27); + numEvent = WCCURSES_FillComplexChar(ir, 0x4d, 0x27, 0); break; case KEY_HOME: - secondEvent = WCCURSES_FillComplexChar(ir, 0x47, 0x24); + numEvent = WCCURSES_FillComplexChar(ir, 0x47, 0x24, 0); break; case KEY_BACKSPACE: - secondEvent = WCCURSES_FillSimpleChar(ir, '\b'); + numEvent = WCCURSES_FillSimpleChar(ir, '\b'); break; case KEY_F0: /* up to F63 */ @@ -410,17 +467,31 @@ case KEY_F( 8): case KEY_F( 9): case KEY_F(10): - secondEvent = WCCURSES_FillComplexChar(ir, 0x3b + inchar - KEY_F(1), 0); + numEvent = WCCURSES_FillComplexChar(ir, 0x3b + inchar - KEY_F(1), 0, 0); break; case KEY_F(11): case KEY_F(12): - secondEvent = WCCURSES_FillComplexChar(ir, 0xd9 + inchar - KEY_F(11), 0); + if (PRIVATE(data)->allow_scroll) + { + WCCURSES_ScrollV(data, inchar == KEY_F(11) ? 8 : -8); + } + else + { + numEvent = WCCURSES_FillComplexChar(ir, 0xd9 + inchar - KEY_F(11), 0, 0); + } break; case KEY_DL: case KEY_IL: + goto notFound; + case KEY_DC: + numEvent = WCCURSES_FillComplexChar(ir, 0x53, 0x2e, 0); + break; case KEY_IC: + numEvent = WCCURSES_FillComplexChar(ir, 0x52, 0x2d, 0); + break; + case KEY_EIC: case KEY_CLEAR: case KEY_EOS: @@ -430,10 +501,10 @@ goto notFound; case KEY_NPAGE: - secondEvent = WCCURSES_FillComplexChar(ir, 0x51, 0x22); + numEvent = WCCURSES_FillComplexChar(ir, 0x51, 0x22, 0); break; case KEY_PPAGE: - secondEvent = WCCURSES_FillComplexChar(ir, 0x49, 0x21); + numEvent = WCCURSES_FillComplexChar(ir, 0x49, 0x21, 0); break; case KEY_STAB: @@ -456,7 +527,12 @@ case KEY_COMMAND: case KEY_COPY: case KEY_CREATE: + goto notFound; + case KEY_END: + numEvent = WCCURSES_FillComplexChar(ir, 0x4f, 0x23, 0); + break; + case KEY_EXIT: case KEY_FIND: case KEY_HELP: @@ -465,7 +541,7 @@ goto notFound; case KEY_MOUSE: - secondEvent = WCCURSES_FillMouse(ir); + numEvent = WCCURSES_FillMouse(ir); break; case KEY_MOVE: @@ -486,17 +562,35 @@ case KEY_SCOMMAND: case KEY_SCOPY: case KEY_SCREATE: + goto notFound; + case KEY_SDC: + numEvent = WCCURSES_FillComplexChar(ir, 0x53, 0x2e, SHIFT_PRESSED); + break; case KEY_SDL: case KEY_SELECT: + goto notFound; + case KEY_SEND: + numEvent = WCCURSES_FillComplexChar(ir, 0x4f, 0x23, SHIFT_PRESSED); + break; + case KEY_SEOL: case KEY_SEXIT: case KEY_SFIND: case KEY_SHELP: + goto notFound; + case KEY_SHOME: + numEvent = WCCURSES_FillComplexChar(ir, 0x47, 0x24, SHIFT_PRESSED); + break; case KEY_SIC: + numEvent = WCCURSES_FillComplexChar(ir, 0x52, 0x2d, SHIFT_PRESSED); + break; case KEY_SLEFT: + numEvent = WCCURSES_FillComplexChar(ir, 0x4b, 0x25, SHIFT_PRESSED); + break; + case KEY_SMESSAGE: case KEY_SMOVE: case KEY_SNEXT: @@ -505,7 +599,12 @@ case KEY_SPRINT: case KEY_SREDO: case KEY_SREPLACE: + goto notFound; + case KEY_SRIGHT: + numEvent = WCCURSES_FillComplexChar(ir, 0x4d, 0x27, SHIFT_PRESSED); + break; + case KEY_SRSUME: case KEY_SSAVE: case KEY_SSUSPEND: @@ -513,13 +612,13 @@ case KEY_SUSPEND: case KEY_UNDO: notFound: - WINE_FIXME("Not done yet (%d)\n", inchar); + WINE_FIXME("Not done yet (%o)\n", inchar); break; default: - WINE_ERR("Unknown val (%d)\n", inchar); + WINE_ERR("Unknown val (%o)\n", inchar); break; } - return secondEvent; + return numEvent; } /****************************************************************** @@ -529,45 +628,25 @@ */ static void WCCURSES_GetEvents(struct inner_data* data) { - int inchar; - INPUT_RECORD ir[2]; - unsigned secondEvent = 0; - DWORD n; - - if ((inchar = wgetch(stdscr)) == ERR) {WINE_FIXME("Ooch. somebody beat us\n");return;} - - WINE_TRACE("Got %d\n", inchar); - - ir->EventType = 0; - - if (inchar & KEY_CODE_YES) - { - secondEvent = WCCURSES_FillCode(ir, inchar); - } - else - { - secondEvent = WCCURSES_FillSimpleChar(ir, inchar); - } - - if (secondEvent != 0) - { - ir[1] = ir[0]; - - switch (ir[1].EventType) - { - case KEY_EVENT: - ir[1].Event.KeyEvent.bKeyDown = 0; - break; - case MOUSE_EVENT: - ir[1].Event.MouseEvent.dwButtonState &= ~secondEvent; - break; - default: - WINE_FIXME("oooo\n"); - break; - } - } - if (ir[0].EventType != 0) - WriteConsoleInput(data->hConIn, ir, secondEvent ? 2 : 1, &n); + int inchar; + INPUT_RECORD ir[8]; + unsigned numEvent; + DWORD n; + + if ((inchar = wgetch(stdscr)) == ERR) {WINE_FIXME("Ooch. somebody beat us\n");return;} + + WINE_TRACE("Got %d\n", inchar); + + if (inchar & KEY_CODE_YES) + { + numEvent = WCCURSES_FillCode(data, ir, inchar); + } + else + { + numEvent = WCCURSES_FillSimpleChar(ir, inchar); + } + if (numEvent) + WriteConsoleInput(data->hConIn, ir, numEvent, &n); } /****************************************************************** @@ -652,6 +731,12 @@ return 0; } + /* FIXME: should find a good way to enable buffer scrolling + * For the time being, setting this to 1 will allow scrolling up/down + * on buffer with F11/F12. + */ + /* data->allow_scroll = 1; */ + initscr(); /* creating the basic colors - FIXME intensity not handled yet */ @@ -670,10 +755,16 @@ intrflush(stdscr, FALSE); nodelay(stdscr, TRUE); keypad(stdscr, TRUE); - mousemask(0xffffffff, &PRIVATE(data)->initial_mouse_mask); - /* no click event generation... we just need button up/down event */ - mouseinterval(-1); - + mousemask(BUTTON1_PRESSED|BUTTON1_RELEASED| + BUTTON2_PRESSED|BUTTON2_RELEASED| + BUTTON3_PRESSED|BUTTON3_RELEASED| + BUTTON_SHIFT|BUTTON_CTRL|BUTTON_ALT|REPORT_MOUSE_POSITION, + &PRIVATE(data)->initial_mouse_mask); + /* no click event generation... we just need button up/down events + * it doesn't seem that mouseinterval(-1) behaves as documented... + * 0 seems to be better value to disable click event generation + */ + mouseinterval(0); return TRUE; }