Merge pull request #1134 from BjossiAlfreds/con-ext

Console clipboard support and input nav
This commit is contained in:
Yamagi 2024-08-11 18:51:11 +02:00 committed by GitHub
commit 18f7541138
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 289 additions and 110 deletions

View file

@ -60,8 +60,8 @@ DrawAltStringScaled(int x, int y, char *s, float factor)
void
Key_ClearTyping(void)
{
key_lines[edit_line][1] = 0; /* clear any typing */
key_linepos = 1;
key_lines[edit_line][0] = '\0';
key_linepos = 0;
}
void
@ -471,6 +471,10 @@ Con_DrawInput(void)
int i;
float scale;
char *text;
char ch;
int txtlen;
int linepos;
int draw_icon;
if (cls.key_dest == key_menu)
{
@ -485,29 +489,50 @@ Con_DrawInput(void)
scale = SCR_GetConsoleScale();
text = key_lines[edit_line];
/* add the cursor frame */
text[key_linepos] = 10 + ((int)(cls.realtime >> 8) & 1);
/* fill out remainder with spaces */
for (i = key_linepos + 1; i < con.linewidth; i++)
{
text[i] = ' ';
}
linepos = key_linepos;
/* prestep if horizontally scrolling */
if (key_linepos >= con.linewidth)
if (linepos >= (con.linewidth - 1))
{
text += 1 + key_linepos - con.linewidth;
int ofs = 1 + linepos - con.linewidth;
text += ofs;
linepos -= ofs;
draw_icon = 0;
}
else
{
Draw_CharScaled(8 * scale, con.vislines - 22 * scale, CON_INPUT_INDICATOR, scale);
draw_icon = 1;
}
for (i = 0; i < con.linewidth; i++)
{
Draw_CharScaled(((i + 1) << 3) * scale, con.vislines - 22 * scale, text[i], scale);
}
txtlen = strlen(text);
/* remove cursor */
key_lines[edit_line][key_linepos] = 0;
for (i = 0; i < (con.linewidth - draw_icon); i++)
{
if (i == linepos)
{
if (cls.realtime & 8)
{
ch = CON_INPUT_CURSOR;
}
else
{
ch = (text[i] == '\0') ? 10 : text[i];
}
}
else if (i >= txtlen)
{
ch = ' ';
}
else
{
ch = text[i];
}
Draw_CharScaled(((i + 1 + draw_icon) << 3) * scale, con.vislines - 22 * scale, ch, scale);
}
}
/*

View file

@ -29,6 +29,10 @@
#include "header/client.h"
void Key_ClearTyping(void);
void IN_GetClipboardText(char *out, size_t n);
int IN_SetClipboardText(const char *s);
static cvar_t *cfg_unbindall;
/*
@ -268,9 +272,10 @@ keyname_t keynames[] = {
void
CompleteCommand(void)
{
char *cmd, *s;
char *cmd;
char *s;
s = key_lines[edit_line] + 1;
s = key_lines[edit_line];
if ((*s == '\\') || (*s == '/'))
{
@ -278,74 +283,68 @@ CompleteCommand(void)
}
cmd = Cmd_CompleteCommand(s);
if (cmd)
if (!cmd)
{
key_lines[edit_line][1] = '/';
strcpy(key_lines[edit_line] + 2, cmd);
key_linepos = strlen(cmd) + 2;
if (Cmd_IsComplete(cmd))
{
key_lines[edit_line][key_linepos] = ' ';
key_linepos++;
key_lines[edit_line][key_linepos] = 0;
}
else
{
key_lines[edit_line][key_linepos] = 0;
}
return;
}
return;
*key_lines[edit_line] = '/';
strcpy(key_lines[edit_line] + 1, cmd);
key_linepos = strlen(cmd) + 1;
if (Cmd_IsComplete(cmd))
{
key_lines[edit_line][key_linepos] = ' ';
key_linepos++;
}
key_lines[edit_line][key_linepos] = '\0';
}
void
CompleteMapNameCommand(void)
{
int i;
char *s, *t, *cmdArg;
char *s, *cmdArg;
const char *mapCmdString = "map ";
s = key_lines[edit_line] + 1;
s = key_lines[edit_line];
if ((*s == '\\') || (*s == '/'))
{
s++;
}
t = s;
for (i = 0; i < strlen(mapCmdString); i++)
if (strncmp(mapCmdString, s, strlen(mapCmdString)) != 0)
{
if (t[i] == mapCmdString[i])
{
s++;
}
else
{
return;
}
return;
}
cmdArg = Cmd_CompleteMapCommand(s);
cmdArg = Cmd_CompleteMapCommand(s + strlen(mapCmdString));
if (cmdArg)
{
key_lines[edit_line][1] = '/';
strcpy(key_lines[edit_line] + 2, mapCmdString);
snprintf(key_lines[edit_line], MAXCMDLINE, "/%s%s", mapCmdString, cmdArg);
key_linepos = strlen(key_lines[edit_line]);
strcpy(key_lines[edit_line] + key_linepos, cmdArg);
key_linepos = key_linepos + strlen(cmdArg);
}
}
/*
* Interactive line editing and console scrollback
*/
static int
IsInConsole(void)
{
return cls.key_dest == key_console ||
(cls.key_dest == key_game &&
(cls.state == ca_disconnected || cls.state == ca_connecting));
}
void
Key_Console(int key)
{
char txt[2];
char cliptext[256];
/*
* Ignore keypad in console to prevent duplicate
* entries through key presses processed as a
@ -375,35 +374,63 @@ Key_Console(int key)
break;
}
if (key == 'l')
if (keydown[K_CTRL])
{
if (keydown[K_CTRL])
if (key == 'l')
{
Cbuf_AddText("clear\n");
return;
}
if (key == 'c' || key == 'x')
{
if (*key_lines[edit_line] != '\0')
{
if (IN_SetClipboardText(key_lines[edit_line]))
{
Com_Printf("Copy to clipboard failed.\n");
}
else if (key == 'x')
{
Key_ClearTyping();
}
}
return;
}
if (key == 'v')
{
IN_GetClipboardText(cliptext, sizeof(cliptext));
if (*cliptext != '\0')
{
key_linepos += Q_strins(key_lines[edit_line], cliptext, key_linepos, MAXCMDLINE);
}
return;
}
}
if ((key == K_ENTER) || (key == K_KP_ENTER))
{
/* slash text are commands, else chat */
if ((key_lines[edit_line][1] == '\\') ||
(key_lines[edit_line][1] == '/'))
if ((*key_lines[edit_line] == '\\') || (*key_lines[edit_line] == '/'))
{
Cbuf_AddText(key_lines[edit_line] + 2); /* skip the > */
Cbuf_AddText(key_lines[edit_line] + 1); /* skip the > */
}
else
{
Cbuf_AddText(key_lines[edit_line] + 1); /* valid command */
Cbuf_AddText(key_lines[edit_line]); /* valid command */
}
Cbuf_AddText("\n");
Com_Printf("%s\n", key_lines[edit_line]);
Com_Printf("%c%s\n", CON_INPUT_INDICATOR, key_lines[edit_line]);
edit_line = (edit_line + 1) & (NUM_KEY_LINES - 1);
history_line = edit_line;
key_lines[edit_line][0] = ']';
key_lines[edit_line][1] = '\0';
key_linepos = 1;
Key_ClearTyping();
if (cls.state == ca_disconnected)
{
@ -423,12 +450,32 @@ Key_Console(int key)
return;
}
if ((key == K_BACKSPACE) || (key == K_LEFTARROW) ||
(key == K_KP_LEFTARROW) ||
if (key == K_LEFTARROW)
{
if (key_linepos > 0)
{
key_linepos--;
}
return;
}
if (key == K_RIGHTARROW)
{
if (key_lines[edit_line][key_linepos] != '\0')
{
key_linepos++;
}
return;
}
if ((key == K_BACKSPACE) ||
((key == 'h') && (keydown[K_CTRL])))
{
if (key_linepos > 1)
if (key_linepos > 0)
{
Q_strdel(key_lines[edit_line], key_linepos - 1, 1);
key_linepos--;
}
@ -437,9 +484,11 @@ Key_Console(int key)
if (key == K_DEL)
{
memmove(key_lines[edit_line] + key_linepos,
key_lines[edit_line] + key_linepos + 1,
sizeof(key_lines[edit_line]) - key_linepos - 1);
if (key_lines[edit_line][key_linepos] != '\0')
{
Q_strdel(key_lines[edit_line], key_linepos, 1);
}
return;
}
@ -451,7 +500,7 @@ Key_Console(int key)
history_line = (history_line - 1) & (NUM_KEY_LINES-1);
}
while (history_line != edit_line &&
!key_lines[history_line][1]);
key_lines[history_line][0] == '\0');
if (history_line == edit_line)
{
@ -459,7 +508,8 @@ Key_Console(int key)
}
memmove(key_lines[edit_line], key_lines[history_line], sizeof(key_lines[edit_line]));
key_linepos = (int)strlen(key_lines[edit_line]);
key_linepos = strlen(key_lines[edit_line]);
return;
}
@ -476,17 +526,16 @@ Key_Console(int key)
history_line = (history_line + 1) & (NUM_KEY_LINES-1);
}
while (history_line != edit_line &&
!key_lines[history_line][1]);
key_lines[history_line][0] == '\0');
if (history_line == edit_line)
{
key_lines[edit_line][0] = ']';
key_linepos = 1;
Key_ClearTyping();
}
else
{
memmove(key_lines[edit_line], key_lines[history_line], sizeof(key_lines[edit_line]));
key_linepos = (int)strlen(key_lines[edit_line]);
key_linepos = strlen(key_lines[edit_line]);
}
return;
@ -521,7 +570,7 @@ Key_Console(int key)
else
{
key_linepos = 1;
key_linepos = 0;
}
return;
@ -536,7 +585,7 @@ Key_Console(int key)
else
{
key_linepos = (int)strlen(key_lines[edit_line]);
key_linepos = strlen(key_lines[edit_line]);
}
return;
@ -547,32 +596,10 @@ Key_Console(int key)
return; /* non printable character */
}
if (key_linepos < MAXCMDLINE - 1)
{
int last;
int length;
*txt = key;
*(txt + 1) = '\0';
length = strlen(key_lines[edit_line]);
if (length >= MAXCMDLINE - 1)
{
return;
}
last = key_lines[edit_line][key_linepos];
memmove(key_lines[edit_line] + key_linepos + 1,
key_lines[edit_line] + key_linepos,
length - key_linepos);
key_lines[edit_line][key_linepos] = key;
key_linepos++;
if (!last)
{
key_lines[edit_line][key_linepos] = 0;
}
}
key_linepos += Q_strins(key_lines[edit_line], txt, key_linepos, MAXCMDLINE);
}
qboolean chat_team;
@ -953,7 +980,7 @@ Key_WriteConsoleHistory()
int lineIdx = (edit_line+i) & (NUM_KEY_LINES-1);
const char* line = key_lines[lineIdx];
if(line[1] != '\0' && strcmp(lastWrittenLine, line ) != 0)
if(*line != '\0' && strcmp(lastWrittenLine, line) != 0)
{
// if the line actually contains something besides the ] prompt,
// and is not identical to the last written line, write it to the file
@ -1000,6 +1027,7 @@ Key_ReadConsoleHistory()
history_line = i;
break;
}
// remove trailing newlines
int lastCharIdx = strlen(key_lines[i])-1;
while((key_lines[i][lastCharIdx] == '\n' || key_lines[i][lastCharIdx] == '\r') && lastCharIdx >= 0)
@ -1007,8 +1035,17 @@ Key_ReadConsoleHistory()
key_lines[i][lastCharIdx] = '\0';
--lastCharIdx;
}
/* backwards compatibility with old history files */
if(key_lines[i][0] == ']')
{
memmove(key_lines[i], key_lines[i] + 1, MAXCMDLINE - 1);
}
}
/* don't remember the input line */
Key_ClearTyping();
fclose(f);
}
@ -1032,12 +1069,11 @@ Key_Init(void)
int i;
for (i = 0; i < NUM_KEY_LINES; i++)
{
key_lines[i][0] = ']';
key_lines[i][1] = 0;
key_lines[i][0] = '\0';
}
// can't call Key_ReadConsoleHistory() here because FS_Gamedir() isn't set yet
key_linepos = 1;
key_linepos = 0;
/* init 128 bit ascii characters in console mode */
for (i = 32; i < 128; i++)
@ -1045,6 +1081,7 @@ Key_Init(void)
consolekeys[i] = true;
}
consolekeys[K_DEL] = true;
consolekeys[K_ENTER] = true;
consolekeys[K_KP_ENTER] = true;
consolekeys[K_TAB] = true;
@ -1380,6 +1417,15 @@ Key_Event(int key, qboolean down, qboolean special)
return;
}
/* FIXME: Better way to do CTRL+<key> actions in the console?
special should be set to true in this case.
*/
if (keydown[K_CTRL] && IsInConsole() &&
key >= 'a' && key <= 'z')
{
special = true;
}
/* All input subsystems handled after this point only
care for key down events (=> if(!down) returns above). */

View file

@ -27,6 +27,9 @@
#ifndef CL_HEADER_CONSOLE_H
#define CL_HEADER_CONSOLE_H
#define CON_INPUT_INDICATOR ']'
#define CON_INPUT_CURSOR 11
#define NUM_CON_TIMES 4
#define CON_TEXTSIZE 32768

View file

@ -59,4 +59,12 @@ void IN_Update(void);
*/
void In_FlushQueue(void);
/* Clipboard get/set */
/* Copy clipboard to buffer of size n */
void IN_GetClipboardText(char *out, size_t n);
/* Copy text to clipboard */
int IN_SetClipboardText(const char *s);
#endif

View file

@ -2412,3 +2412,25 @@ IN_Shutdown(void)
}
/* ------------------------------------------------------------------ */
void
IN_GetClipboardText(char *out, size_t n)
{
char *s = SDL_GetClipboardText();
if (!s || *s == '\0')
{
*out = '\0';
return;
}
Q_strlcpy(out, s, n - 1);
SDL_free(s);
}
int
IN_SetClipboardText(const char *s)
{
return SDL_SetClipboardText(s);
}

View file

@ -2410,3 +2410,25 @@ IN_Shutdown(void)
}
/* ------------------------------------------------------------------ */
void
IN_GetClipboardText(char *out, size_t n)
{
char *s = SDL_GetClipboardText();
if (!s || *s == '\0')
{
*out = '\0';
return;
}
Q_strlcpy(out, s, n - 1);
SDL_free(s);
}
int
IN_SetClipboardText(const char *s)
{
return SDL_SetClipboardText(s);
}

View file

@ -329,6 +329,13 @@ char *Q_strlwr(char *s);
int Q_strlcpy(char *dst, const char *src, int size);
int Q_strlcat(char *dst, const char *src, int size);
/* Delete n characters from s starting at index i */
void Q_strdel(char *s, size_t i, size_t n);
/* Insert src into dest starting at index i, total, n is the total size of the buffer */
/* Returns length of src on success, 0 if there is not enough space in dest for src */
size_t Q_strins(char *dest, const char *src, size_t i, size_t n);
/* ============================================= */
/* Unicode wrappers that also make sure it's a regular file around fopen(). */

View file

@ -1144,6 +1144,52 @@ Q_strlcat(char *dst, const char *src, int size)
return (d - dst) + Q_strlcpy(d, src, size);
}
void
Q_strdel(char *s, size_t i, size_t n)
{
size_t len;
if (!n)
{
return;
}
len = strlen(s);
if (i >= len || n > (len - i))
{
return;
}
memmove(s + i, s + i + n, len - i);
s[len - n] = '\0';
}
size_t
Q_strins(char *dest, const char *src, size_t i, size_t n)
{
size_t dlen;
size_t slen;
if (!src || *src == '\0')
{
return 0;
}
slen = strlen(src);
dlen = strlen(dest);
if (i > dlen || (dlen + slen + 1) > n)
{
return 0;
}
memmove(dest + i + slen, dest + i, dlen - i + 1);
memcpy(dest + i, src, slen);
return slen;
}
/*
* An unicode compatible fopen() Wrapper for Windows.
*/