Skip to content

Commit

Permalink
add arrow key support for dedicated console
Browse files Browse the repository at this point in the history
  • Loading branch information
timbergeron committed Dec 7, 2024
1 parent 39ce361 commit ceb63be
Show file tree
Hide file tree
Showing 2 changed files with 235 additions and 68 deletions.
185 changes: 146 additions & 39 deletions Quake/sys_sdl_unix.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "SDL.h"
#endif

#include <termios.h> // woods #arrowkeys
#include <unistd.h> // woods #arrowkeys

qboolean isDedicated;
cvar_t sys_throttle = {"sys_throttle", "0.02", CVAR_ARCHIVE};
Expand Down Expand Up @@ -469,52 +471,157 @@ double Sys_DoubleTime (void)
return SDL_GetTicks() / 1000.0;
}

const char *Sys_ConsoleInput (void)
const char *Sys_ConsoleInput (void) // woods #arrowkeys
{
static char con_text[256];
static int textlen;
static int cursor_pos; // Track cursor position separately from text length
char c;
fd_set set;
struct timeval timeout;

FD_ZERO (&set);
static struct termios orig_termios, raw_termios;
static qboolean term_setup = false;

// Set up terminal once
if (!term_setup)
{
if (tcgetattr(0, &orig_termios) != -1)
{
raw_termios = orig_termios;
raw_termios.c_lflag &= ~(ICANON | ECHO); // Disable canonical mode and echo
raw_termios.c_cc[VMIN] = 1;
raw_termios.c_cc[VTIME] = 0;
tcsetattr(0, TCSANOW, &raw_termios);
term_setup = true;
cursor_pos = 0;
}
}

FD_ZERO (&set);
FD_SET (0, &set); // stdin
timeout.tv_sec = 0;
timeout.tv_usec = 0;

while (select (1, &set, NULL, NULL, &timeout))
{
read (0, &c, 1);
if (c == '\n' || c == '\r')
{
con_text[textlen] = '\0';
textlen = 0;
return con_text;
}
else if (c == 8)
{
if (textlen)
{
textlen--;
con_text[textlen] = '\0';
}
continue;
}
con_text[textlen] = c;
textlen++;
if (textlen < (int) sizeof(con_text))
con_text[textlen] = '\0';
else
{
// buffer is full
textlen = 0;
con_text[0] = '\0';
Sys_Printf("\nConsole input too long!\n");
break;
}
}

return NULL;
timeout.tv_sec = 0;
timeout.tv_usec = 0;

while (select (1, &set, NULL, NULL, &timeout))
{
ssize_t len = read(0, &c, 1);
if (len != 1)
continue;

// Handle escape sequences for arrow keys
if (c == 27) // ESC character
{
char seq[3] = {0};
struct timeval seq_timeout;
seq_timeout.tv_sec = 0;
seq_timeout.tv_usec = 10000;

FD_ZERO(&set);
FD_SET(0, &set);
if (select(1, &set, NULL, NULL, &seq_timeout) > 0)
{
len = read(0, seq, 1);
if (len == 1 && seq[0] == '[')
{
FD_ZERO(&set);
FD_SET(0, &set);
if (select(1, &set, NULL, NULL, &seq_timeout) > 0)
{
len = read(0, seq + 1, 1);
if (len == 1)
{
switch (seq[1])
{
case 'D': // Left arrow
if (cursor_pos > 0)
{
cursor_pos--;
write(1, "\b", 1);
}
continue;
case 'C': // Right arrow
if (cursor_pos < textlen)
{
write(1, &con_text[cursor_pos], 1);
cursor_pos++;
}
continue;
case 'A': // Up arrow
case 'B': // Down arrow
continue;
}
}
}
}
}
continue;
}

if (c == '\n' || c == '\r')
{
write(1, "\n", 1);
con_text[textlen] = '\0';
textlen = 0;
cursor_pos = 0;
return con_text;
}
else if (c == 8 || c == 127) // backspace or delete
{
if (cursor_pos > 0)
{
// Move characters after cursor back by one position
memmove(&con_text[cursor_pos - 1], &con_text[cursor_pos], textlen - cursor_pos);
cursor_pos--;
textlen--;

// Rewrite the line from cursor position
write(1, "\b", 1);
if (cursor_pos < textlen)
{
write(1, &con_text[cursor_pos], textlen - cursor_pos);
write(1, " ", 1); // Clear last character
// Move cursor back to position
for (int i = 0; i < textlen - cursor_pos + 1; i++)
write(1, "\b", 1);
}
else
{
write(1, " \b", 2); // Clear last character
}
}
continue;
}

if (textlen < sizeof(con_text)-1 && c >= 32 && c < 127)
{
// Insert character at cursor position
if (cursor_pos < textlen)
{
// Make room for new character
memmove(&con_text[cursor_pos + 1], &con_text[cursor_pos], textlen - cursor_pos);
con_text[cursor_pos] = c;
textlen++;

// Write the new character and the rest of the line
write(1, &con_text[cursor_pos], textlen - cursor_pos);

// Move cursor back to just after inserted character
cursor_pos++;
for (int i = 0; i < textlen - cursor_pos; i++)
write(1, "\b", 1);
}
else
{
// Append character at end of line
con_text[textlen] = c;
write(1, &c, 1);
textlen++;
cursor_pos++;
}
}
}

return NULL;
}

void Sys_Sleep (unsigned long msecs)
Expand Down
118 changes: 89 additions & 29 deletions Quake/sys_sdl_win.c
Original file line number Diff line number Diff line change
Expand Up @@ -518,10 +518,11 @@ void Sys_Image_BGRA_To_Clipboard(byte* bmbits, int width, int height, int size)
}
#endif

const char *Sys_ConsoleInput (void)
const char *Sys_ConsoleInput (void) // woods #arrowkeys
{
static char con_text[256];
static int textlen;
static int cursor_pos;
INPUT_RECORD recs[1024];
int ch;
DWORD dummy, numread, numevents;
Expand All @@ -542,42 +543,101 @@ const char *Sys_ConsoleInput (void)

if (recs[0].EventType == KEY_EVENT)
{
if (recs[0].Event.KeyEvent.bKeyDown == FALSE)
{
ch = recs[0].Event.KeyEvent.uChar.AsciiChar;

switch (ch)
if (recs[0].Event.KeyEvent.bKeyDown == FALSE)
{
case '\r':
WriteFile(houtput, "\r\n", 2, &dummy, NULL);

if (textlen != 0)
if (recs[0].Event.KeyEvent.wVirtualKeyCode == VK_LEFT)
{
con_text[textlen] = 0;
textlen = 0;
return con_text;
if (cursor_pos > 0)
{
cursor_pos--;
WriteFile(houtput, "\b", 1, &dummy, NULL);
}
continue;
}
else if (recs[0].Event.KeyEvent.wVirtualKeyCode == VK_RIGHT)
{
if (cursor_pos < textlen)
{
WriteFile(houtput, &con_text[cursor_pos], 1, &dummy, NULL);
cursor_pos++;
}
continue;
}

break;

case '\b':
WriteFile(houtput, "\b \b", 3, &dummy, NULL);
if (textlen != 0)
textlen--;

break;
ch = recs[0].Event.KeyEvent.uChar.AsciiChar;

default:
if (ch >= ' ')
switch (ch)
{
WriteFile(houtput, &ch, 1, &dummy, NULL);
con_text[textlen] = ch;
textlen = (textlen + 1) & 0xff;
case '\r':
WriteFile(houtput, "\r\n", 2, &dummy, NULL);

if (textlen != 0)
{
con_text[textlen] = 0;
textlen = 0;
cursor_pos = 0; // woods #arrowkeys
return con_text;
}

break;

case '\b':
if (cursor_pos > 0)
{
// Move characters after cursor back by one position
memmove(&con_text[cursor_pos - 1], &con_text[cursor_pos], textlen - cursor_pos);
cursor_pos--;
textlen--;

// Rewrite the line from cursor position
WriteFile(houtput, "\b", 1, &dummy, NULL);
if (cursor_pos < textlen)
{
WriteFile(houtput, &con_text[cursor_pos], textlen - cursor_pos, &dummy, NULL);
WriteFile(houtput, " ", 1, &dummy, NULL); // Clear last character
// Move cursor back to position
for (int i = 0; i < textlen - cursor_pos + 1; i++)
WriteFile(houtput, "\b", 1, &dummy, NULL);
}
else
{
WriteFile(houtput, " \b", 2, &dummy, NULL); // Clear last character
}
}
break;

default:
if (ch >= ' ')
{
// Insert character at cursor position
if (cursor_pos < textlen)
{
// Make room for new character
memmove(&con_text[cursor_pos + 1], &con_text[cursor_pos], textlen - cursor_pos);
con_text[cursor_pos] = ch;
textlen++;

// Write the new character and the rest of the line
WriteFile(houtput, &con_text[cursor_pos], textlen - cursor_pos, &dummy, NULL);

// Move cursor back to just after inserted character
cursor_pos++;
for (int i = 0; i < textlen - cursor_pos; i++)
WriteFile(houtput, "\b", 1, &dummy, NULL);
}
else
{
// Append character at end of line
con_text[textlen] = ch;
WriteFile(houtput, &ch, 1, &dummy, NULL);
textlen++;
cursor_pos++;
}
}

break;
}

break;
}
}
}
}

Expand Down

0 comments on commit ceb63be

Please sign in to comment.