Add a keyboard controls editor
This commit is contained in:
parent
b9fcd7808e
commit
fba357433f
|
@ -3,7 +3,7 @@
|
|||
#include "doomdef.h"
|
||||
|
||||
/* Dynamic keymap */
|
||||
static uint16_t Keymap[] = {
|
||||
uint16_t CGD_Keymap[] = {
|
||||
KEY_LEFTARROW, -1,
|
||||
KEY_RIGHTARROW, -1,
|
||||
KEY_UPARROW, -1,
|
||||
|
@ -54,6 +54,7 @@ const uint16_t CGD_Keymap_CGDoom_0_3[] = {
|
|||
KEYCODE_OPTN,
|
||||
KEYCODE_0,
|
||||
KEYCODE_DOT,
|
||||
-1,
|
||||
KEYCODE_MINUS,
|
||||
KEYCODE_PLUS,
|
||||
KEYCODE_POWER,
|
||||
|
@ -142,8 +143,8 @@ void CGD_ScanKeyboard(CGD_KeyboardState state)
|
|||
|
||||
void CGD_LoadKeymap(const uint16_t *template)
|
||||
{
|
||||
for(int i = 0; Keymap[2*i] != 0; i++) {
|
||||
Keymap[2*i+1] = template[i];
|
||||
for(int i = 0; CGD_Keymap[2*i] != 0; i++) {
|
||||
CGD_Keymap[2*i+1] = template[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -158,7 +159,7 @@ static int DecodeKeymap(uint16_t *map, int key)
|
|||
|
||||
static int DoomKeyToKeycode(int key)
|
||||
{
|
||||
int code = DecodeKeymap(Keymap, key);
|
||||
int code = DecodeKeymap(CGD_Keymap, key);
|
||||
if(code != -1)
|
||||
return code;
|
||||
|
||||
|
@ -250,3 +251,45 @@ int KeyWasJustReleased(int key)
|
|||
{
|
||||
return KeyDown(st_prev, key) && !KeyDown(st_now, key);
|
||||
}
|
||||
|
||||
static const char * const keynames[] = {
|
||||
"F1", "F2", "F3", "F4", "F5", "F6",
|
||||
"SHIFT", "OPTN", "VARS", "MENU", "Left", "Up",
|
||||
"ALPHA", "x^2", "^", "EXIT", "Down", "Right",
|
||||
"X,O,T", "log", "ln", "sin", "cos", "tan",
|
||||
"Frac", "S<>D", "(", ")", ",", "->",
|
||||
"7", "8", "9", "DEL", NULL, NULL,
|
||||
"4", "5", "6", "x", "/", NULL,
|
||||
"1", "2", "3", "+", "-", NULL,
|
||||
"0", ".", "x10^x", "(-)", "EXE", NULL,
|
||||
};
|
||||
|
||||
const char *CGD_KeyName(int keycode)
|
||||
{
|
||||
if(keycode < 0)
|
||||
return "(None)";
|
||||
if(keycode == KEYCODE_ACON)
|
||||
return "AC/ON";
|
||||
|
||||
int row = 9 - (keycode >> 4);
|
||||
int col = (keycode & 0xf) - 1;
|
||||
|
||||
return keynames[6*row + col];
|
||||
}
|
||||
|
||||
int CGD_PRGM_Getkey(void)
|
||||
{
|
||||
CGD_KeyboardState st;
|
||||
CGD_ScanKeyboard(st);
|
||||
|
||||
for(int code_y = 9; code_y >= 1; code_y--) {
|
||||
for(int code_x = 1; code_x <= 6 - (code_y < 5); code_x++) {
|
||||
int code = (code_y << 4) | code_x;
|
||||
if(code == 0x45) code = KEYCODE_ACON;
|
||||
|
||||
if(KeycodeDown(st, code))
|
||||
return code;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -19,9 +19,17 @@ extern const uint16_t CGD_Keymap_CGDoom_0_3[];
|
|||
extern const uint16_t CGD_Keymap_ThumbsOnly[];
|
||||
extern const uint16_t CGD_Keymap_FullHands[];
|
||||
|
||||
/* Dynamic keymap (the format is slightly different, see cgdoom-kbd.c) */
|
||||
extern uint16_t CGD_Keymap[];
|
||||
|
||||
/* Load a default keymap */
|
||||
void CGD_LoadKeymap(const uint16_t *template);
|
||||
|
||||
/* Key name from matrix code */
|
||||
const char *CGD_KeyName(int keycode);
|
||||
|
||||
/* PRGM_Getkey() but with the direct driver */
|
||||
int CGD_PRGM_Getkey(void);
|
||||
|
||||
/* Keyboard matrix codes for the keyboard driver */
|
||||
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
#include "cgdoom-ui.h"
|
||||
#include "cgdoom-kbd.h"
|
||||
#include "doomdef.h"
|
||||
#include "i_system.h"
|
||||
#include "z_zone.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* RGB color composition, all channels in 0..31 */
|
||||
#define C_RGB(r,g,b) (((r) << 11) | ((g) << 6) | (b))
|
||||
|
||||
/* gint's font in a PrizmSDK-friendly (though ugly) form */
|
||||
static uint8_t const font_width[96] = {
|
||||
5, 2, 6, 7, 8, 6, 8, 3, 4, 4, 8, 8, 3, 7, 2, 5, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
|
@ -263,7 +268,7 @@ void Layout_CenteredText(Layout *l, const char *text)
|
|||
l->y += 14;
|
||||
}
|
||||
|
||||
void Layout_Text(Layout *l, const char *label, const char *fmt, ...)
|
||||
int Layout_Text(Layout *l, const char *label, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
|
@ -272,17 +277,28 @@ void Layout_Text(Layout *l, const char *label, const char *fmt, ...)
|
|||
UI_Vprintf(LAYOUT_RIGHT, l->y, 0x0000, UI_RIGHT, fmt, args);
|
||||
l->y += 14;
|
||||
va_end(args);
|
||||
return l->focus_count - 1;
|
||||
}
|
||||
|
||||
void Layout_Checkbox(Layout *l, const char *label, int *checked)
|
||||
void Layout_Subtext(Layout *l, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
UI_Vprintf(LAYOUT_LEFT, l->y, C_RGB(20, 20, 20), UI_LEFT, fmt, args);
|
||||
l->y += 14;
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
int Layout_Checkbox(Layout *l, const char *label, int *checked)
|
||||
{
|
||||
Layout_AddFocus(l, FOCUS_CHECKBOX, checked);
|
||||
UI_Print(LAYOUT_LEFT, l->y, 0x0000, UI_LEFT, label, -1);
|
||||
UI_Checkbox(LAYOUT_RIGHT-7, l->y+1, *checked);
|
||||
l->y += 14;
|
||||
return l->focus_count - 1;
|
||||
}
|
||||
|
||||
void Layout_Integer(Layout *l, const char *label, int *value)
|
||||
int Layout_Integer(Layout *l, const char *label, int *value)
|
||||
{
|
||||
Layout_AddFocus(l, FOCUS_INTEGER, value);
|
||||
UI_Print(LAYOUT_LEFT, l->y, 0x0000, UI_LEFT, label, -1);
|
||||
|
@ -291,6 +307,7 @@ void Layout_Integer(Layout *l, const char *label, int *value)
|
|||
else
|
||||
UI_Printf(LAYOUT_RIGHT, l->y, 0x0000, UI_RIGHT, "%d", *value);
|
||||
l->y += 14;
|
||||
return l->focus_count - 1;
|
||||
}
|
||||
|
||||
void Layout_Spacing(Layout *l, int spacing)
|
||||
|
@ -375,6 +392,192 @@ int Layout_Event(Layout *l, int key)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void UI_AdvancedOptions(int *dev_info, int *use_mmap, int *trustunaligned)
|
||||
{
|
||||
Layout l;
|
||||
Layout_Init(&l);
|
||||
|
||||
while(1)
|
||||
{
|
||||
Bdisp_AllClr_VRAM();
|
||||
Layout_StartFrame(&l);
|
||||
Layout_CenteredText(&l, "CGDoom: Advanced options");
|
||||
Layout_Spacing(&l, 10);
|
||||
|
||||
Layout_Checkbox(&l, "Developer info:", dev_info);
|
||||
Layout_Subtext(&l, "Start/end screens with statistics.");
|
||||
Layout_Spacing(&l, 10);
|
||||
|
||||
Layout_Checkbox(&l, "Map file to memory:", use_mmap);
|
||||
Layout_Subtext(&l, "Much faster than BFile.");
|
||||
Layout_Spacing(&l, 10);
|
||||
|
||||
Layout_Checkbox(&l, "Trust unaligned lumps", trustunaligned);
|
||||
Layout_Subtext(&l, "Faster; if System ERROR, report a bug!");
|
||||
|
||||
Layout_EndFrame(&l);
|
||||
Bdisp_PutDisp_DD();
|
||||
|
||||
int key;
|
||||
GetKey(&key);
|
||||
|
||||
if(Layout_Event(&l, key)) {
|
||||
}
|
||||
else if(key == KEY_CTRL_EXIT) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const char *UI_ControlName(int key)
|
||||
{
|
||||
switch(key)
|
||||
{
|
||||
case KEY_LEFTARROW: return "Look left";
|
||||
case KEY_RIGHTARROW: return "Look right";
|
||||
case KEY_UPARROW: return "Move forward";
|
||||
case KEY_DOWNARROW: return "Move backward";
|
||||
case ' ': return "Interact";
|
||||
case KEY_RCTRL: return "Shoot";
|
||||
case '1': return "1-Hand";
|
||||
case '2': return "2-Pistol";
|
||||
case '3': return "3-Shotgun";
|
||||
case '4': return "4-Chaingun";
|
||||
case '5': return "5-Rockets";
|
||||
case '6': return "6-Plasma";
|
||||
case '7': return "7-BFG9000";
|
||||
case KEY_TAB: return "Map";
|
||||
case KEY_PAUSE: return "Pause";
|
||||
case KEY_SLEFTARROW: return "Strafe left";
|
||||
case KEY_SRIGHTARROW: return "Strafe right";
|
||||
case KEY_RSHIFT: return "Toggle run";
|
||||
|
||||
case SKEY_DECVP: return "Smaller view";
|
||||
case SKEY_INCVP: return "Larger view";
|
||||
case SKEY_CHEAT: return "Cheat";
|
||||
case SKEY_NOCLIP: return "Noclip";
|
||||
case SKEY_GAMMA: return "Brightness";
|
||||
case SKEY_FREEMEM: return "Heap stats";
|
||||
case SKEY_FPSCOUNTER: return "FPS counter";
|
||||
case SKEY_FRAMESKIP: return "Frameskip";
|
||||
case SKEY_PROFILER: return "Run profiler";
|
||||
|
||||
default: return "???";
|
||||
}
|
||||
}
|
||||
|
||||
void UI_Controls(void)
|
||||
{
|
||||
int focus_x=0, focus_y=-1;
|
||||
int dflt = 0;
|
||||
int editing = -1;
|
||||
|
||||
uint16_t saved_keymap[28] = { 0 };
|
||||
for(int i = 0; CGD_Keymap[2*i] != 0; i++)
|
||||
saved_keymap[i] = CGD_Keymap[2*i+1];
|
||||
|
||||
while(1) {
|
||||
Bdisp_AllClr_VRAM();
|
||||
UI_Print(LAYOUT_LEFT, 10, 0x0000, UI_LEFT, "Load default:", -1);
|
||||
UI_Print(LAYOUT_RIGHT, 10, 0x0000, UI_RIGHT,
|
||||
(dflt == 0) ? "Thumbs only >" :
|
||||
(dflt == 1) ? "< Full hands >" :
|
||||
(dflt == 2) ? "< CGDoom 0.3" :
|
||||
"?", -1);
|
||||
if(focus_y == -1)
|
||||
UI_AreaReverse(0, 10-2, WIDTH-1, 10+11);
|
||||
|
||||
for(int i = 0; CGD_Keymap[2*i] != 0; i++) {
|
||||
int x1 = (i < 14) ? LAYOUT_LEFT - 20 : WIDTH/2 + 15;
|
||||
int x2 = (i < 14) ? WIDTH/2 - 15 : LAYOUT_RIGHT + 20;
|
||||
int y = 29 + 12 * (i % 14);
|
||||
|
||||
/* Skip a row before special keys */
|
||||
if(CGD_Keymap[2*i] >= 0x100)
|
||||
y += 12;
|
||||
|
||||
if(editing == i) {
|
||||
UI_Print(x2, y, 0x0000, UI_RIGHT, "Press a key...", -1);
|
||||
}
|
||||
else {
|
||||
UI_Printf(x1, y, 0x0000, UI_LEFT, "%s",
|
||||
UI_ControlName(CGD_Keymap[2*i]));
|
||||
UI_Printf(x2, y, 0x0000, UI_RIGHT, "%s",
|
||||
CGD_KeyName(CGD_Keymap[2*i+1]));
|
||||
}
|
||||
|
||||
if(focus_y >= 0 && 14 * focus_x + focus_y == i)
|
||||
UI_AreaReverse(x1-4, y-1, x2+4, y+10);
|
||||
}
|
||||
|
||||
UI_Print(LAYOUT_LEFT, HEIGHT-11, 0x0000, UI_LEFT,
|
||||
"F1: Save and quit", -1);
|
||||
UI_Print(LAYOUT_RIGHT, HEIGHT-11, 0x0000, UI_RIGHT,
|
||||
"F6: Cancel", -1);
|
||||
Bdisp_PutDisp_DD();
|
||||
|
||||
/* This is quite hackish */
|
||||
if(editing >= 0) {
|
||||
int key = -1;
|
||||
|
||||
/* Wait for all keys to be released */
|
||||
while(CGD_PRGM_Getkey() != -1) {}
|
||||
/* Wait for a new key to be pressed */
|
||||
while((key = CGD_PRGM_Getkey()) == -1) {}
|
||||
CGD_Keymap[2*editing+1] = key;
|
||||
editing = -1;
|
||||
|
||||
/* Unbuffer that key so GetKey() won't return it again */
|
||||
GetKey(&key);
|
||||
continue;
|
||||
}
|
||||
|
||||
int key;
|
||||
GetKey(&key);
|
||||
|
||||
/* Exit */
|
||||
if(key == KEY_CTRL_F1)
|
||||
break;
|
||||
if(key == KEY_CTRL_F6) {
|
||||
CGD_LoadKeymap(saved_keymap);
|
||||
break;
|
||||
}
|
||||
/* Default selection */
|
||||
else if(key == KEY_CTRL_LEFT && focus_y == -1 && dflt > 0)
|
||||
dflt--;
|
||||
else if(key == KEY_CTRL_RIGHT && focus_y == -1 && dflt < 2)
|
||||
dflt++;
|
||||
else if(key == KEY_CTRL_EXE && focus_y == -1) {
|
||||
if(dflt == 0)
|
||||
CGD_LoadKeymap(CGD_Keymap_ThumbsOnly);
|
||||
else if(dflt == 1)
|
||||
CGD_LoadKeymap(CGD_Keymap_FullHands);
|
||||
else if(dflt == 2)
|
||||
CGD_LoadKeymap(CGD_Keymap_CGDoom_0_3);
|
||||
}
|
||||
/* Focus movement */
|
||||
else if(key == KEY_CTRL_UP && focus_y >= 0)
|
||||
focus_y--;
|
||||
else if(key == KEY_CTRL_DOWN && focus_y < 13 - (focus_x == 1))
|
||||
focus_y++;
|
||||
else if(key == KEY_CTRL_LEFT && focus_x > 0) {
|
||||
focus_x--;
|
||||
focus_y += (focus_y >= 4);
|
||||
}
|
||||
else if(key == KEY_CTRL_RIGHT && focus_x < 1 && focus_y != 4) {
|
||||
focus_x++;
|
||||
focus_y -= (focus_y > 4);
|
||||
}
|
||||
/* Key edition */
|
||||
else if(key == KEY_CTRL_EXE && focus_y >= 0) {
|
||||
editing = 14 * focus_x + focus_y;
|
||||
}
|
||||
else if(key == KEY_CTRL_DEL && focus_y >= 0) {
|
||||
CGD_Keymap[2*(14*focus_x + focus_y)+1] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int UI_Main(CGD_WADFileInfo *wads, int wad_count, int *dev_info, int *use_mmap,
|
||||
int *startmap, int *startepisode, int *trustunaligned,
|
||||
int *autostart, int *enabledemos, int *enable2MBline)
|
||||
|
@ -415,16 +618,15 @@ int UI_Main(CGD_WADFileInfo *wads, int wad_count, int *dev_info, int *use_mmap,
|
|||
Layout_Spacing(&l, 10);
|
||||
Layout_Integer(&l, "Start at episode:", startepisode);
|
||||
Layout_Integer(&l, "Start at map:", startmap);
|
||||
Layout_Text(&l, "Title screen:",
|
||||
int i_title = Layout_Text(&l, "Title screen:",
|
||||
*autostart ? "Skip" :
|
||||
!*enabledemos ? "No demos" : "Full");
|
||||
|
||||
Layout_Spacing(&l, 10);
|
||||
Layout_Checkbox(&l, "Developer info:", dev_info);
|
||||
Layout_Checkbox(&l, "Map file to memory:", use_mmap);
|
||||
Layout_Checkbox(&l, "Trust unaligned lumps:", trustunaligned);
|
||||
if(enable2MBline)
|
||||
Layout_Checkbox(&l, "Use experimental RAM:", enable2MBline);
|
||||
int i_controls = Layout_Text(&l, "Customize controls...", "");
|
||||
int i_advanced = Layout_Text(&l, "Advanced options...", "");
|
||||
Layout_EndFrame(&l);
|
||||
Bdisp_PutDisp_DD();
|
||||
|
||||
|
@ -439,7 +641,7 @@ int UI_Main(CGD_WADFileInfo *wads, int wad_count, int *dev_info, int *use_mmap,
|
|||
if(startparam && changekey)
|
||||
*autostart = 1;
|
||||
}
|
||||
else if(key == KEY_CTRL_EXE && l.focus == wad_count + 2) {
|
||||
else if(key == KEY_CTRL_EXE && l.focus == i_title) {
|
||||
if (!*autostart && *enabledemos)
|
||||
*autostart = 1;
|
||||
else if (!*autostart)
|
||||
|
@ -447,6 +649,12 @@ int UI_Main(CGD_WADFileInfo *wads, int wad_count, int *dev_info, int *use_mmap,
|
|||
else
|
||||
*autostart = 0, *enabledemos = 0;
|
||||
}
|
||||
else if(key == KEY_CTRL_EXE && l.focus == i_controls) {
|
||||
UI_Controls();
|
||||
}
|
||||
else if(key == KEY_CTRL_EXE && l.focus == i_advanced) {
|
||||
UI_AdvancedOptions(dev_info, use_mmap, trustunaligned);
|
||||
}
|
||||
else if(key == KEY_CTRL_EXE && l.focus < wad_count) {
|
||||
return l.focus;
|
||||
}
|
||||
|
|
|
@ -47,11 +47,13 @@ void Layout_EndFrame(Layout *l);
|
|||
/* Add a centered text. */
|
||||
void Layout_CenteredText(Layout *l, const char *text);
|
||||
/* Add a labeled field with printf-formatted contents. */
|
||||
void Layout_Text(Layout *l, const char *label, const char *fmt, ...);
|
||||
int Layout_Text(Layout *l, const char *label, const char *fmt, ...);
|
||||
/* Add a subtext field with no focus. */
|
||||
void Layout_Subtext(Layout *l, const char *fmt, ...);
|
||||
/* Add a checkbox. */
|
||||
void Layout_Checkbox(Layout *l, const char *label, int *checked);
|
||||
int Layout_Checkbox(Layout *l, const char *label, int *checked);
|
||||
/* Add an integer input. */
|
||||
void Layout_Integer(Layout *l, const char *label, int *value);
|
||||
int Layout_Integer(Layout *l, const char *label, int *value);
|
||||
/* Add spacing. */
|
||||
void Layout_Spacing(Layout *l, int spacing);
|
||||
|
||||
|
|
|
@ -496,6 +496,9 @@ int main(void)
|
|||
if(!strncmp(osv, "03.", 3) && osv[3] <= '6') // 3.60 or earlier
|
||||
enable_2MBline = &CGD_2MBLineMemory;
|
||||
|
||||
/* Load initial keyboard layout */
|
||||
CGD_LoadKeymap(CGD_Keymap_ThumbsOnly);
|
||||
|
||||
int choice = UI_Main(wads, wad_count, &dev_info, &CGD_WADMethod,
|
||||
&startmap, &startepisode, &CGD_TrustUnalignedLumps, &autostart_,
|
||||
&CGD_EnableDemos, enable_2MBline);
|
||||
|
@ -511,9 +514,6 @@ int main(void)
|
|||
CGD_2MBLineMemory = 0;
|
||||
#endif
|
||||
|
||||
/* Load keyboard layout */
|
||||
CGD_LoadKeymap(CGD_Keymap_ThumbsOnly);
|
||||
|
||||
/* Override version detection for single-episode Ultimate Doom WADs */
|
||||
if (!strcmp(wads[choice].name, "doomu1.wad"))
|
||||
CGD_SingleEpisodeUltimate = 1;
|
||||
|
|
Loading…
Reference in New Issue