]> granicus.if.org Git - nethack/commitdiff
partial fix for #K3869 - curses: meta characters
authorPatR <rankin@nethack.org>
Tue, 28 Feb 2023 18:14:25 +0000 (10:14 -0800)
committerPatR <rankin@nethack.org>
Tue, 28 Feb 2023 18:14:25 +0000 (10:14 -0800)
Meta-key fix for curses interface running on top of ncurses library.
Previously only digits and lower case letters would produce a meta
character when combined with Alt (or Option on Apple keyboards), now
it should work for any basic character (not arrows or other function
keys).  It only works on terminals that send two characters ESC k
for Alt+k but that is not a change in behavior.

curses interface running on top of PDcurses library uses different
code which isn't fixed by this.  The alt key fixup it does have was
already present in curses_read_char() and recently got duplicated in
curses_convert_keys().  At least one other routine calls the latter
so it was necessary, but curses_read_char() calls that routine so
doesn't need to keep its own copy of the fixup.

win/curses/cursdial.c
win/curses/cursmisc.c

index 8dff91223e1490f524f502535283535b8562eb56..2b16152704e54b63125a2707a34b8718eabfa8aa 100644 (file)
@@ -1541,7 +1541,7 @@ menu_get_selections(WINDOW *win, nhmenu *menu, int how)
             if (isdigit(curletter) && !groupaccels[curletter]) {
                 count = curses_get_count(curletter);
                 /* after count, we know some non-digit is already pending */
-                curletter = getch();
+                curletter = curses_getch();
                 count_letter = (count > 0L) ? curletter : '\0';
 
                 /* remove the count wind (erases last line of message wind) */
index 35860bd7fa04b6787989d1647c5eed951b9b6d09..4e4f3c38ef6d4b6128e70e93088e5ac6f45caad9 100644 (file)
@@ -44,35 +44,16 @@ int
 curses_read_char(void)
 {
     int ch;
-#if defined(ALT_0) || defined(ALT_9) || defined(ALT_A) || defined(ALT_Z)
-    int tmpch;
-#endif
 
     /* cancel message suppression; all messages have had a chance to be read */
     curses_got_input();
 
     ch = curses_getch();
-#if defined(ALT_0) || defined(ALT_9) || defined(ALT_A) || defined(ALT_Z)
-    tmpch = ch;
-#endif
     ch = curses_convert_keys(ch);
 
     if (ch == 0) {
         ch = '\033'; /* map NUL to ESC since nethack doesn't expect NUL */
     }
-#if defined(ALT_0) && defined(ALT_9)    /* PDCurses, maybe others */
-    if ((ch >= ALT_0) && (ch <= ALT_9)) {
-        tmpch = (ch - ALT_0) + '0';
-        ch = M(tmpch);
-    }
-#endif
-
-#if defined(ALT_A) && defined(ALT_Z)    /* PDCurses, maybe others */
-    if ((ch >= ALT_A) && (ch <= ALT_Z)) {
-        tmpch = (ch - ALT_A) + 'a';
-        ch = M(tmpch);
-    }
-#endif
 
 #ifdef KEY_RESIZE
     /* Handle resize events via get_nh_event, not this code */
@@ -882,6 +863,22 @@ curses_convert_keys(int key)
         ret = C('H');
         /*FALLTHRU*/
     default:
+#if defined(ALT_A) && defined(ALT_Z)
+        /* for PDcurses, but doesn't handle Alt+X for upper case X;
+           ncurses doesn't have ALT_x definitions so we achieve a similar
+           effect via parse_escape_sequence(), and that works for upper
+           case and other non-letter, non-digit keys */
+        if (ret >= ALT_A && ret <= ALT_Z) {
+            ret = (ret - ALT_A) + 'a';
+            ret = M(ret);
+        }
+#endif
+#if defined(ALT_0) && defined(ALT_9)
+        if (ret >= ALT_0 && ret <= ALT_9) {
+            ret = (ret - ALT_0) + '0';
+            ret = M(ret);
+        }
+#endif
         /* use key as-is unless it's out of normal char range */
         reject = ((uchar) ret < 1 || ret > 255);
         as_is = TRUE;
@@ -939,36 +936,6 @@ curses_convert_keys(int key)
         ret = iflags.num_pad ? '5' : 'g';
         break;
 #endif /* KEY_B2 */
-#ifdef PDCURSES
-    case ALT_A:
-    case ALT_B:
-    case ALT_C:
-    case ALT_D:
-    case ALT_E:
-    case ALT_F:
-    case ALT_G:
-    case ALT_H:
-    case ALT_I:
-    case ALT_J:
-    case ALT_K:
-    case ALT_L:
-    case ALT_M:
-    case ALT_N:
-    case ALT_O:
-    case ALT_P:
-    case ALT_Q:
-    case ALT_R:
-    case ALT_S:
-    case ALT_T:
-    case ALT_U:
-    case ALT_V:
-    case ALT_W:
-    case ALT_X:
-    case ALT_Y:
-    case ALT_Z:
-        ret = M((ret - ALT_A) + 'a');
-        break;
-#endif
     }
 
     /* phone layout is inverted, 123 on top and 789 on bottom; if player has
@@ -1073,6 +1040,9 @@ curses_mouse_support(int mode) /* 0: off, 1: on, 2: alternate on */
 #endif
 }
 
+/* caller just got an input character of ESC;
+   note: curses converts a lot of escape sequences to single values greater
+   than 255 and those won't look like ESC to caller so won't get here */
 static int
 parse_escape_sequence(void)
 {
@@ -1083,19 +1053,21 @@ parse_escape_sequence(void)
 
     ret = getch();
 
-    if (ret != ERR) {           /* Likely an escape sequence */
-        if ((ret >= 'a' && ret <= 'z') || (ret >= '0' && ret <= '9')) {
-            ret |= 0x80;        /* Meta key support for most terminals */
-        } else if (ret == 'O') {        /* Numeric keypad */
-            ret = getch();
-            if (ret != ERR && ret >= 112 && ret <= 121) {
-                ret = ret - 112 + '0';  /* Convert to number */
-            } else {
-                ret = '\033';   /* Escape */
-            }
-        }
+    if (ret == 'O') {               /* Numeric keypad */
+        /* ESC O <something> */
+        ret = getch();
+        if (ret >= 112 && ret <= 121)
+            return ret - 112 + '0'; /* Convert to number */
+
+        if (ret == ERR)
+            ret = 'O'; /* there was no third char; treat as ESC O below */
+    }
+
+    if (ret != ERR && ret <= 255) {
+        /* ESC <something>; effectively 'altmeta' behind player's back */
+        ret = M(ret);               /* Meta key support for most terminals */
     } else {
-        ret = '\033';           /* Just an escape character */
+        ret = '\033';               /* Just an escape character */
     }
 
     timeout(-1);