From e821783a18cf9ad18b92e38d39323be0b25be63d Mon Sep 17 00:00:00 2001
From: rswindell <>
Date: Fri, 8 May 2020 08:25:49 +0000
Subject: [PATCH] More mouse hot spot stuff: - User Defaults menu mousified -
 When all hot spots have scrolled off the screen, clear the hot spot list -
 Insert new hot spots in the front of the list so they will take precedence  
 over any previously defined duplicate hot spots - Numeric hot spot commands
 end in a carriage-return - No auto-acceptence of numbers when there are keys
 in the keyboard buffer - Baja UNGETKEY function now inserts keys into the
 "front" of the keyboard   buffer (next to be consumed) - Hot key @-code
 command text supports C-style escape sequences   (allows encoding of ctrl
 chars, spaces, etc.)

---
 src/sbbs3/atcodes.cpp  |  1 +
 src/sbbs3/exec.cpp     |  2 +-
 src/sbbs3/execfile.cpp | 12 +++++++++++-
 src/sbbs3/execmsg.cpp  |  6 ++++++
 src/sbbs3/getkey.cpp   |  2 +-
 src/sbbs3/getstr.cpp   |  2 +-
 src/sbbs3/inkey.cpp    | 18 +++++++++++++++---
 src/sbbs3/useredit.cpp | 36 +++++++++++++++++++++++++++++++-----
 8 files changed, 67 insertions(+), 12 deletions(-)

diff --git a/src/sbbs3/atcodes.cpp b/src/sbbs3/atcodes.cpp
index 703e41595b..193490e7fc 100644
--- a/src/sbbs3/atcodes.cpp
+++ b/src/sbbs3/atcodes.cpp
@@ -248,6 +248,7 @@ const char* sbbs_t::atcode(char* sp, char* str, size_t maxlen, long* pmode, bool
 			*tp = 0;
 			tp++;
 		}
+		c_unescape_str(tp);
 		add_hotspot(tp, column, column + strlen(sp) - 1, row);
 		return sp;
 	}
diff --git a/src/sbbs3/exec.cpp b/src/sbbs3/exec.cpp
index 6f5766ee1d..6fea283902 100644
--- a/src/sbbs3/exec.cpp
+++ b/src/sbbs3/exec.cpp
@@ -1917,7 +1917,7 @@ int sbbs_t::exec(csi_t *csi)
 				csi->logic=LOGIC_FALSE;
 			return(0);
 		case CS_UNGETKEY:
-			ungetkey(csi->cmd&0x7f);
+			ungetkey(csi->cmd&0x7f, /* insert: */true);
 			return(0);
 		case CS_UNGETSTR:
 			j=strlen(csi->str);
diff --git a/src/sbbs3/execfile.cpp b/src/sbbs3/execfile.cpp
index caa6e22124..58f1c845fe 100644
--- a/src/sbbs3/execfile.cpp
+++ b/src/sbbs3/execfile.cpp
@@ -42,7 +42,7 @@ int sbbs_t::exec_file(csi_t *csi)
 {
 	char	str[256],ch;
 	int		s;
-	uint 	i,j,x,y;
+	ulong 	i,j,x,y;
 	file_t	f;
 
 	switch(*(csi->ip++)) {
@@ -61,6 +61,7 @@ int sbbs_t::exec_file(csi_t *csi)
 							else outchar(' ');
 							if(i<9) outchar(' ');
 							if(i<99) outchar(' ');
+							add_hotspot(i+1);
 							bprintf(text[CfgLibLstFmt]
 								,i+1,cfg.lib[usrlib[i]]->lname); 
 						} 
@@ -87,6 +88,7 @@ int sbbs_t::exec_file(csi_t *csi)
 							,getfiles(&cfg,usrdir[j][i]));
 						if(i<9) outchar(' ');
 						if(i<99) outchar(' ');
+						add_hotspot(i+1);
 						bputs(str); 
 					} 
 				}
@@ -153,6 +155,8 @@ int sbbs_t::exec_file(csi_t *csi)
 				}
 				if(i<=usrdirs[curlib])
 					curdir[curlib]=i-1;
+				if(keybuf_level() && (ch=getkey(K_UPPER)) != '\r')
+					ungetkey(ch, /* insert: */true);
 				return(0); 
 			}
 			if((ch&0xf)<=(int)usrdirs[curlib] && (ch&0xf) && usrlibs)
@@ -187,10 +191,14 @@ int sbbs_t::exec_file(csi_t *csi)
 				i+=ch&0xf;
 				if(i<=usrlibs)
 					curlib=i-1;
+				if(keybuf_level() && (ch=getkey(K_UPPER)) != '\r')
+					ungetkey(ch, /* insert: */true);
 				return(0); 
 			}
 			if((ch&0xf)<=(int)usrlibs && (ch&0xf))
 				curlib=(ch&0xf)-1;
+			if(keybuf_level() && (ch=getkey(K_UPPER)) != '\r')
+				ungetkey(ch, /* insert: */true);
 			return(0);
 
 		case CS_FILE_SHOW_LIBRARIES:
@@ -204,6 +212,7 @@ int sbbs_t::exec_file(csi_t *csi)
 					outchar('*');
 				else outchar(' ');
 				if(i<9) outchar(' ');
+				add_hotspot(i+1);
 				bprintf(text[LibLstFmt],i+1
 					,cfg.lib[usrlib[i]]->lname,nulstr,usrdirs[i]); 
 			}
@@ -225,6 +234,7 @@ int sbbs_t::exec_file(csi_t *csi)
 					,getfiles(&cfg,usrdir[curlib][i]));
 				if(i<9) outchar(' ');
 				if(i<99) outchar(' ');
+				add_hotspot(i+1);
 				bputs(str); 
 			}
 			return(0);
diff --git a/src/sbbs3/execmsg.cpp b/src/sbbs3/execmsg.cpp
index b63155b8f5..71600cfe8b 100644
--- a/src/sbbs3/execmsg.cpp
+++ b/src/sbbs3/execmsg.cpp
@@ -151,6 +151,8 @@ int sbbs_t::exec_msg(csi_t *csi)
 				}
 				if(i<=usrsubs[curgrp])
 					cursub[curgrp]=i-1;
+				if(keybuf_level() && (ch=getkey(K_UPPER)) != '\r')
+					ungetkey(ch, /* insert: */true);
 				return(0); 
 			}
 			if((uint)(ch&0xf)<=usrsubs[curgrp] && (ch&0xf) && usrgrps)
@@ -185,10 +187,14 @@ int sbbs_t::exec_msg(csi_t *csi)
 				i+=ch&0xf;
 				if(i<=usrgrps)
 					curgrp=i-1;
+				if(keybuf_level() && (ch=getkey(K_UPPER)) != '\r')
+					ungetkey(ch, /* insert: */true);
 				return(0); 
 			}
 			if((uint)(ch&0xf)<=usrgrps && (ch&0xf))
 				curgrp=(ch&0xf)-1;
+			if(keybuf_level() && (ch=getkey(K_UPPER)) != '\r')
+				ungetkey(ch, /* insert: */true);
 			return(0);
 
 		case CS_MSG_SET_GROUP:
diff --git a/src/sbbs3/getkey.cpp b/src/sbbs3/getkey.cpp
index e304ff9921..356ab38944 100644
--- a/src/sbbs3/getkey.cpp
+++ b/src/sbbs3/getkey.cpp
@@ -516,7 +516,7 @@ long sbbs_t::getkeys(const char *keys, ulong max, long mode)
 			i+=ch&0xf;
 			if(!(mode&K_NOECHO))	
 				outchar(ch);
-			if(i*10>max && !(useron.misc&COLDKEYS)) {
+			if(i*10>max && !(useron.misc&COLDKEYS) && keybuf_level() < 1) {
 				if(!(mode&(K_NOECHO|K_NOCRLF))) {
 					attr(LIGHTGRAY);
 					CRLF;
diff --git a/src/sbbs3/getstr.cpp b/src/sbbs3/getstr.cpp
index ab7d37661c..87ba38d17c 100644
--- a/src/sbbs3/getstr.cpp
+++ b/src/sbbs3/getstr.cpp
@@ -694,7 +694,7 @@ long sbbs_t::getnum(ulong max, ulong dflt)
 			n++;
 			i+=ch&0xf;
 			outchar(ch);
-			if(i*10UL>max && !(useron.misc&COLDKEYS)) {
+			if(i*10UL>max && !(useron.misc&COLDKEYS) && keybuf_level() < 1) {
 				CRLF;
 				lncntr=0;
 				return(i); 
diff --git a/src/sbbs3/inkey.cpp b/src/sbbs3/inkey.cpp
index 6a6e036aac..67f0b56d0a 100644
--- a/src/sbbs3/inkey.cpp
+++ b/src/sbbs3/inkey.cpp
@@ -351,6 +351,13 @@ char sbbs_t::handle_ctrlkey(char ch, long mode)
 							continue;
 						if(x < spot->minx || x > spot->maxx)
 							continue;
+#ifdef _DEBUG
+						{
+							char dbg[128];
+							c_escape_str(spot->cmd, dbg, sizeof(dbg), /* Ctrl-only? */true);
+							lprintf(LOG_DEBUG, "Stuffing hot spot command into keybuf: '%s'", dbg);
+						}
+#endif
 						ungetstr(spot->cmd);
 						if(pause_inside)
 							return handle_ctrlkey(TERM_KEY_ABORT, mode);
@@ -463,7 +470,7 @@ void sbbs_t::add_hotspot(struct mouse_hotspot* spot)
 	lprintf(LOG_DEBUG, "Adding mouse hot spot %ld-%ld x %ld = '%s'"
 		,spot->minx, spot->maxx, spot->y, spot->cmd);
 #endif
-	listPushNodeData(&mouse_hotspots, spot, sizeof(*spot));
+	listInsertNodeData(&mouse_hotspots, spot, sizeof(*spot));
 	set_mouse(MOUSE_MODE_X10);
 }
 
@@ -481,15 +488,20 @@ void sbbs_t::clear_hotspots(void)
 void sbbs_t::scroll_hotspots(long count)
 {
 	long spots = 0;
+	long remain = 0;
 	for(list_node_t* node = mouse_hotspots.first; node != NULL; node = node->next) {
 		struct mouse_hotspot* spot = (struct mouse_hotspot*)node->data;
 		spot->y -= count;
 		spots++;
+		if(spot->y >= 0)
+			remain++;
 	}
 #ifdef _DEBUG
 	if(spots)
-		lprintf(LOG_DEBUG, "Scrolled %ld mouse hot-spots %ld rows", spots, count);
+		lprintf(LOG_DEBUG, "Scrolled %ld mouse hot-spots %ld rows (%ld remain)", spots, count, remain);
 #endif
+	if(remain < 1)
+		clear_hotspots();
 }
 
 void sbbs_t::add_hotspot(char cmd, long minx, long maxx, long y)
@@ -505,7 +517,7 @@ void sbbs_t::add_hotspot(char cmd, long minx, long maxx, long y)
 void sbbs_t::add_hotspot(ulong num, long minx, long maxx, long y)
 {
 	struct mouse_hotspot spot = {0};
-	SAFEPRINTF(spot.cmd, "%lu", num);
+	SAFEPRINTF(spot.cmd, "%lu\r", num);
 	spot.minx = minx;
 	spot.maxx = maxx;
 	spot.y = y;
diff --git a/src/sbbs3/useredit.cpp b/src/sbbs3/useredit.cpp
index a387358226..60696e737c 100644
--- a/src/sbbs3/useredit.cpp
+++ b/src/sbbs3/useredit.cpp
@@ -813,50 +813,73 @@ void sbbs_t::maindflts(user_t* user)
 							,term_type(term)
 							,term&COLOR ? (term&ICE_COLOR ? text[TerminalIceColor] : text[TerminalColor]) : text[TerminalMonochrome]
 							,term&SWAP_DELETE ? "DEL=BS" : nulstr);
+		add_hotspot('T');
 		bprintf(text[UserDefaultsTerminal], truncsp(str));
 		if(user->rows)
 			ultoa(user->rows,tmp,10);
 		else
 			SAFEPRINTF2(tmp,"%s%ld", text[TerminalAutoDetect], rows);
+		add_hotspot('L');
 		bprintf(text[UserDefaultsRows], tmp, text[TerminalRows]);
-		if(cfg.total_shells>1)
+		if(cfg.total_shells>1) {
+			add_hotspot('K');
 			bprintf(text[UserDefaultsCommandSet]
 				,cfg.shell[user->shell]->name);
-		if(cfg.total_xedits)
+		}
+		if(cfg.total_xedits) {
+			add_hotspot('E');
 			bprintf(text[UserDefaultsXeditor]
 				,user->xedit ? cfg.xedit[user->xedit-1]->name : "None");
+		}
+		add_hotspot('A');
 		bprintf(text[UserDefaultsArcType]
 			,user->tmpext);
+		add_hotspot('X');
 		bprintf(text[UserDefaultsMenuMode]
 			,user->misc&EXPERT ? text[On] : text[Off]);
+		add_hotspot('P');
 		bprintf(text[UserDefaultsPause]
 			,user->misc&UPAUSE ? text[On] : text[Off]);
+		add_hotspot('H');
 		bprintf(text[UserDefaultsHotKey]
 			,user->misc&COLDKEYS ? text[Off] : text[On]);
+		add_hotspot('S');
 		bprintf(text[UserDefaultsCursor]
 			,user->misc&SPIN ? text[On] : user->misc&NOPAUSESPIN ? text[Off] : "Pause Prompt Only");
+		add_hotspot('C');
 		bprintf(text[UserDefaultsCLS]
 			,user->misc&CLRSCRN ? text[On] : text[Off]);
+		add_hotspot('N');
 		bprintf(text[UserDefaultsAskNScan]
 			,user->misc&ASK_NSCAN ? text[On] : text[Off]);
+		add_hotspot('Y');
 		bprintf(text[UserDefaultsAskSScan]
 			,user->misc&ASK_SSCAN ? text[On] : text[Off]);
+		add_hotspot('F');
 		bprintf(text[UserDefaultsANFS]
 			,user->misc&ANFSCAN ? text[On] : text[Off]);
+		add_hotspot('R');
 		bprintf(text[UserDefaultsRemember]
 			,user->misc&CURSUB ? text[On] : text[Off]);
+		add_hotspot('B');
 		bprintf(text[UserDefaultsBatFlag]
 			,user->misc&BATCHFLAG ? text[On] : text[Off]);
-		if(cfg.sys_misc&SM_FWDTONET)
+		if(cfg.sys_misc&SM_FWDTONET) {
+			add_hotspot('M');
 			bprintf(text[UserDefaultsNetMail]
 				,user->misc&NETMAIL ? text[On] : text[Off]
 				,user->netmail);
-		if(startup->options&BBS_OPT_AUTO_LOGON && user->exempt&FLAG('V'))
+		}
+		if(startup->options&BBS_OPT_AUTO_LOGON && user->exempt&FLAG('V')) {
+			add_hotspot('I');
 			bprintf(text[UserDefaultsAutoLogon]
 			,user->misc&AUTOLOGON ? text[On] : text[Off]);
-		if(user->exempt&FLAG('Q') || user->misc&QUIET)
+		}
+		if(user->exempt&FLAG('Q') || user->misc&QUIET) {
+			add_hotspot('D');
 			bprintf(text[UserDefaultsQuiet]
 				,user->misc&QUIET ? text[On] : text[Off]);
+		}
 		SAFECOPY(str,"None");
 		for(i=0;i<cfg.total_prots;i++) {
 			if(user->prot==cfg.prot[i]->mnemonic) {
@@ -864,8 +887,10 @@ void sbbs_t::maindflts(user_t* user)
 				break;
 			}
 		}
+		add_hotspot('Z');
 		bprintf(text[UserDefaultsProtocol],str
 			,user->misc&AUTOHANG ? "(Auto-Hangup)":nulstr);
+		add_hotspot('W');
 		if(cfg.sys_misc&SM_PWEDIT && !(user->rest&FLAG('G')))
 			bputs(text[UserDefaultsPassword]);
 
@@ -885,6 +910,7 @@ void sbbs_t::maindflts(user_t* user)
 		if(cfg.total_shells>1)
 			strcat(str,"K");
 
+		add_hotspot('Q');
 		ch=(char)getkeys(str,0);
 		switch(ch) {
 			case 'T':
-- 
GitLab