comparison mcabber/src/screen.c @ 761:4532a9fe0e8c

Handle some keyboard escape sequences Some sequences are not caught by ncurses, so I've made a basic escape sequences interpreter. The patch defines a few sequences for xterm and Gnome terminal (ctrl-arrows).
author Mikael Berthe <mikael@lilotux.net>
date Sun, 19 Mar 2006 12:41:46 +0100
parents 715952c2f37f
children 96d46e00524a
comparison
equal deleted inserted replaced
760:715952c2f37f 761:4532a9fe0e8c
89 static short int inputline_offset; 89 static short int inputline_offset;
90 static int completion_started; 90 static int completion_started;
91 static GList *cmdhisto; 91 static GList *cmdhisto;
92 static GList *cmdhisto_cur; 92 static GList *cmdhisto_cur;
93 static char cmdhisto_backup[INPUTLINE_LENGTH+1]; 93 static char cmdhisto_backup[INPUTLINE_LENGTH+1];
94
95 #define MAX_KEYSEQ_LENGTH 8
96
97 typedef struct {
98 char *seqstr;
99 guint mkeycode;
100 gint value;
101 } keyseq;
102
103 GSList *keyseqlist;
104 static void add_keyseq(char *seqstr, guint mkeycode, gint value);
94 105
95 106
96 /* Functions */ 107 /* Functions */
97 108
98 static int scr_WindowWidth(WINDOW * win) 109 static int scr_WindowWidth(WINDOW * win)
207 } 218 }
208 } 219 }
209 220
210 void scr_InitCurses(void) 221 void scr_InitCurses(void)
211 { 222 {
223 /* Key sequences initialization */
224 add_keyseq("O5A", MKEY_EQUIV, 521); // Ctrl-Up
225 add_keyseq("O5B", MKEY_EQUIV, 514); // Ctrl-Down
226 add_keyseq("O5C", MKEY_EQUIV, 518); // Ctrl-Right
227 add_keyseq("O5D", MKEY_EQUIV, 516); // Ctrl-Left
228 add_keyseq("O6A", MKEY_EQUIV, 520); // Ctrl-Shift-Up
229 add_keyseq("O6B", MKEY_EQUIV, 513); // Ctrl-Shift-Down
230 add_keyseq("O6C", MKEY_EQUIV, 402); // Ctrl-Shift-Right
231 add_keyseq("O6D", MKEY_EQUIV, 393); // Ctrl-Shift-Left
232
233 // Xterm
234 add_keyseq("[1;5A", MKEY_EQUIV, 521); // Ctrl-Up
235 add_keyseq("[1;5B", MKEY_EQUIV, 514); // Ctrl-Down
236 add_keyseq("[1;5C", MKEY_EQUIV, 518); // Ctrl-Right
237 add_keyseq("[1;5D", MKEY_EQUIV, 516); // Ctrl-Left
238 add_keyseq("[1;6A", MKEY_EQUIV, 520); // Ctrl-Shift-Up
239 add_keyseq("[1;6B", MKEY_EQUIV, 513); // Ctrl-Shift-Down
240 add_keyseq("[1;6C", MKEY_EQUIV, 402); // Ctrl-Shift-Right
241 add_keyseq("[1;6D", MKEY_EQUIV, 393); // Ctrl-Shift-Left
242
212 initscr(); 243 initscr();
213 raw(); 244 raw();
214 noecho(); 245 noecho();
215 nonl(); 246 nonl();
216 intrflush(stdscr, FALSE); 247 intrflush(stdscr, FALSE);
1861 scr_end_current_completion(); 1892 scr_end_current_completion();
1862 check_offset(-1); 1893 check_offset(-1);
1863 refresh_inputline(); 1894 refresh_inputline();
1864 } 1895 }
1865 1896
1866 int scr_Getch(void) 1897 static void add_keyseq(char *seqstr, guint mkeycode, gint value)
1867 { 1898 {
1868 return wgetch(inputWnd); 1899 keyseq *ks;
1900
1901 // Let's make sure the length is correct
1902 if (strlen(seqstr) > MAX_KEYSEQ_LENGTH) {
1903 scr_LogPrint(LPRINT_LOGNORM, "add_keyseq(): key sequence is too long!");
1904 return;
1905 }
1906
1907 ks = g_new0(keyseq, 1);
1908 ks->seqstr = g_strdup(seqstr);
1909 ks->mkeycode = mkeycode;
1910 ks->value = value;
1911 keyseqlist = g_slist_append(keyseqlist, ks);
1912 }
1913
1914 // match_keyseq(iseq, &ret)
1915 // Check if "iseq" is a known key escape sequence.
1916 // Return value:
1917 // -1 if "seq" matches no known sequence
1918 // 0 if "seq" could match 1 or more known sequences
1919 // >0 if "seq" matches a key sequence; the mkey code is returned
1920 // and *ret is set to the matching keyseq structure.
1921 static inline guint match_keyseq(int *iseq, keyseq **ret)
1922 {
1923 GSList *ksl;
1924 keyseq *ksp;
1925 char *p, c;
1926 int *i;
1927 int needmore = FALSE;
1928
1929 for (ksl = keyseqlist; ksl; ksl = g_slist_next(ksl)) {
1930 ksp = ksl->data;
1931 p = ksp->seqstr;
1932 i = iseq;
1933 while (1) {
1934 c = (unsigned char)*i;
1935 if (!*p && !c) { // Match
1936 (*ret) = ksp;
1937 return ksp->mkeycode;
1938 }
1939 if (!c) {
1940 // iseq is too short
1941 needmore = TRUE;
1942 break;
1943 } else if (!*p || c != *p) {
1944 // This isn't a match
1945 break;
1946 }
1947 p++; i++;
1948 }
1949 }
1950
1951 if (needmore)
1952 return 0;
1953 return -1;
1954 }
1955
1956 void scr_Getch(keycode *kcode)
1957 {
1958 keyseq *mks;
1959 int ks[MAX_KEYSEQ_LENGTH+1];
1960 int i;
1961
1962 memset(kcode, 0, sizeof(keycode));
1963 memset(ks, 0, sizeof(ks));
1964
1965 kcode->value = wgetch(inputWnd);
1966 if (kcode->value != 27)
1967 return;
1968
1969 // Check for escape key sequence
1970 for (i=0; i < MAX_KEYSEQ_LENGTH; i++) {
1971 int match;
1972 ks[i] = wgetch(inputWnd);
1973 if (ks[i] == ERR) break;
1974 match = match_keyseq(ks, &mks);
1975 if (match == -1) {
1976 // No such key sequence. Let's increment i as it is a valid key.
1977 i++;
1978 break;
1979 }
1980 if (match > 0) {
1981 // We have a matching sequence
1982 kcode->mcode = mks->mkeycode;
1983 kcode->value = mks->value;
1984 return;
1985 }
1986 }
1987
1988 // No match. Let's return a meta-key.
1989 if (i > 0) {
1990 kcode->mcode = MKEY_META;
1991 kcode->value = ks[0];
1992 }
1993 if (i > 1) {
1994 // We need to push some keys back to the keyboard buffer
1995 while (i-- > 1)
1996 ungetch(ks[i]);
1997 }
1998 return;
1869 } 1999 }
1870 2000
1871 // process_key(key) 2001 // process_key(key)
1872 // Handle the pressed key, in the command line (bottom). 2002 // Handle the pressed key, in the command line (bottom).
1873 int process_key(int key) 2003 int process_key(keycode kcode)
1874 { 2004 {
1875 if (key == 27) { 2005 int key = kcode.value;
1876 key = scr_Getch(); 2006
1877 if (key == -1 || key == 27) { 2007 switch (kcode.mcode) {
1878 // This is a "real" escape... 2008 case 0:
1879 scr_CheckAutoAway(TRUE); 2009 break;
1880 currentWindow = NULL; 2010 case MKEY_EQUIV:
1881 chatmode = FALSE; 2011 key = kcode.value;
1882 if (current_buddy) 2012 break;
1883 buddy_setflags(BUDDATA(current_buddy), ROSTER_FLAG_LOCK, FALSE); 2013 case MKEY_META:
1884 scr_RosterVisibility(1); 2014 key = ERR;
1885 scr_UpdateChatStatus(FALSE); 2015 switch (kcode.value) {
1886 top_panel(chatPanel); 2016 case 27:
1887 top_panel(inputPanel); 2017 key = 27;
1888 update_panels(); 2018 break;
1889 } else { // Meta 2019 default:
1890 switch (key) { 2020 scr_LogPrint(LPRINT_NORMAL, "Unknown key=M%d", kcode.value);
1891 default: 2021 }
1892 scr_LogPrint(LPRINT_NORMAL, "Unknown key=M%d", key); 2022 break;
1893 } 2023 default:
1894 } 2024 scr_LogPrint(LPRINT_NORMAL, "Unknown mkeycode! (%d)", kcode.mcode);
1895 key = -1; 2025 key = ERR;
1896 } 2026 }
2027
1897 switch (key) { 2028 switch (key) {
1898 case -1: 2029 case 0:
2030 case ERR:
1899 break; 2031 break;
1900 case 8: // Ctrl-h 2032 case 8: // Ctrl-h
1901 case 127: // Backspace too 2033 case 127: // Backspace too
1902 case KEY_BACKSPACE: 2034 case KEY_BACKSPACE:
1903 if (ptr_inputline != (char*)&inputLine) { 2035 if (ptr_inputline != (char*)&inputLine) {
2028 scr_Resize(); 2160 scr_Resize();
2029 redrawwin(stdscr); 2161 redrawwin(stdscr);
2030 break; 2162 break;
2031 case KEY_RESIZE: 2163 case KEY_RESIZE:
2032 scr_Resize(); 2164 scr_Resize();
2165 break;
2166 case 27: // ESC
2167 scr_CheckAutoAway(TRUE);
2168 currentWindow = NULL;
2169 chatmode = FALSE;
2170 if (current_buddy)
2171 buddy_setflags(BUDDATA(current_buddy), ROSTER_FLAG_LOCK, FALSE);
2172 scr_RosterVisibility(1);
2173 scr_UpdateChatStatus(FALSE);
2174 top_panel(chatPanel);
2175 top_panel(inputPanel);
2176 update_panels();
2033 break; 2177 break;
2034 default: 2178 default:
2035 if (isprint(key)) { 2179 if (isprint(key)) {
2036 char tmpLine[INPUTLINE_LENGTH+1]; 2180 char tmpLine[INPUTLINE_LENGTH+1];
2037 2181