[PATCH 3/4] [Kernel32]: now correctly parsing the input strings for advanced keys
Eric Pouech
eric.pouech at orange.fr
Tue Jan 18 15:02:37 CST 2011
A+
---
dlls/kernel32/console.c | 101 +++++++++++++++++++-------
dlls/kernel32/console_private.h | 1
dlls/kernel32/term.c | 149 +++++++++++++++++++++++++++++++++++++++
3 files changed, 223 insertions(+), 28 deletions(-)
diff --git a/dlls/kernel32/console.c b/dlls/kernel32/console.c
index f845fe9..ba8771c 100644
--- a/dlls/kernel32/console.c
+++ b/dlls/kernel32/console.c
@@ -5,7 +5,7 @@
* Copyright 1997 Karl Garrison
* Copyright 1998 John Richardson
* Copyright 1998 Marcus Meissner
- * Copyright 2001,2002,2004,2005 Eric Pouech
+ * Copyright 2001,2002,2004,2005,2010 Eric Pouech
* Copyright 2001 Alexandre Julliard
*
* This library is free software; you can redistribute it and/or
@@ -1099,39 +1099,84 @@ enum read_console_input_return {rci_error = 0, rci_timeout = 1, rci_gotone = 2};
static enum read_console_input_return bare_console_fetch_input(HANDLE handle, int fd, DWORD timeout)
{
- struct pollfd pollfd;
- char ch;
- enum read_console_input_return ret;
- unsigned numEvent;
- INPUT_RECORD ir[8];
- DWORD written;
-
- pollfd.fd = fd;
- pollfd.events = POLLIN;
- pollfd.revents = 0;
+ enum read_console_input_return ret;
+ char input[8];
+ int i;
+ size_t idx = 0;
+ unsigned numEvent;
+ INPUT_RECORD ir[8];
+ DWORD written;
+ struct pollfd pollfd;
+ BOOL locked = FALSE, next_char;
+
+ do
+ {
+ if (idx == sizeof(input))
+ {
+ FIXME("buffer too small (%s)\n", wine_dbgstr_an(input, idx));
+ ret = rci_error;
+ break;
+ }
+ pollfd.fd = fd;
+ pollfd.events = POLLIN;
+ pollfd.revents = 0;
+ next_char = FALSE;
- switch (poll(&pollfd, 1, timeout))
- {
- case 1:
- RtlEnterCriticalSection(&CONSOLE_CritSect);
- switch (read(fd, &ch, 1))
+ switch (poll(&pollfd, 1, timeout))
{
case 1:
- numEvent = TERM_FillSimpleChar(ch, ir);
- ret = WriteConsoleInputW(handle, ir, numEvent, &written) ? rci_gotone : rci_error;
+ if (!locked)
+ {
+ RtlEnterCriticalSection(&CONSOLE_CritSect);
+ locked = TRUE;
+ }
+ i = read(fd, &input[idx], 1);
+ if (i < 0)
+ {
+ ret = rci_error;
+ break;
+ }
+ if (i == 0)
+ {
+ /* actually another thread likely beat us to reading the char
+ * return rci_gotone, while not perfect, it should work in most of the cases (as the new event
+ * should be now in the queue, fed from the other thread)
+ */
+ ret = rci_gotone;
+ break;
+ }
+
+ idx++;
+ numEvent = TERM_FillInputRecord(input, idx, ir);
+ switch (numEvent)
+ {
+ case 0:
+ /* we need more char(s) to tell if it matches a key-db entry. wait 1/2s for next char */
+ timeout = 500;
+ next_char = TRUE;
+ break;
+ case -1:
+ /* we haven't found the string into key-db, push full input string into server */
+ for (i = 0; i < idx; i++)
+ {
+ numEvent = TERM_FillSimpleChar(input[i], ir);
+ WriteConsoleInputW(handle, ir, numEvent, &written);
+ }
+ ret = idx == 0 ? rci_timeout : rci_gotone;
+ break;
+ default:
+ /* we got a transformation from key-db... push this into server */
+ ret = WriteConsoleInputW(handle, ir, numEvent, &written) ? rci_gotone : rci_error;
+ break;
+ }
break;
- /* actually another thread likely beat us to reading the char
- * return gotone, while not perfect, it should work in most of the cases (as the new event
- * should be now in the queue)
- */
- case 0: ret = rci_gotone; break;
+ case 0: ret = rci_timeout; break;
default: ret = rci_error; break;
}
- RtlLeaveCriticalSection(&CONSOLE_CritSect);
- return ret;
- case 0: return rci_timeout;
- default: return rci_error;
- }
+ } while (next_char);
+ if (locked) RtlLeaveCriticalSection(&CONSOLE_CritSect);
+
+ return ret;
}
static enum read_console_input_return read_console_input(HANDLE handle, PINPUT_RECORD ir, DWORD timeout)
diff --git a/dlls/kernel32/console_private.h b/dlls/kernel32/console_private.h
index c5b8799..b25f65c 100644
--- a/dlls/kernel32/console_private.h
+++ b/dlls/kernel32/console_private.h
@@ -37,5 +37,6 @@ extern WCHAR* CONSOLE_Readline(HANDLE, BOOL);
extern BOOL TERM_Init(void);
extern BOOL TERM_Exit(void);
extern unsigned TERM_FillSimpleChar(unsigned real_inchar, INPUT_RECORD* ir);
+extern int TERM_FillInputRecord(const char* in, size_t len, INPUT_RECORD* ir);
#endif /* __WINE_CONSOLE_PRIVATE_H */
diff --git a/dlls/kernel32/term.c b/dlls/kernel32/term.c
index acffd43..8111f0b 100644
--- a/dlls/kernel32/term.c
+++ b/dlls/kernel32/term.c
@@ -157,7 +157,10 @@ static void *nc_handle = NULL;
#define MAKE_FUNCPTR(f) static typeof(f) * p_##f;
+MAKE_FUNCPTR(putp)
MAKE_FUNCPTR(setupterm)
+MAKE_FUNCPTR(tigetstr)
+MAKE_FUNCPTR(tparm)
#undef MAKE_FUNCPTR
@@ -185,7 +188,10 @@ static BOOL TERM_bind_libcurses(void)
goto sym_not_found; \
}
+ LOAD_FUNCPTR(putp)
LOAD_FUNCPTR(setupterm)
+ LOAD_FUNCPTR(tigetstr)
+ LOAD_FUNCPTR(tparm)
#undef LOAD_FUNCPTR
@@ -201,20 +207,163 @@ sym_not_found:
return FALSE;
}
+#define putp p_putp
#define setupterm p_setupterm
+#define tigetstr p_tigetstr
+#define tparm p_tparm
+
+struct dbkey_descr
+{
+ enum dbkey_kind {dbk_simple, dbk_complex} kind;
+ DWORD_PTR p1;
+ DWORD_PTR p2;
+ DWORD_PTR p3;
+};
+
+struct dbkey_pair
+{
+ const char* string;
+ struct dbkey_descr descr;
+};
+
+static struct dbkey_pair TERM_dbkey_init[] = {
+ {"kcud1", {dbk_complex, 0x50, 0x28, 0}},
+ {"kcuu1", {dbk_complex, 0x48, 0x26, 0}},
+ {"kcub1", {dbk_complex, 0x4b, 0x25, 0}},
+ {"kcuf1", {dbk_complex, 0x4d, 0x27, 0}},
+ {"khome", {dbk_complex, 0x47, 0x24, 0}},
+ {"kbs", {dbk_simple, 0x7f, 0x00, 0}},
+ {"kf1", {dbk_complex, 0x3b, 0x70, 0}},
+ {"kf2", {dbk_complex, 0x3c, 0x71, 0}},
+ {"kf3", {dbk_complex, 0x3d, 0x72, 0}},
+ {"kf4", {dbk_complex, 0x3e, 0x73, 0}},
+ {"kf5", {dbk_complex, 0x3f, 0x74, 0}},
+ {"kf6", {dbk_complex, 0x40, 0x75, 0}},
+ {"kf7", {dbk_complex, 0x41, 0x76, 0}},
+ {"kf8", {dbk_complex, 0x42, 0x77, 0}},
+ {"kf9", {dbk_complex, 0x43, 0x78, 0}},
+ {"kf10", {dbk_complex, 0x44, 0x79, 0}},
+ {"kf11", {dbk_complex, 0xd9, 0x7a, 0}},
+ {"kf12", {dbk_complex, 0xda, 0x7b, 0}},
+ {"kdch1", {dbk_complex, 0x53, 0x2e, 0}},
+ {"kich1", {dbk_complex, 0x52, 0x2d, 0}},
+ {"knp", {dbk_complex, 0x51, 0x22, 0}},
+ {"kpp", {dbk_complex, 0x49, 0x21, 0}},
+ {"kcbt", {dbk_simple, 0x09, 0x00, SHIFT_PRESSED}},
+
+ {"kend", {dbk_complex, 0x4f, 0x23, 0}},
+ /* {"kmous", NULL, }, */
+ {"kDC", {dbk_complex, 0x53, 0x2e, SHIFT_PRESSED}},
+ {"kEND", {dbk_complex, 0x4f, 0x23, SHIFT_PRESSED}},
+ {"kHOM", {dbk_complex, 0x47, 0x24, SHIFT_PRESSED}},
+ {"kIC", {dbk_complex, 0x52, 0x2d, SHIFT_PRESSED}},
+ {"kLFT", {dbk_complex, 0x4b, 0x25, SHIFT_PRESSED}},
+ {"kRIT", {dbk_complex, 0x4d, 0x27, SHIFT_PRESSED}},
+
+ /* Still some keys to manage:
+ KEY_DL KEY_IL KEY_EIC KEY_CLEAR KEY_EOS
+ KEY_EOL KEY_SF KEY_SR KEY_STAB KEY_CTAB
+ KEY_CATAB KEY_ENTER KEY_SRESET KEY_RESET KEY_PRINT
+ KEY_LL KEY_A1 KEY_A3 KEY_B2 KEY_C1
+ KEY_C3 KEY_BEG KEY_CANCEL KEY_CLOSE KEY_COMMAND
+ KEY_COPY KEY_CREATE KEY_EXIT KEY_FIND KEY_HELP
+ KEY_MARK KEY_MESSAGE KEY_MOVE KEY_NEXT KEY_OPEN
+ KEY_OPTIONS KEY_PREVIOUS KEY_REDO KEY_REFERENCE KEY_REFRESH
+ KEY_REPLACE KEY_RESTART KEY_RESUME KEY_SAVE KEY_SBEG
+ KEY_SCANCEL KEY_SCOMMAND KEY_SCOPY KEY_SCREATE KEY_RESIZE
+ KEY_SDL KEY_SELECT KEY_SEOL KEY_SEXIT KEY_SFIND
+ KEY_SHELP KEY_SMESSAGE KEY_SMOVE KEY_SNEXT KEY_SOPTIONS
+ KEY_SPREVIOUS KEY_SPRINT KEY_SREDO KEY_SREPLACE KEY_SRSUME
+ KEY_SSAVE KEY_SSUSPEND KEY_SUNDO KEY_SUSPEND KEY_UNDO
+ */
+};
+
+static struct dbkey_pair* TERM_dbkey;
+static unsigned TERM_dbkey_size;
+static unsigned TERM_dbkey_index;
+
+static BOOL TERM_AddKeyDescr(const char* string, struct dbkey_descr* descr)
+{
+ if (!string) return FALSE;
+ if (!TERM_dbkey)
+ {
+ TERM_dbkey_size = 32;
+ TERM_dbkey = HeapAlloc(GetProcessHeap(), 0, TERM_dbkey_size * sizeof(struct dbkey_pair));
+ if (!TERM_dbkey) return FALSE;
+ }
+ if (TERM_dbkey_index == TERM_dbkey_size)
+ {
+ struct dbkey_pair* new;
+
+ new = HeapReAlloc(GetProcessHeap(), 0, TERM_dbkey, (2 * TERM_dbkey_size) * sizeof(struct dbkey_pair));
+ if (!new) return FALSE;
+ TERM_dbkey = new;
+ TERM_dbkey_size *= 2;
+ }
+ TERM_dbkey[TERM_dbkey_index].string = string;
+ TERM_dbkey[TERM_dbkey_index].descr = *descr;
+ TERM_dbkey_index++;
+ return TRUE;
+}
+
+static BOOL TERM_BuildKeyDB(void)
+{
+ unsigned i;
+ for (i = 0; i < sizeof(TERM_dbkey_init) / sizeof(TERM_dbkey_init[0]); i++)
+ {
+ if (!TERM_AddKeyDescr(tigetstr(TERM_dbkey_init[i].string), &TERM_dbkey_init[i].descr))
+ return FALSE;
+ }
+ return TRUE;
+}
BOOL TERM_Init(void)
{
if (!TERM_bind_libcurses()) return FALSE;
if (setupterm(NULL, 1 /* really ?? */, NULL) == -1) return FALSE;
+ TERM_BuildKeyDB();
+ /* set application key mode */
+ putp(tigetstr("smkx"));
return TRUE;
}
BOOL TERM_Exit(void)
{
+ /* put back the cursor key mode */
+ putp(tigetstr("rmkx"));
return TRUE;
}
+
+/* -1 not found, 0 cannot decide, > 0 found */
+int TERM_FillInputRecord(const char* in, size_t len, INPUT_RECORD* ir)
+{
+ unsigned i;
+ struct dbkey_descr* found = NULL;
+
+ for (i = 0; i < TERM_dbkey_index; i++)
+ {
+ if (!memcmp(TERM_dbkey[i].string, in, len))
+ {
+ if (len < strlen(TERM_dbkey[i].string)) return 0;
+ if (found) return 0;
+ found = &TERM_dbkey[i].descr;
+ }
+ }
+ if (!found) return -1;
+ switch (found->kind)
+ {
+ case dbk_simple:
+ return TERM_FillSimpleChar(found->p1, ir);
+ case dbk_complex:
+ init_complex_char(&ir[0], 1, found->p1, found->p2, ENHANCED_KEY | found->p3);
+ init_complex_char(&ir[1], 0, found->p1, found->p2, ENHANCED_KEY | found->p3);
+ return 2;
+ }
+ return -1;
+}
+
#else
BOOL TERM_Init(void) {return FALSE;}
BOOL TERM_Exit(void) {return FALSE;}
+int TERM_FillInputRecord(const char* in, INPUT_RECORD* ir) {return -1;}
#endif
More information about the wine-patches
mailing list