[console] Restore compatibility with "--key" values in existing scripts

Commit 3ef4f7e ("[console] Avoid overlap between special keys and
Unicode characters") renumbered the special key encoding to avoid
collisions with Unicode key values outside the ASCII range.  This
change broke backwards compatibility with existing scripts that
specify key values using e.g. "prompt --key" or "menu --key".

Restore compatibility with existing scripts by tweaking the special
key encoding so that the relative key value (i.e. the delta from
KEY_MIN) is numerically equal to the old pre-Unicode key value, and by
modifying parse_key() to accept a relative key value.

Reported-by: Sven Dreyer <sven@dreyer-net.de>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
diff --git a/src/core/parseopt.c b/src/core/parseopt.c
index 1dbfc7a..cd3b310 100644
--- a/src/core/parseopt.c
+++ b/src/core/parseopt.c
@@ -28,6 +28,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#include <ctype.h>
 #include <errno.h>
 #include <getopt.h>
 #include <ipxe/netdevice.h>
@@ -35,6 +36,7 @@
 #include <ipxe/settings.h>
 #include <ipxe/params.h>
 #include <ipxe/timer.h>
+#include <ipxe/keys.h>
 #include <ipxe/parseopt.h>
 #include <config/branding.h>
 
@@ -213,6 +215,7 @@
  * @ret rc		Return status code
  */
 int parse_key ( char *text, unsigned int *key ) {
+	int rc;
 
 	/* Interpret single characters as being a literal key character */
 	if ( text[0] && ! text[1] ) {
@@ -221,7 +224,17 @@
 	}
 
 	/* Otherwise, interpret as an integer */
-	return parse_integer ( text, key );
+	if ( ( rc = parse_integer ( text, key ) ) < 0 )
+		return rc;
+
+	/* For backwards compatibility with existing scripts, treat
+	 * integers between the ASCII range and special key range as
+	 * being relative special key values.
+	 */
+	if ( ( ! isascii ( *key ) ) && ( *key < KEY_MIN ) )
+		*key += KEY_MIN;
+
+	return 0;
 }
 
 /**
diff --git a/src/include/ctype.h b/src/include/ctype.h
index 0d79ecd..6fefd5d 100644
--- a/src/include/ctype.h
+++ b/src/include/ctype.h
@@ -10,6 +10,17 @@
 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 
 /**
+ * Check if character is ASCII
+ *
+ * @v character		Character
+ * @ret is_ascii	Character is an ASCII character
+ */
+static inline int isascii ( int character ) {
+
+	return ( character <= '\x7f' );
+}
+
+/**
  * Check if character is a decimal digit
  *
  * @v character		ASCII character
diff --git a/src/include/ipxe/keys.h b/src/include/ipxe/keys.h
index 2335691..49e65fa 100644
--- a/src/include/ipxe/keys.h
+++ b/src/include/ipxe/keys.h
@@ -54,6 +54,9 @@
  * The names are chosen to match those used by curses.  The values are
  * chosen to facilitate easy conversion from a received ANSI escape
  * sequence to a KEY_XXX constant.
+ *
+ * Note that the values are exposed to iPXE commands via parse_key()
+ * and therefore may not be changed without breaking existing scripts.
  */
 
 /**
@@ -79,7 +82,8 @@
  * @v terminator	ANSI escape sequence terminating character
  * @ret key		Key value
  */
-#define KEY_ANSI( n, terminator ) ( KEY_MIN + ( (n) << 8 ) + (terminator) )
+#define KEY_ANSI( n, terminator ) \
+	( KEY_MIN + ( ( (n) + 1 ) << 8 ) + (terminator) )
 
 /**
  * Extract ANSI escape sequence numeric portion
@@ -87,7 +91,7 @@
  * @v key		Key value (or relative key value)
  * @ret n		ANSI escape sequence numeric portion, or 0 for none
  */
-#define KEY_ANSI_N( key ) ( ( (key) >> 8 ) & 0xff )
+#define KEY_ANSI_N( key ) ( ( ( (key) >> 8 ) & 0xff ) - 1 )
 
 /**
  * Extract ANSI escape sequence terminating character