diff --git a/src/sbbs3/atcodes.cpp b/src/sbbs3/atcodes.cpp
index 086cb2fe82eca93d05ffe9ee2df8e78f65c2a416..1760b8b223d282416bea9a8589af6faeaef44d18 100644
--- a/src/sbbs3/atcodes.cpp
+++ b/src/sbbs3/atcodes.cpp
@@ -338,7 +338,7 @@ const char* sbbs_t::atcode(const char* sp, char* str, size_t maxlen, int* pmode,
 		else if(stricmp(sp, "off") == 0)
 			hot_attr = 0;
 		else
-			hot_attr = attrstr(sp);
+			hot_attr = strtoattr(sp, /* endptr: */NULL);
 		return nulstr;
 	}
 	if(strcmp(sp, "CLEAR_HOT") == 0) {
@@ -346,6 +346,17 @@ const char* sbbs_t::atcode(const char* sp, char* str, size_t maxlen, int* pmode,
 		return nulstr;
 	}
 
+	if(strncmp(sp, "MNE:", 4) == 0) {	// Mnemonic attribute control
+		sp += 4;
+		mneattr_low = strtoattr(sp, &tp);
+		mneattr_high = mneattr_low ^ HIGH;
+		if(tp != NULL && *tp != '\0')
+			mneattr_high = strtoattr(tp + 1, &tp);
+		if(tp != NULL && *tp != '\0')
+			mneattr_cmd = strtoattr(tp + 1, NULL);
+		return nulstr;
+	}
+
 	if(strncmp(sp, "U+", 2) == 0) {	// UNICODE
 		enum unicode_codepoint codepoint = (enum unicode_codepoint)strtoul(sp + 2, &tp, 16);
 		if(tp == NULL || *tp == 0)
diff --git a/src/sbbs3/getkey.cpp b/src/sbbs3/getkey.cpp
index fedcccd048c28c46d64b3f4858c7ce3efebbf15e..77712fe128c470d8ef0e91114e9ccf80fb048dd2 100644
--- a/src/sbbs3/getkey.cpp
+++ b/src/sbbs3/getkey.cpp
@@ -191,12 +191,17 @@ void sbbs_t::mnemonics(const char *instr)
 			bputs(instr);
 			return; 
 		}
-		attr(cfg.color[clr_mnelow]); 
 	}
+
+	mneattr_low = cfg.color[clr_mnelow];
+	mneattr_high = cfg.color[clr_mnehigh];
+	mneattr_cmd = cfg.color[clr_mnecmd];
+
 	char str[256];
 	expand_atcodes(instr, str, sizeof str);
 	l=0L;
 	int term = term_supports();
+	attr(mneattr_low);
 
 	while(str[l]) {
 		if(str[l]=='~' && str[l+1] < ' ') {
@@ -208,28 +213,28 @@ void sbbs_t::mnemonics(const char *instr)
 				outchar('(');
 			l++;
 			if(!ctrl_a_codes)
-				attr(cfg.color[clr_mnehigh]);
+				attr(mneattr_high);
 			add_hotspot(str[l], /* hungry: */true);
 			outchar(str[l]);
 			l++;
 			if(!(term&(ANSI|PETSCII)))
 				outchar(')');
 			if(!ctrl_a_codes)
-				attr(cfg.color[clr_mnelow]); 
+				attr(mneattr_low);
 		}
 		else if(str[l]=='`' && str[l+1]!=0) {
 			if(!(term&(ANSI|PETSCII)))
 				outchar('[');
 			l++;
 			if(!ctrl_a_codes)
-				attr(cfg.color[clr_mnehigh]);
+				attr(mneattr_high);
 			add_hotspot(str[l], /* hungry: */false);
 			outchar(str[l]);
 			l++;
 			if(!(term&(ANSI|PETSCII)))
 				outchar(']');
 			if(!ctrl_a_codes)
-				attr(cfg.color[clr_mnelow]); 
+				attr(mneattr_low);
 		}
 		else {
 			if(str[l]==CTRL_A && str[l+1]!=0) {
@@ -243,7 +248,7 @@ void sbbs_t::mnemonics(const char *instr)
 		} 
 	}
 	if(!ctrl_a_codes)
-		attr(cfg.color[clr_mnecmd]);
+		attr(mneattr_cmd);
 }
 
 /****************************************************************************/
diff --git a/src/sbbs3/js_console.cpp b/src/sbbs3/js_console.cpp
index 1e1c6a50cde0f4aab06560514f48a400e30a1399..8fc46b1864109f9d3fc934a4ee768dfc95159209 100644
--- a/src/sbbs3/js_console.cpp
+++ b/src/sbbs3/js_console.cpp
@@ -293,7 +293,7 @@ static JSBool js_console_set(JSContext *cx, JSObject *obj, jsid id, JSBool stric
 				JSVALUE_TO_MSTRING(cx, *vp, sval, NULL);
 				if(sval==NULL)
 					break;
-				val=attrstr(sval);
+				val=strtoattr(sval, /* endptr: */NULL);
 				free(sval);
 			}
 			rc=JS_SUSPENDREQUEST(cx);
@@ -1112,7 +1112,7 @@ js_set_attr(JSContext* cx, sbbs_t* sbbs, jsval val)
 		JSVALUE_TO_MSTRING(cx, val, as, NULL);
 		if(as==NULL)
 			return JS_FALSE;
-		attr=attrstr(as);
+		attr=strtoattr(as, /* endptr: */NULL);
 		free(as);
 	}
 	else {
diff --git a/src/sbbs3/load_cfg.c b/src/sbbs3/load_cfg.c
index 5c196088c595c9968917ed5c2dcb2275589ccbe7..f6b4c545d600983e9fd691add60f406c59ae3fa9 100644
--- a/src/sbbs3/load_cfg.c
+++ b/src/sbbs3/load_cfg.c
@@ -440,7 +440,7 @@ bool read_attr_cfg(scfg_t* cfg, char* error, size_t maxerrlen)
 				break;
 			cfg->color=clr;
 		}
-		cfg->color[cfg->total_colors]=attrstr(str); 
+		cfg->color[cfg->total_colors]=strtoattr(str, /* endptr: */NULL); 
 	}
 	fclose(instream);
 	if(cfg->total_colors<MIN_COLORS)
diff --git a/src/sbbs3/sbbs.h b/src/sbbs3/sbbs.h
index 6741bcca33dbdb1e1b95847b68cf76354132e968..983f8eedaa07098d29482ef79ced4403721104bf 100644
--- a/src/sbbs3/sbbs.h
+++ b/src/sbbs3/sbbs.h
@@ -624,6 +624,9 @@ public:
 	uint	curatr = LIGHTGRAY;	/* Current Text Attributes Always */
 	uint	attr_stack[64]{};	/* Saved attributes (stack) */
 	int 	attr_sp = 0;	/* Attribute stack pointer */
+	uint	mneattr_low = LIGHTGRAY;
+	uint	mneattr_high = LIGHTGRAY;
+	uint	mneattr_cmd = LIGHTGRAY;
 	int 	lncntr = 0; 	/* Line Counter - for PAUSE */
 	bool	msghdr_tos = false;	/* Message header was displayed at Top of Screen */
 	int		row=0;			/* Current row */
diff --git a/src/sbbs3/scfglib.h b/src/sbbs3/scfglib.h
index ccdad5f687b8f99bd6c97808d30c00d8059d2a36..f46c405f9d3e8bbdbe67cd10d4e36348c1f65422 100644
--- a/src/sbbs3/scfglib.h
+++ b/src/sbbs3/scfglib.h
@@ -51,7 +51,7 @@ DLLEXPORT void	free_chat_cfg(scfg_t* cfg);
 
 DLLEXPORT uint32_t aftou32(const char *str);      /* Converts flag string to uint32_t */
 DLLEXPORT char*	u32toaf(uint32_t t, char *str); /* Converts uint32_t to flag string */
-uint	attrstr(const char *str);		/* Convert ATTR string into attribute int */
+uint	strtoattr(const char *str, char** endptr);		/* Convert ATTR string into attribute int */
 
 int		getdirnum(scfg_t*, const char* code);
 int		getlibnum(scfg_t*, const char* code);
diff --git a/src/sbbs3/scfglib2.c b/src/sbbs3/scfglib2.c
index 279a9e965647fa9d2b5d4a1b6c6309b0b37eba93..72f4cf9a9f4e58f839df0be320f95805f19cd0be 100644
--- a/src/sbbs3/scfglib2.c
+++ b/src/sbbs3/scfglib2.c
@@ -768,7 +768,7 @@ char *u32toaf(uint32_t l,char *str)
 /****************************************************************************/
 /* Returns the actual attribute code from a string of ATTR characters       */
 /****************************************************************************/
-uint attrstr(const char *str)
+uint strtoattr(const char *str, char** endptr)
 {
 	int atr;
 	ulong l=0;
@@ -833,9 +833,15 @@ uint attrstr(const char *str)
 			case '7':	/* White Background */
 				atr=(uchar)((atr&0x8f)|BG_LIGHTGRAY);
 				break;
+			default:
+				if(endptr != NULL)
+					*endptr = (char*)str + l;
+				return atr;
 			}
 		l++;
 	}
+	if(endptr != NULL)
+		*endptr = (char*)str + l;
 	return(atr);
 }