shithub: qk2

Download patch

ref: 3ebd884ebb70433445614272d81f29ea66b90c75
parent: c80ce20775776c2a02b08e84566ef3aa887bcf62
author: qwx <qwx@sciops.net>
date: Tue Jul 20 09:29:33 EDT 2021

keys: implement key autorepeat

- in: just don't send first useless cons message on key down
- keys: cleaner autorepeat implementation, don't bother counting anything
- like for qw, set key_dest correctly for when we are on the console
and disconnected; don't autorepeat ingame; ignore special keys
- fix a few mouse grabbing instances
- remove "model key press hack", unused

--- a/cl_cin.c
+++ b/cl_cin.c
@@ -576,6 +576,7 @@
 		cl.cinematictime = 1;
 		SCR_EndLoadingPlaque ();
 		cls.state = ca_active;
+		CL_SetGameInput(key_game);
 		if (!cin.pic)
 		{
 			Com_Printf ("%s not found.\n", name);
@@ -602,6 +603,7 @@
 	SCR_EndLoadingPlaque ();
 
 	cls.state = ca_active;
+	CL_SetGameInput(key_game);
 
 	FS_Read (&width, 4, cl.cinematic_file);
 	FS_Read (&height, 4, cl.cinematic_file);
--- a/cl_ents.c
+++ b/cl_ents.c
@@ -739,6 +739,7 @@
 		if (cls.state != ca_active)
 		{
 			cls.state = ca_active;
+			CL_SetGameInput(key_game);
 			cl.force_refdef = true;
 			cl.predicted_origin[0] = cl.frame.playerstate.pmove.origin[0]*0.125;
 			cl.predicted_origin[1] = cl.frame.playerstate.pmove.origin[1]*0.125;
--- a/cl_main.c
+++ b/cl_main.c
@@ -76,7 +76,24 @@
 
 //======================================================================
 
+void
+CL_SetGameInput(k)
+{
+	switch(cls.key_dest = k){
+	case key_game:
+		IN_Grabm(1);
+		if(Cvar_VariableValue("maxclients") == 1 && Com_ServerState())
+			Cvar_Set("paused", "0");
+		break;
+	default:
+		IN_Grabm(0);
+		if(Cvar_VariableValue("maxclients") == 1 && Com_ServerState())
+			Cvar_Set("paused", "1");
+		break;
+	}
+}
 
+
 /*
 ====================
 CL_WriteDemoMessage
@@ -580,7 +597,7 @@
 	VectorClear (cl.refdef.blend);
 	re.CinematicSetPalette(NULL);
 
-	M_ForceMenuOff ();
+	M_ForceMenuOff(false);
 
 	cls.connect_time = 0;
 
--- a/console.c
+++ b/console.c
@@ -65,23 +65,7 @@
 
 	Key_ClearTyping ();
 	Con_ClearNotify ();
-
-	if (cls.key_dest == key_console)
-	{
-		M_ForceMenuOff ();
-		Cvar_Set ("paused", "0");
-		IN_Grabm (1);
-	}
-	else
-	{
-		M_ForceMenuOff ();
-		cls.key_dest = key_console;	
-
-		if (Cvar_VariableValue ("maxclients") == 1 
-			&& Com_ServerState ())
-			Cvar_Set ("paused", "1");
-		IN_Grabm (0);
-	}
+	M_ForceMenuOff(cls.key_dest == key_console && cls.state == ca_active);
 }
 
 /*
@@ -96,10 +80,7 @@
 	if (cls.key_dest == key_console)
 	{
 		if (cls.state == ca_active)
-		{
-			M_ForceMenuOff ();
-			cls.key_dest = key_game;
-		}
+			M_ForceMenuOff(true);
 	}
 	else
 		cls.key_dest = key_console;
--- a/dat.h
+++ b/dat.h
@@ -2457,7 +2457,6 @@
 	K_PAUSE = 255
 };
 extern char *keybindings[256];
-extern int key_repeats[256];
 extern int anykeydown;
 extern char chat_buffer[];
 extern int chat_bufferlen;
--- a/fns.h
+++ b/fns.h
@@ -288,7 +288,7 @@
 void	M_Keydown(int);
 void	M_Draw(void);
 void	M_Menu_Main_f(void);
-void	M_ForceMenuOff(void);
+void	M_ForceMenuOff(qboolean);
 void	M_AddToServerList(netadr_t, char *);
 void	CL_ParseInventory(void);
 void	CL_KeyInventory(int);
@@ -296,6 +296,7 @@
 void	CL_PredictMovement(void);
 qboolean	CL_CheckOrDownloadFile(char *);
 void	CL_AddNetgraph(void);
+void	CL_SetGameInput(int);
 
 void	SV_Init(void);
 void	SV_Shutdown(char *, qboolean);
@@ -584,7 +585,7 @@
 void	IN_Activate(qboolean);
 void	IN_Grabm(int);
 
-void	Key_Event(int, qboolean, unsigned);
+void	Key_Event(int, qboolean, qboolean, unsigned);
 void	Key_Init(void);
 void	Key_WriteBindings(FILE *);
 void	Key_SetBinding(int, char *);
--- a/in.c
+++ b/in.c
@@ -35,6 +35,7 @@
 struct Kev{
 	int key;
 	int down;
+	int isrep;
 };
 enum{
 	Nbuf	= 64
@@ -100,9 +101,9 @@
 	for(i = 0; i < 3; i++){
 		b = 1<<i;
 		if(btn & b && ~oldb & b)
-			Key_Event(K_MOUSE1+i, true, msec);
+			Key_Event(K_MOUSE1+i, true, false, msec);
 		else if(~btn & b && oldb & b)
-			Key_Event(K_MOUSE1+i, false, msec);
+			Key_Event(K_MOUSE1+i, false, false, msec);
 	}
 	oldb = btn & 7;
 	/* mwheelup and mwheeldn buttons are never held down */
@@ -109,8 +110,8 @@
 	for(i = 3; i < 5; i++){
 		b = 1<<i;
 		if(btn & b){
-			Key_Event(K_MOUSE1+i, true, msec);
-			Key_Event(K_MOUSE1+i, false, msec);
+			Key_Event(K_MOUSE1+i, true, false, msec);
+			Key_Event(K_MOUSE1+i, false, false, msec);
 		}
 	}
 }
@@ -127,7 +128,7 @@
 		IN_Grabm(m_windowed->value);
 	}
 	while((r = nbrecv(kchan, &ev)) > 0)
-		Key_Event(ev.key, ev.down, Sys_Milliseconds());
+		Key_Event(ev.key, ev.down, ev.isrep, Sys_Milliseconds());
 	if(r < 0)
 		sysfatal("KBD_Update:nbrecv: %r\n");
 	while((r = nbrecv(mchan, &m)) > 0){
@@ -253,14 +254,20 @@
 static void
 kproc(void *)
 {
-	int n, k, fd;
-	char buf[128], kdown[128], *s;
+	int n, k, fd, rep;
+	char buf[128], kdown[128], *s, *p;
 	Rune r;
-	Kev ev;
+	Kev ev, evc;
 
 	if((fd = open("/dev/kbd", OREAD)) < 0)
 		sysfatal("kproc: %r");
-	kdown[0] = kdown[1] = buf[0] = 0;
+	memset(buf, 0, sizeof buf);
+	memset(kdown, 0, sizeof kdown);
+	evc.key = K_ENTER;
+	evc.down = true;
+	evc.isrep = true;
+	ev.isrep = false;
+	rep = 0;
 	for(;;){
 		if(buf[0] != 0){
 			n = strlen(buf)+1;
@@ -267,48 +274,44 @@
 			memmove(buf, buf+n, sizeof(buf)-n);
 		}
 		if(buf[0] == 0){
-			n = read(fd, buf, sizeof(buf)-1);
-			if(n <= 0)
+			if((n = read(fd, buf, sizeof(buf)-1)) <= 0)
 				break;
 			buf[n-1] = 0;
 			buf[n] = 0;
 		}
-		switch(*buf){
+		switch(buf[0]){
 		case 'c':
+			if(rep++ > 0 && send(kchan, &evc) < 0)
+				threadexits(nil);
 		default:
 			continue;
 		case 'k':
+			ev.down = true;
 			s = buf+1;
-			while(*s){
-				s += chartorune(&r, s);
-				if(utfrune(kdown+1, r) == nil){
-					if(k = runetokey(r)){
-						ev.key = k;
-						ev.down = true;
-						if(send(kchan, &ev) < 0)
-							goto end;
-					}
-				}
-			}
+			p = kdown+1;
 			break;
 		case 'K':
+			ev.down = false;
 			s = kdown+1;
-			while(*s){
-				s += chartorune(&r, s);
-				if(utfrune(buf+1, r) == nil){
-					if(k = runetokey(r)){
-						ev.key = k;
-						ev.down = false;
-						if(send(kchan, &ev) < 0)
-							goto end;
-					}
+			p = buf+1;
+			break;
+		}
+		while(*s != 0){
+			s += chartorune(&r, s);
+			if(utfrune(p, r) == nil){
+				if((k = runetokey(r)) == 0)
+					continue;
+				ev.key = k;
+				if(send(kchan, &ev) < 0)
+					threadexits(nil);
+				if(ev.down){
+					evc.key = k;
+					rep = 0;
 				}
 			}
-			break;
 		}
 		strcpy(kdown, buf);
 	}
-end:;
 }
 
 static void
--- a/keys.c
+++ b/keys.c
@@ -20,12 +20,10 @@
 int		edit_line=0;
 int		history_line=0;
 
-int		key_waiting;
 char	*keybindings[256];
 qboolean	consolekeys[256];	// if true, can't be rebound while in console
 qboolean	menubound[256];	// if true, can't be rebound while in menu
 int		keyshift[256];		// key to map to if shift held down in console
-int		key_repeats[256];	// if > 1, it is autorepeating
 qboolean	keydown[256];
 
 typedef struct
@@ -722,39 +720,39 @@
 Should NOT be called during an interrupt!
 ===================
 */
-void Key_Event (int key, qboolean down, unsigned time)
+void Key_Event (int key, qboolean down, qboolean isrep, unsigned time)
 {
 	char	*kb;
 	char	cmd[1024];
 
-	// hack for modal presses
-	if (key_waiting == -1)
-	{
-		if (down)
-			key_waiting = key;
-		return;
-	}
-
 	// update auto-repeat status
 	if (down)
 	{
-		key_repeats[key]++;
-		if (key != K_BACKSPACE 
-			&& key != K_PAUSE 
-			&& key != K_PGUP 
-			&& key != K_KP_PGUP 
-			&& key != K_PGDN
-			&& key != K_KP_PGDN
-			&& key_repeats[key] > 1)
-			return;	// ignore most autorepeats
-			
+		if(isrep){
+			/* no autorepeat for anything ingame */
+			if(cls.key_dest == key_game)
+				return;
+			/* ignore hardcoded specially-handled keys */
+			switch(key){
+			case K_ESCAPE:
+			case '`':
+			case '~':
+			case K_ENTER:
+			case K_KP_ENTER:
+			case K_INS:		/* paste clipboard data */
+			case K_KP_INS:
+			case K_END:		/* jump to end */
+			case K_KP_END:
+			case K_TAB:		/* autocomplete */
+				return;
+			}
+			/* cons still sending repeats but key state has been cleared */
+			if(!keydown[key])
+				return;
+		}
 		if (key >= 200 && !keybindings[key])
 			Com_Printf ("%s is unbound, hit F4 to set.\n", Key_KeynumToString (key) );
 	}
-	else
-	{
-		key_repeats[key] = 0;
-	}
 
 	if (key == K_SHIFT)
 		shift_down = down;
@@ -803,15 +801,11 @@
 
 	// track if any key is down for BUTTON_ANY
 	keydown[key] = down;
-	if (down)
-	{
-		if (key_repeats[key] == 1)
-			anykeydown++;
-	}
-	else
-	{
+	if(down && !isrep)
+		anykeydown++;
+	else{
 		anykeydown--;
-		if (anykeydown < 0)
+		if(anykeydown < 0)
 			anykeydown = 0;
 	}
 
@@ -899,30 +893,12 @@
 {
 	int		i;
 
-	anykeydown = false;
+	anykeydown = 0;
 
 	for (i=0 ; i<256 ; i++)
 	{
-		if ( keydown[i] || key_repeats[i] )
-			Key_Event( i, false, 0 );
-		keydown[i] = 0;
-		key_repeats[i] = 0;
+		if(keydown[i])
+			Key_Event(i, false, false, 0);
+		keydown[i] = false;
 	}
 }
-
-
-/*
-===================
-Key_GetKey
-===================
-*/
-int Key_GetKey (void)
-{
-	key_waiting = -1;
-
-	while (key_waiting == -1)
-		Sys_SendKeyEvents ();
-
-	return key_waiting;
-}
-
--- a/menu.c
+++ b/menu.c
@@ -65,9 +65,7 @@
 {
 	int		i;
 
-	if (Cvar_VariableValue ("maxclients") == 1 
-		&& Com_ServerState ())
-		Cvar_Set ("paused", "1");
+	CL_SetGameInput(key_menu);
 
 	// if this menu is already present, drop back to that level
 	// to avoid stacking menus by hotkeys
@@ -91,19 +89,16 @@
 	m_keyfunc = key;
 
 	m_entersound = true;
-
-	cls.key_dest = key_menu;
 }
 
-void M_ForceMenuOff (void)
+void
+M_ForceMenuOff(qboolean set)
 {
 	m_drawfunc = 0;
 	m_keyfunc = 0;
-	cls.key_dest = key_game;
 	m_menudepth = 0;
-	Key_ClearStates ();
-	Cvar_Set ("paused", "0");
-	IN_Grabm (1);
+	Key_ClearStates();
+	CL_SetGameInput(set ? key_game : key_console);
 }
 
 void M_PopMenu (void)
@@ -117,7 +112,7 @@
 	m_keyfunc = m_layers[m_menudepth].key;
 
 	if (!m_menudepth)
-		M_ForceMenuOff ();
+		M_ForceMenuOff(cls.state == ca_active);
 }
 
 
@@ -469,7 +464,6 @@
 
 void M_Menu_Main_f (void)
 {
-	IN_Grabm (0);
 	M_PushMenu (M_Main_Draw, M_Main_Key);
 }
 
@@ -1140,8 +1134,7 @@
 	Key_ClearTyping ();
 	Con_ClearNotify ();
 
-	M_ForceMenuOff ();
-	cls.key_dest = key_console;
+	M_ForceMenuOff(false);
 }
 
 void Options_MenuInit( void )
@@ -1824,7 +1817,7 @@
 {
 	// disable updates and start the cinematic going
 	cl.servercount = -1;
-	M_ForceMenuOff ();
+	M_ForceMenuOff(true);
 	Cvar_SetValue( "deathmatch", 0 );
 	Cvar_SetValue( "coop", 0 );
 
@@ -1831,7 +1824,6 @@
 	Cvar_SetValue( "gamerules", 0 );		//PGM
 
 	Cbuf_AddText ("loading ; killserver ; wait ; newgame\n");
-	cls.key_dest = key_game;
 }
 
 static void EasyGameFunc( void * )
@@ -2003,7 +1995,7 @@
 
 	if ( m_savevalid[ a->generic.localdata[0] ] )
 		Cbuf_AddText (va("load save%i\n",  a->generic.localdata[0] ) );
-	M_ForceMenuOff ();
+	M_ForceMenuOff(true);
 }
 
 void LoadGame_MenuInit( void )
@@ -2074,7 +2066,7 @@
 	menuaction_t *a = ( menuaction_t * ) self;
 
 	Cbuf_AddText (va("save save%i\n", a->generic.localdata[0] ));
-	M_ForceMenuOff ();
+	M_ForceMenuOff(true);
 }
 
 void SaveGame_MenuDraw( void )
@@ -2192,7 +2184,7 @@
 
 	Com_sprintf (buffer, sizeof(buffer), "connect %s\n", NET_AdrToString (local_server_netadr[index]));
 	Cbuf_AddText (buffer);
-	M_ForceMenuOff ();
+	M_ForceMenuOff(true);
 }
 
 void AddressBookFunc( void * )
@@ -2444,8 +2436,7 @@
 	{
 		Cbuf_AddText (va("map %s\n", startmap));
 	}
-
-	M_ForceMenuOff ();
+	M_ForceMenuOff(true);
 }
 
 void StartServer_MenuInit( void )
--- a/vmenu.c
+++ b/vmenu.c
@@ -36,7 +36,7 @@
 {
 	Cvar_SetValue("vid_gamma", 0.8 - (gammaslide.curvalue/10.0 - 0.5) + 0.5);
 	Cvar_SetValue("vid_fullscreen", fullscrbox.curvalue);
-	M_ForceMenuOff();
+	M_ForceMenuOff(cls.state == ca_active);
 }
 
 void