From aafa0880b584aaa464b1409446782d56b166570d Mon Sep 17 00:00:00 2001
From: Benno Schulenberg <bensberg@telfort.nl>
Date: Mon, 9 Dec 2019 15:53:54 +0100
Subject: [PATCH] input: allow distinguishing shifted from unshifted Meta
 keystrokes

When the new option 'splitmeta' is set, nano will differentiate
between Meta+letter and Shift+Meta+letter.  In other words, typing
Alt+a will do something else than typing Alt+A, and binding M-a will
be different from binding M-A.
---
 src/global.c |  9 ++++++---
 src/nano.c   |  3 ++-
 src/nano.h   |  3 ++-
 src/rcfile.c |  8 +++++---
 src/winio.c  | 10 ++++++----
 5 files changed, 21 insertions(+), 12 deletions(-)

diff --git a/src/global.c b/src/global.c
index d0ab509b..263aca2b 100644
--- a/src/global.c
+++ b/src/global.c
@@ -501,9 +501,12 @@ int keycode_from_string(const char *keystring)
 	} else if (keystring[0] == 'M') {
 		if (strcasecmp(keystring, "M-Space") == 0)
 			return (int)' ';
-		if (keystring[1] == '-' && strlen(keystring) == 3)
-			return tolower((unsigned char)keystring[2]);
-		else
+		if (keystring[1] == '-' && strlen(keystring) == 3) {
+			if (ISSET(SPLIT_META))
+				return (unsigned char)keystring[2];
+			else
+				return tolower((unsigned char)keystring[2]);
+		} else
 			return -1;
 	} else if (keystring[0] == 'F') {
 		int fn = atoi(&keystring[1]);
diff --git a/src/nano.c b/src/nano.c
index 25a070b4..7ff5df91 100644
--- a/src/nano.c
+++ b/src/nano.c
@@ -1541,7 +1541,8 @@ void unbound_key(int code)
 		if (code == '[')
 			statusline(ALERT, _("Unbindable key: M-["));
 		else
-			statusline(ALERT, _("Unbound key: M-%c"), toupper(code));
+			statusline(ALERT, _("Unbound key: M-%c"),
+						ISSET(SPLIT_META) ? code : toupper(code));
 	} else if (code == ESC_CODE)
 		statusline(ALERT, _("Unbindable key: ^["));
 	else if (code < 0x20)
diff --git a/src/nano.h b/src/nano.h
index ba05501c..a568b419 100644
--- a/src/nano.h
+++ b/src/nano.h
@@ -537,7 +537,8 @@ enum
 	LET_THEM_ZAP,
 	BREAK_LONG_LINES,
 	JUMPY_SCROLLING,
-	EMPTY_LINE
+	EMPTY_LINE,
+	SPLIT_META
 };
 
 /* Flags for the menus in which a given function should be present. */
diff --git a/src/rcfile.c b/src/rcfile.c
index 469c4ce2..bb88656d 100644
--- a/src/rcfile.c
+++ b/src/rcfile.c
@@ -89,6 +89,7 @@ static const rcoption rcopts[] = {
 #ifdef ENABLE_SPELLER
 	{"speller", 0},
 #endif
+	{"splitmeta", SPLIT_META},
 	{"suspend", SUSPEND},
 	{"tabsize", 0},
 	{"tempfile", TEMP_FILE},
@@ -428,9 +429,10 @@ void parse_binding(char *ptr, bool dobind)
 	keycopy[0] = toupper((unsigned char)keycopy[0]);
 	keycopy[1] = toupper((unsigned char)keycopy[1]);
 	if (keycopy[0] == 'M' && keycopy[1] == '-') {
-		if (strlen(keycopy) > 2)
-			keycopy[2] = toupper((unsigned char)keycopy[2]);
-		else {
+		if (strlen(keycopy) > 2) {
+			if (!ISSET(SPLIT_META))
+				keycopy[2] = toupper((unsigned char)keycopy[2]);
+		} else {
 			jot_error(N_("Key name is too short"));
 			goto free_things;
 		}
diff --git a/src/winio.c b/src/winio.c
index b702a30c..d905aadd 100644
--- a/src/winio.c
+++ b/src/winio.c
@@ -401,9 +401,11 @@ int parse_kbinput(WINDOW *win)
 						key_buffer_len == 0 || *key_buffer == ESC_CODE) {
 				/* One escape followed by a single non-escape:
 				 * meta key sequence mode. */
-				if (!solitary || (keycode >= 0x20 && keycode < 0x7F))
+				if (!solitary || (keycode >= 0x20 && keycode < 0x7F)) {
 					meta_key = TRUE;
-				retval = tolower(keycode);
+					retval = ISSET(SPLIT_META) ? keycode : tolower(keycode);
+				} else
+					retval = tolower(keycode);
 			} else
 				/* One escape followed by a non-escape, and there
 				 * are more codes waiting: escape sequence mode. */
@@ -478,7 +480,7 @@ int parse_kbinput(WINDOW *win)
 						 * or control character sequence mode. */
 						if (!solitary) {
 							meta_key = TRUE;
-							retval = tolower(keycode);
+							retval = ISSET(SPLIT_META) ? keycode : tolower(keycode);
 						} else
 							retval = get_control_kbinput(keycode);
 					else {
@@ -507,7 +509,7 @@ int parse_kbinput(WINDOW *win)
 			if (key_buffer_len == 0) {
 				if (!solitary) {
 					meta_key = TRUE;
-					retval = tolower(keycode);
+					retval = ISSET(SPLIT_META) ? keycode : tolower(keycode);
 				} else
 					/* Three escapes followed by a non-escape, and no
 					 * other codes are waiting: normal input mode. */
-- 
2.24.0

