mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-11-19 18:12:54 -05:00
rb core allows you to load custom keyboard layouts
this patch adds the ability to load a keyboard layout in a buffer
the custom layout is temporary and does not overwrite the current layout
use like so:
unsigned short kbd[64];
unsigned short *kbd_p = kbd;
if (!kbd_create_layout("ABCD1234\n", kbd, sizeof(kbd)))
kbd_p = NULL;
rb->kbd_input(buf,sizeof(buf), kbd_p);
Change-Id: I7be2bd4a1b4797a147fa70228a9749dc56ac052a
630 lines
15 KiB
C
630 lines
15 KiB
C
#include "duke3d.h"
|
|
#include "console.h"
|
|
#include "cvars.h"
|
|
#include "cvar_defs.h"
|
|
#include <stdarg.h>
|
|
|
|
// For autoexec.cfg
|
|
#include <stdio.h>
|
|
|
|
#define MAX_STRING_LENGTH 64
|
|
#define MAX_CONSOLE_STRING_LENGTH 70
|
|
#define MAX_CVAR_ARGS 10
|
|
#define MAX_CONSOLE_VIEWABLE 10
|
|
|
|
#define BUILD_NUMBER "Build 19"
|
|
|
|
typedef struct console_element
|
|
{
|
|
char text[MAX_CONSOLE_STRING_LENGTH];
|
|
void* prev;
|
|
void* next;
|
|
}CONSOLEELEMENT;
|
|
|
|
// Private member functions
|
|
void CONSOLE_InsertUsedCommand(const char * szUsedCommand);
|
|
void CONSOLE_ClearUsedCommandList(void);
|
|
void CONSOLE_RecalculateDirtyBuffer(void);
|
|
|
|
// console argument tracker
|
|
int argc;
|
|
char argv[MAX_CVAR_ARGS][MAX_CONSOLE_STRING_LENGTH];
|
|
// Console entries, prepending linked list
|
|
CONSOLEELEMENT *console_buffer = NULL;
|
|
// Current viewed setion of the console
|
|
CONSOLEELEMENT *p_console_current_view = NULL;
|
|
// Previously entered commands:
|
|
CONSOLEELEMENT *console_used_command_list = NULL;
|
|
// Previously entered commands:
|
|
CONSOLEELEMENT *console_used_command_list_current = NULL;
|
|
|
|
// dirty buffer
|
|
char dirty_buffer[MAX_CONSOLE_STRING_LENGTH];
|
|
|
|
// dirty buffer control vars
|
|
int console_cursor_pos = 0; //without spaces
|
|
int console_num_spaces = 0; //number of spaces
|
|
|
|
// Toggle for the console state
|
|
int nConsole_Active = 0;
|
|
|
|
void CVAR_RegisterDefaultCvarBindings(void);
|
|
// Initialize the console
|
|
void CONSOLE_Init(void)
|
|
{
|
|
CONSOLE_Reset();
|
|
|
|
// Console Variable init
|
|
CVAR_RegisterDefaultCvarBindings();
|
|
|
|
// read in our startup.txt
|
|
CONSOLE_ParseStartupScript();
|
|
|
|
CONSOLE_Printf("Type \'HELP\' for help with console Commands.");
|
|
}
|
|
|
|
void CONSOLE_Reset(void)
|
|
{
|
|
CONSOLEELEMENT *pElement;
|
|
CONSOLEELEMENT *pDelElement;
|
|
|
|
// Free the list if it exists
|
|
pElement = console_buffer;
|
|
while(pElement)
|
|
{
|
|
pDelElement = pElement;
|
|
pElement = (CONSOLEELEMENT*)pElement->next;
|
|
|
|
free(pDelElement);
|
|
}
|
|
|
|
console_buffer = NULL;
|
|
p_console_current_view = NULL;
|
|
}
|
|
|
|
void CONSOLE_Term()
|
|
{
|
|
// Do any clean up releasing to the console
|
|
CONSOLE_Reset();
|
|
CONSOLE_ClearUsedCommandList();
|
|
}
|
|
|
|
void CONSOLE_ParseStartupScript()
|
|
{
|
|
// FIX_00017: heavy autoexec.cfg not needed anymore.
|
|
char *sStartupScript = ENGINE_DIR "startup.cfg";
|
|
|
|
FILE* fp = fopen(sStartupScript, "r");
|
|
|
|
// If the file exists
|
|
if(NULL != fp)
|
|
{
|
|
char line[128];
|
|
memset(line, 0, 128);
|
|
|
|
while(fgets(line ,128-1, fp) != NULL)
|
|
{
|
|
CONSOLE_ParseCommand(line);
|
|
|
|
memset(line, 0, 128);
|
|
}
|
|
fclose(fp);
|
|
}
|
|
}
|
|
|
|
void CONSOLE_HandleInput()
|
|
{
|
|
char * lastKey;
|
|
int tmp;
|
|
|
|
if(g_CV_classic)
|
|
{
|
|
nConsole_Active = 0;
|
|
return;
|
|
}
|
|
|
|
// See if we should toggle the console
|
|
if(ACTION(gamefunc_Console))
|
|
{
|
|
nConsole_Active = !nConsole_Active;
|
|
|
|
CONTROL_ClearAction(gamefunc_Console);
|
|
//KB_ClearKeyDown(sc_Tilde);
|
|
|
|
|
|
if(nConsole_Active)
|
|
{
|
|
// If this is a singleplayer game, let's pause the game when the console is active
|
|
if (numplayers == 1)
|
|
{
|
|
if (!ud.recstat) //check if we are not playing a Demo and console is active
|
|
{
|
|
ud.pause_on = 1;
|
|
}else
|
|
{
|
|
ud.pause_on = 0;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
// Bug fix: make sure the frag bar displays after console
|
|
// is hidden
|
|
//if(!nConsole_Active)
|
|
{
|
|
if ( ud.multimode > 1 && ud.coop != 1 )
|
|
{
|
|
displayfragbar();
|
|
}
|
|
if(numplayers<2)
|
|
ud.pause_on = 0;
|
|
// FIX_00078: Out Of Synch error (multiplayer) when using console in pause mode
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
// If the console is not active, there's no need to process input
|
|
if(!nConsole_Active)
|
|
{
|
|
return;
|
|
}
|
|
|
|
switch(KB_GetLastScanCode())
|
|
{
|
|
case sc_Space:
|
|
{
|
|
if(strlen(dirty_buffer) < MAX_CONSOLE_STRING_LENGTH-2)
|
|
{
|
|
strncat(dirty_buffer, " ", 1);
|
|
console_num_spaces++;
|
|
}
|
|
}
|
|
break;
|
|
case sc_Delete:
|
|
case sc_BackSpace:
|
|
{
|
|
tmp = strlen(dirty_buffer);
|
|
if(tmp > 0)
|
|
{
|
|
if( dirty_buffer[tmp - 1] == ' ' )
|
|
{
|
|
dirty_buffer[tmp - 1] = '\0';
|
|
console_num_spaces--;
|
|
}
|
|
else
|
|
{
|
|
dirty_buffer[tmp - 1] = '\0';
|
|
console_cursor_pos--;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
//Ignore list
|
|
case sc_LeftShift:
|
|
case sc_RightShift:
|
|
case sc_PrintScreen:
|
|
case sc_Tab:
|
|
case sc_NumLock:
|
|
case sc_LeftAlt:
|
|
case sc_LeftControl:
|
|
case sc_CapsLock:
|
|
case sc_Bad:
|
|
case sc_LeftArrow:
|
|
case sc_RightArrow:
|
|
case sc_Insert:
|
|
case sc_Home: //this should take us to the top of the list
|
|
case sc_RightAlt:
|
|
case sc_RightControl:
|
|
case sc_Tilde: //ignore
|
|
{
|
|
}break;
|
|
case sc_kpad_Enter:
|
|
case sc_Enter:
|
|
{
|
|
//If console_buffer[0] strlen() != 0
|
|
//1. Push the dirty_buffer unto the console_buffer
|
|
//2. parse the text
|
|
rb->kbd_input(dirty_buffer, sizeof(dirty_buffer), NULL);
|
|
|
|
CONSOLE_Printf("%s", dirty_buffer);
|
|
console_cursor_pos = 0;
|
|
console_num_spaces = 0;
|
|
|
|
CONSOLE_InsertUsedCommand(dirty_buffer);
|
|
CONSOLE_ParseCommand(dirty_buffer);
|
|
|
|
memset(dirty_buffer, 0, MAX_CONSOLE_STRING_LENGTH);
|
|
|
|
}break;
|
|
case sc_UpArrow:
|
|
{
|
|
/*
|
|
if(p_console_current_view->next != NULL)
|
|
{
|
|
p_console_current_view = p_console_current_view->next;
|
|
}
|
|
*/
|
|
if(console_used_command_list_current == NULL)
|
|
{
|
|
if(NULL == console_used_command_list)
|
|
{
|
|
break;
|
|
}
|
|
console_used_command_list_current = console_used_command_list;
|
|
sprintf(dirty_buffer, "%s", console_used_command_list_current->text);
|
|
CONSOLE_RecalculateDirtyBuffer();
|
|
break;
|
|
}
|
|
|
|
if(console_used_command_list_current->next != NULL)
|
|
{
|
|
console_used_command_list_current = console_used_command_list_current->next;
|
|
sprintf(dirty_buffer, "%s", console_used_command_list_current->text);
|
|
CONSOLE_RecalculateDirtyBuffer();
|
|
}else
|
|
if(console_used_command_list_current != NULL)
|
|
{
|
|
sprintf(dirty_buffer, "%s", console_used_command_list_current->text);
|
|
CONSOLE_RecalculateDirtyBuffer();
|
|
}
|
|
|
|
}break;
|
|
case sc_PgUp:
|
|
case sc_A:
|
|
{
|
|
int i;
|
|
for(i = 0; i < MAX_CONSOLE_VIEWABLE; i++)
|
|
{
|
|
if(p_console_current_view->next != NULL)
|
|
{
|
|
p_console_current_view = p_console_current_view->next;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}break;
|
|
case sc_DownArrow:
|
|
{
|
|
/*
|
|
if(p_console_current_view->prev != NULL)
|
|
{
|
|
p_console_current_view = p_console_current_view->prev;
|
|
}
|
|
*/
|
|
if(console_used_command_list_current != NULL)
|
|
{
|
|
if(console_used_command_list_current->prev != NULL)
|
|
{
|
|
console_used_command_list_current = console_used_command_list_current->prev;
|
|
sprintf(dirty_buffer, "%s", console_used_command_list_current->text);
|
|
CONSOLE_RecalculateDirtyBuffer();
|
|
}
|
|
}
|
|
}break;
|
|
case sc_PgDn:
|
|
case sc_D:
|
|
{
|
|
int i;
|
|
for(i = 0; i < MAX_CONSOLE_VIEWABLE; i++)
|
|
{
|
|
if(p_console_current_view->prev != NULL)
|
|
{
|
|
p_console_current_view = p_console_current_view->prev;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}break;
|
|
case sc_End:
|
|
{
|
|
p_console_current_view = console_buffer;
|
|
}break;
|
|
case sc_Escape:
|
|
{
|
|
nConsole_Active = 0;
|
|
KB_ClearKeyDown(sc_Escape);
|
|
// FIX_00057: Using ESC to get out of the console mode wouldn't take pause mode off
|
|
if(numplayers<2)
|
|
ud.pause_on = 0;
|
|
// FIX_00078: Out Of Synch error (multiplayer) when using console in pause mode
|
|
}break;
|
|
default:
|
|
{
|
|
if(strlen(dirty_buffer) < MAX_CONSOLE_STRING_LENGTH-2)
|
|
{
|
|
lastKey = KB_ScanCodeToString(KB_GetLastScanCode());
|
|
|
|
if(lastKey)
|
|
{
|
|
strncat(dirty_buffer, lastKey, 1);
|
|
console_cursor_pos++;
|
|
//printf("Key %s : %s\n", lastKey, console_buffer[0]);
|
|
}
|
|
}
|
|
|
|
}
|
|
break;
|
|
}
|
|
|
|
|
|
KB_ClearLastScanCode();
|
|
}
|
|
|
|
void CONSOLE_Render(void)
|
|
{
|
|
if(g_CV_classic)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Let the Cvars draw something if they need to.
|
|
CVAR_Render();
|
|
|
|
if(nConsole_Active)
|
|
{
|
|
int x,y, y1, y2;
|
|
int i, iCurHeight = 0, iCurWidth = 0;
|
|
int iYOffset = 3; //offset for the console text
|
|
CONSOLEELEMENT *pElement;
|
|
|
|
y1 = 0;
|
|
y2 = (ydim / 2) - ((ydim / 2)/12);
|
|
|
|
// Draw console background
|
|
for(y=y1;y<y2;y+=128)
|
|
{
|
|
for(x=0;x<xdim;x+=128)
|
|
{
|
|
rotatesprite(x<<16,y<<16,65536L,0,BIGHOLE,8,0,(g_CV_TransConsole ? 1:0)+8+16+64+128,0,y1,xdim-1,y2-1);
|
|
}
|
|
}
|
|
|
|
// Draw bottom egde of console
|
|
rotatesprite(78<<16,94<<16,65536L,512,WINDOWBORDER1,24,0,2+8,0,0,xdim-1,ydim-1);
|
|
rotatesprite(238<<16,94<<16,65536L,512,WINDOWBORDER1,24,0,2+8,0,0,xdim-1,ydim-1);
|
|
|
|
// Draw the contents of the console buffer
|
|
pElement = p_console_current_view;//console_buffer;
|
|
for(i = 0; i < MAX_CONSOLE_VIEWABLE; i++)
|
|
{
|
|
if(!pElement)
|
|
{
|
|
break;
|
|
}
|
|
|
|
minitext(5,(8*(9-i)) + iYOffset,
|
|
pElement->text,
|
|
g_CV_console_text_color,
|
|
10+16);
|
|
|
|
pElement = (CONSOLEELEMENT*)pElement->next;
|
|
|
|
}
|
|
|
|
// Set the height of the new line
|
|
iCurHeight = (8*10) + iYOffset;
|
|
|
|
// Draw dirty buffer
|
|
minitext(5, iCurHeight, dirty_buffer, 0,10+16);
|
|
|
|
// Calculate the location of the cursor
|
|
iCurWidth = (console_cursor_pos*4) + (console_num_spaces*5) +5;
|
|
|
|
//Draw the version number
|
|
minitext(283, iCurHeight, BUILD_NUMBER, 17,10+16);
|
|
|
|
// Draw the cursor //Change the color every second
|
|
minitext(iCurWidth, iCurHeight,"_",(time(NULL)%2)+1,10+16);
|
|
}
|
|
else
|
|
if(g_CV_num_console_lines > 0)
|
|
{
|
|
int i, iYOffset = 3; //offset for the console text
|
|
CONSOLEELEMENT *pElement;
|
|
// Draw the contents of the console buffer
|
|
pElement = console_buffer;
|
|
for(i = 0; i < g_CV_num_console_lines; i++)
|
|
{
|
|
if(!pElement)
|
|
{
|
|
break;
|
|
}
|
|
|
|
minitext(5,(8*((g_CV_num_console_lines-1)-i)) + iYOffset,
|
|
pElement->text,
|
|
g_CV_console_text_color,
|
|
10+16);
|
|
|
|
pElement = (CONSOLEELEMENT*)pElement->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CONSOLE_ParseCommand(char * command)
|
|
{
|
|
char *cvar;
|
|
char *token;
|
|
int i, numCvars;
|
|
argc = 0;
|
|
|
|
if( strlen(command) < 1)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Split the command into cvar and args
|
|
cvar = strtok(command, " \r\n");
|
|
|
|
for(i = 0; i < MAX_CVAR_ARGS; i++)
|
|
{
|
|
token = strtok(NULL, " ");
|
|
|
|
if(!token)
|
|
{
|
|
break;
|
|
}
|
|
|
|
sprintf(argv[i], "%s", token);
|
|
argc++;
|
|
}
|
|
|
|
// Cycle through our cvar list and look for this keyword
|
|
numCvars = CVAR_GetNumCvarBindings();
|
|
for(i = 0; i < numCvars; i++)
|
|
{
|
|
cvar_binding* binding = CVAR_GetCvarBinding(i);
|
|
|
|
// Did we find it?
|
|
if ( strcmpi(cvar, binding->name) == 0 )
|
|
{
|
|
binding->function(binding);
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void CONSOLE_InsertUsedCommand(const char * szUsedCommand)
|
|
{
|
|
//create a new element in the list, and add it to the front
|
|
CONSOLEELEMENT *pElement = (CONSOLEELEMENT*)malloc(sizeof(CONSOLEELEMENT));
|
|
if(pElement)
|
|
{
|
|
//Store our newly created member as the prev address
|
|
if(NULL != console_used_command_list)
|
|
{
|
|
console_used_command_list->prev = pElement;
|
|
}
|
|
// Set the next pointer to the front of the list
|
|
pElement->next = console_used_command_list;
|
|
|
|
console_used_command_list_current = NULL;//pElement;
|
|
|
|
// Prepend the entry. This entry is now the head of the list.
|
|
console_used_command_list = pElement;
|
|
|
|
// Make sure we NULL out the prev for our top level element
|
|
pElement->prev = NULL;
|
|
|
|
//sprintf(console_buffer->text, "%s", msg);
|
|
memset(console_used_command_list->text, 0, MAX_CONSOLE_STRING_LENGTH);
|
|
strncpy(console_used_command_list->text, szUsedCommand, MAX_CONSOLE_STRING_LENGTH-2);
|
|
}
|
|
}
|
|
|
|
void CONSOLE_ClearUsedCommandList(void)
|
|
{
|
|
CONSOLEELEMENT *pElement;
|
|
CONSOLEELEMENT *pDelElement;
|
|
|
|
// Free the list if it exists
|
|
pElement = console_used_command_list;
|
|
while(pElement)
|
|
{
|
|
pDelElement = pElement;
|
|
pElement = (CONSOLEELEMENT*)pElement->next;
|
|
|
|
free(pDelElement);
|
|
}
|
|
|
|
console_used_command_list = NULL;
|
|
console_used_command_list_current = NULL;
|
|
}
|
|
|
|
|
|
void CONSOLE_RecalculateDirtyBuffer(void)
|
|
{
|
|
int len;
|
|
int l;
|
|
|
|
console_cursor_pos = 0; //without spaces
|
|
console_num_spaces = 0; //number of spac
|
|
|
|
len = strlen(dirty_buffer);
|
|
|
|
for(l = 0; l < len; ++l)
|
|
{
|
|
if(dirty_buffer[l] == ' ')
|
|
{
|
|
++console_num_spaces;
|
|
}
|
|
else
|
|
{
|
|
++console_cursor_pos;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CONSOLE_Printf(const char *newmsg, ...)
|
|
{
|
|
CONSOLEELEMENT *pElement;
|
|
va_list argptr;
|
|
char msg[512];//[MAX_CONSOLE_STRING_LENGTH];
|
|
va_start (argptr,newmsg);
|
|
vsprintf (msg, newmsg, argptr);
|
|
va_end (argptr);
|
|
|
|
//create a new element in the list, and add it to the front
|
|
pElement = (CONSOLEELEMENT*)malloc(sizeof(CONSOLEELEMENT));
|
|
if(pElement)
|
|
{
|
|
//Store our newly created member as the prev address
|
|
if(NULL != console_buffer)
|
|
{
|
|
console_buffer->prev = pElement;
|
|
}
|
|
// Set the next pointer to the front of the list
|
|
pElement->next = console_buffer;
|
|
|
|
// Set our view, if they are at the bottom of the list.
|
|
// Otherwise, if we set it everytime, Folks might lose
|
|
// what they were looking for in the output, if they
|
|
// were using pgup and pgdn to scroll through the entries.
|
|
if(p_console_current_view == console_buffer)
|
|
{
|
|
p_console_current_view = pElement;
|
|
}
|
|
|
|
// Prepend the entry. This entry is now the head of the list.
|
|
console_buffer = pElement;
|
|
|
|
// Make sure we NULL out the prev for our top level element
|
|
pElement->prev = NULL;
|
|
|
|
//sprintf(console_buffer->text, "%s", msg);
|
|
memset(console_buffer->text, 0, MAX_CONSOLE_STRING_LENGTH);
|
|
strncpy(console_buffer->text, msg, MAX_CONSOLE_STRING_LENGTH-2);
|
|
}
|
|
|
|
}
|
|
|
|
// Get the current number of args for this keyword
|
|
int CONSOLE_GetArgc(void)
|
|
{
|
|
return argc;
|
|
}
|
|
|
|
// Get the current list of args for this keyword
|
|
char * CONSOLE_GetArgv(unsigned int var)
|
|
{
|
|
return argv[var];
|
|
}
|
|
|
|
// Is our console showing?
|
|
int CONSOLE_IsActive(void)
|
|
{
|
|
|
|
return nConsole_Active;
|
|
}
|
|
|
|
// Set our consople active or not.
|
|
void CONSOLE_SetActive(int i)
|
|
{
|
|
nConsole_Active = (i == 0) ? 0 : 1;
|
|
}
|