diff --git a/src/sbbs3/exec.cpp b/src/sbbs3/exec.cpp
index e88fbd19bf5431af243ca1d9acfe554143b16219..d90036e3c2d77e70a8e9723ee176d2533e5f22b5 100644
--- a/src/sbbs3/exec.cpp
+++ b/src/sbbs3/exec.cpp
@@ -562,7 +562,7 @@ js_OperationCallback(JSContext *cx)
 	return ret;
 }
 
-long sbbs_t::js_execfile(const char *cmd, const char* startup_dir, JSObject* scope)
+long sbbs_t::js_execfile(const char *cmd, const char* startup_dir, JSObject* scope, JSContext* js_cx)
 {
 	char*		p;
 	char*		args=NULL;
@@ -577,6 +577,9 @@ long sbbs_t::js_execfile(const char *cmd, const char* startup_dir, JSObject* sco
 	jsval		rval;
 	int32		result=0;
 
+	if(js_cx == NULL)
+		js_cx = this->js_cx;
+
 	if(js_cx==NULL) {
 		errormsg(WHERE,ERR_CHK,"JavaScript support",0);
 		errormsg(WHERE,ERR_EXEC,cmd,0);
@@ -720,9 +723,8 @@ long sbbs_t::js_execfile(const char *cmd, const char* startup_dir, JSObject* sco
 		JS_RemoveValueRoot(js_cx, &old_js_argc);
 	}
 
-	JS_GC(js_cx);
-
 	JS_ENDREQUEST(js_cx);
+	JS_GC(js_cx);
 
 	return(result);
 }
diff --git a/src/sbbs3/inkey.cpp b/src/sbbs3/inkey.cpp
index ae2ebaf177fa8c2819f60c015c34201da213eb56..68fc5fa98ad11793cca7d3179d511394404fa26e 100644
--- a/src/sbbs3/inkey.cpp
+++ b/src/sbbs3/inkey.cpp
@@ -183,10 +183,14 @@ char sbbs_t::handle_ctrlkey(char ch, long mode)
 				attr(LIGHTGRAY);
 				CRLF; 
 			}
-			if(cfg.hotkey[i]->cmd[0]=='?')
-				js_execfile(cmdstr(cfg.hotkey[i]->cmd+1,nulstr,nulstr,NULL), /* startup_dir: */NULL, /* scope: */js_glob);
-			else
-				external(cmdstr(cfg.hotkey[i]->cmd,nulstr,nulstr,NULL),0);
+			if(cfg.hotkey[i]->cmd[0]=='?') {
+				if(js_hotkey_cx == NULL) {
+					js_hotkey_cx = js_init(&js_hotkey_runtime, &js_hotkey_glob, "HotKey");
+					js_create_user_objects(js_hotkey_cx, js_hotkey_glob);
+				}
+				js_execfile(cmdstr(cfg.hotkey[i]->cmd+1,nulstr,nulstr,tmp), /* startup_dir: */NULL, /* scope: */js_hotkey_glob, js_hotkey_cx);
+			} else
+				external(cmdstr(cfg.hotkey[i]->cmd,nulstr,nulstr,tmp),0);
 			if(!(sys_status&SS_SPLITP)) {
 				CRLF;
 				RESTORELINE; 
diff --git a/src/sbbs3/logon.cpp b/src/sbbs3/logon.cpp
index 42f58075c8170aa6fc60ce99502c90982200fa9c..748109c1e93aace6f31da4d5c85ef5837b940b4f 100644
--- a/src/sbbs3/logon.cpp
+++ b/src/sbbs3/logon.cpp
@@ -66,7 +66,7 @@ bool sbbs_t::logon()
 	client_on(client_socket,&client,TRUE /* update */);
 
 #ifdef JAVASCRIPT
-	js_create_user_objects();
+	js_create_user_objects(js_cx, js_glob);
 #endif
 
 	if(useron.rest&FLAG('Q'))
diff --git a/src/sbbs3/main.cpp b/src/sbbs3/main.cpp
index 535d80875d37e29c4e32d5948605233d4e40fdd3..593a1764f05798c08b9917f5d22a9272d3eb62e3 100644
--- a/src/sbbs3/main.cpp
+++ b/src/sbbs3/main.cpp
@@ -1259,22 +1259,23 @@ js_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
 	JS_RESUMEREQUEST(cx, rc);
 }
 
-bool sbbs_t::js_init(ulong* stack_frame)
+JSContext* sbbs_t::js_init(JSRuntime** runtime, JSObject** glob, const char* desc)
 {
+	JSContext* js_cx;
+
 	if(startup->js.max_bytes==0)			startup->js.max_bytes=JAVASCRIPT_MAX_BYTES;
 	if(startup->js.cx_stack==0)				startup->js.cx_stack=JAVASCRIPT_CONTEXT_STACK;
 
-	lprintf(LOG_DEBUG,"JavaScript: Creating runtime: %lu bytes"
-		,startup->js.max_bytes);
-
-	if((js_runtime = jsrt_GetNew(startup->js.max_bytes, 1000, __FILE__, __LINE__))==NULL)
-		return(false);
+	lprintf(LOG_DEBUG,"JavaScript: Creating %s runtime: %lu bytes"
+		,desc, startup->js.max_bytes);
+	if((*runtime = jsrt_GetNew(startup->js.max_bytes, 1000, __FILE__, __LINE__)) == NULL)
+		return NULL;
 
-	lprintf(LOG_DEBUG,"JavaScript: Initializing context (stack: %lu bytes)"
-		,startup->js.cx_stack);
+	lprintf(LOG_DEBUG,"JavaScript: Initializing %s context (stack: %lu bytes)"
+		,desc, startup->js.cx_stack);
 
-    if((js_cx = JS_NewContext(js_runtime, startup->js.cx_stack))==NULL)
-		return(false);
+    if((js_cx = JS_NewContext(*runtime, startup->js.cx_stack))==NULL)
+		return NULL;
 	JS_BEGINREQUEST(js_cx);
 
 	memset(&js_callback,0,sizeof(js_callback));
@@ -1300,22 +1301,22 @@ bool sbbs_t::js_init(ulong* stack_frame)
 					,&startup->js
 					,&client, client_socket, -1					/* client */
 					,&js_server_props							/* server */
-					,&js_glob
+					,glob
 			))
 			break;
 		rooted=true;
 
 #ifdef BUILD_JSDOCS
-		js_CreateUifcObject(js_cx, js_glob);
-		js_CreateConioObject(js_cx, js_glob);
+		js_CreateUifcObject(js_cx, *glob);
+		js_CreateConioObject(js_cx, *glob);
 #endif
 
 		/* BBS Object */
-		if(js_CreateBbsObject(js_cx, js_glob)==NULL)
+		if(js_CreateBbsObject(js_cx, *glob)==NULL)
 			break;
 
 		/* Console Object */
-		if(js_CreateConsoleObject(js_cx, js_glob)==NULL)
+		if(js_CreateConsoleObject(js_cx, *glob)==NULL)
 			break;
 
 		success=true;
@@ -1324,16 +1325,16 @@ bool sbbs_t::js_init(ulong* stack_frame)
 
 	if(!success) {
 		if(rooted)
-			JS_RemoveObjectRoot(js_cx, &js_glob);
+			JS_RemoveObjectRoot(js_cx, glob);
 		JS_ENDREQUEST(js_cx);
 		JS_DestroyContext(js_cx);
 		js_cx=NULL;
-		return(false);
+		return NULL;
 	}
 	else
 		JS_ENDREQUEST(js_cx);
 
-	return(true);
+	return js_cx;
 }
 
 void sbbs_t::js_cleanup(void)
@@ -1353,17 +1354,36 @@ void sbbs_t::js_cleanup(void)
 		jsrt_Release(js_runtime);
 		js_runtime=NULL;
 	}
+
+	if(js_hotkey_cx!=NULL) {
+		lprintf(LOG_DEBUG,"JavaScript: Destroying HotKey context");
+		JS_BEGINREQUEST(js_hotkey_cx);
+		JS_RemoveObjectRoot(js_hotkey_cx, &js_hotkey_glob);
+		JS_ENDREQUEST(js_hotkey_cx);
+		JS_DestroyContext(js_hotkey_cx);
+		js_hotkey_cx=NULL;
+	}
+
+	if(js_hotkey_runtime!=NULL) {
+		lprintf(LOG_DEBUG,"JavaScript: Destroying HotKey runtime");
+		jsrt_Release(js_hotkey_runtime);
+		js_hotkey_runtime=NULL;
+	}
+
 }
 
-void sbbs_t::js_create_user_objects(void)
+bool sbbs_t::js_create_user_objects(JSContext* cx, JSObject* glob)
 {
-	if(js_cx==NULL)
-		return;
-
-	JS_BEGINREQUEST(js_cx);
-	if(!js_CreateUserObjects(js_cx, js_glob, &cfg, &useron, &client, NULL, subscan))
-		lprintf(LOG_ERR,"!JavaScript ERROR creating user objects");
-	JS_ENDREQUEST(js_cx);
+	bool result = false;
+	if(cx != NULL) {
+		JS_BEGINREQUEST(cx);
+		if(!js_CreateUserObjects(cx, glob, &cfg, &useron, &client, NULL, subscan))
+			lprintf(LOG_ERR,"!JavaScript ERROR creating user objects");
+		else
+			result = true;
+		JS_ENDREQUEST(cx);
+	}
+	return result;
 }
 
 extern "C" BOOL DLLCALL js_CreateCommonObjects(JSContext* js_cx
@@ -2490,7 +2510,6 @@ void output_thread(void* arg)
 
 void event_thread(void* arg)
 {
-	ulong		stack_frame;
 	char		str[MAX_PATH+1];
 	char		bat_list[MAX_PATH+1];
 	char		semfile[MAX_PATH+1];
@@ -2524,7 +2543,7 @@ void event_thread(void* arg)
 
 #ifdef JAVASCRIPT
 	if(!(startup->options&BBS_OPT_NO_JAVASCRIPT)) {
-		if(!sbbs->js_init(&stack_frame)) /* This must be done in the context of the events thread */
+		if((sbbs->js_cx = sbbs->js_init(&sbbs->js_runtime, &sbbs->js_glob, "event")) == NULL) /* This must be done in the context of the events thread */
 			lprintf(LOG_ERR,"!JavaScript Initialization FAILURE");
 	}
 #endif
@@ -3389,6 +3408,8 @@ sbbs_t::sbbs_t(ushort node_num, union xp_sockaddr *addr, size_t addr_len, const
 #ifdef JAVASCRIPT
 	js_runtime=NULL;	/* runtime */
 	js_cx=NULL;			/* context */
+	js_hotkey_runtime = NULL;
+	js_hotkey_cx = NULL;
 #endif
 
 	for(i=0;i<TOTAL_TEXT;i++)
@@ -4407,7 +4428,6 @@ void sbbs_t::logoffstats()
 
 void node_thread(void* arg)
 {
-	ulong			stack_frame;
 	char			str[128];
 	int				file;
 	uint			curshell=0;
@@ -4427,7 +4447,7 @@ void node_thread(void* arg)
 
 #ifdef JAVASCRIPT
 	if(!(startup->options&BBS_OPT_NO_JAVASCRIPT)) {
-		if(!sbbs->js_init(&stack_frame)) /* This must be done in the context of the node thread */
+		if((sbbs->js_cx = sbbs->js_init(&sbbs->js_runtime, &sbbs->js_glob, "node")) == NULL) /* This must be done in the context of the node thread */
 			lprintf(LOG_ERR,"Node %d !JavaScript Initialization FAILURE",sbbs->cfg.node_num);
 	}
 #endif
diff --git a/src/sbbs3/newuser.cpp b/src/sbbs3/newuser.cpp
index d24eef995818709346b75a8452b34ed913454737..a868be49c131117fc55984edb41a8484fb25ae8e 100644
--- a/src/sbbs3/newuser.cpp
+++ b/src/sbbs3/newuser.cpp
@@ -474,7 +474,7 @@ BOOL sbbs_t::newuser()
 	answertime=starttime=time(NULL);	  /* set answertime to now */
 
 #ifdef JAVASCRIPT
-	js_create_user_objects();
+	js_create_user_objects(js_cx, js_glob);
 #endif
 
 	if(cfg.newuser_mod[0])
diff --git a/src/sbbs3/sbbs.h b/src/sbbs3/sbbs.h
index 0e497bbaf24ddb6e31cfbd0f532b5d652052f1d9..e97aafa67339434aa2f016845fe008b6fa781865 100644
--- a/src/sbbs3/sbbs.h
+++ b/src/sbbs3/sbbs.h
@@ -394,11 +394,14 @@ public:
 	JSRuntime*		js_runtime;
 	JSContext*		js_cx;
 	JSObject*		js_glob;
+	JSRuntime*		js_hotkey_runtime;
+	JSContext*		js_hotkey_cx;
+	JSObject*		js_hotkey_glob;
 	js_callback_t	js_callback;
-	long			js_execfile(const char *fname, const char* startup_dir, JSObject* scope=NULL);
-	bool			js_init(ulong* stack_frame);
+	long			js_execfile(const char *fname, const char* startup_dir, JSObject* scope = NULL, JSContext* cx = NULL);
+	JSContext*		js_init(JSRuntime**, JSObject**, const char* desc);
 	void			js_cleanup(void);
-	void			js_create_user_objects(void);
+	bool			js_create_user_objects(JSContext*, JSObject* glob);
 
 #endif