diff --git a/src/android/i_system.c b/src/android/i_system.c index 150cbd505..58fca7c19 100644 --- a/src/android/i_system.c +++ b/src/android/i_system.c @@ -258,6 +258,18 @@ INT32 I_PutEnv(char *variable) return -1; } +INT32 I_ClipboardCopy(const char *data, size_t size) +{ + (void)data; + (void)size; + return -1; +} + +char *I_ClipboardPaste(void) +{ + return NULL; +} + void I_RegisterSysCommands(void) {} #include "../sdl/dosstr.c" diff --git a/src/console.c b/src/console.c index 025bc1c19..70f8ab6f8 100644 --- a/src/console.c +++ b/src/console.c @@ -84,19 +84,23 @@ UINT32 con_scalefactor; // text size scale factor // hold 32 last lines of input for history #define CON_MAXPROMPTCHARS 256 -#define CON_PROMPTCHAR '>' +#define CON_PROMPTCHAR '$' static char inputlines[32][CON_MAXPROMPTCHARS]; // hold last 32 prompt lines static INT32 inputline; // current input line number static INT32 inputhist; // line number of history input line to restore -static size_t input_cx; // position in current input line +static size_t input_cur; // position of cursor in line +static size_t input_sel; // position of selection marker (I.E.: anything between this and input_cur is "selected") +static size_t input_len; // length of current line, used to bound cursor and such +// notice: input does NOT include the "$" at the start of the line. - 11/3/16 // protos. static void CON_InputInit(void); static void CON_RecalcSize(void); static void CONS_hudlines_Change(void); +static void CONS_backcolor_Change(void); static void CON_DrawBackpic(patch_t *pic, INT32 startx, INT32 destwidth); //static void CON_DrawBackpic2(pic_t *pic, INT32 startx, INT32 destwidth); @@ -129,10 +133,11 @@ static CV_PossibleValue_t backpic_cons_t[] = {{0, "translucent"}, {1, "picture"} // whether to use console background picture, or translucent mode static consvar_t cons_backpic = {"con_backpic", "translucent", CV_SAVE, backpic_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -static CV_PossibleValue_t backcolor_cons_t[] = {{0, "White"}, {1, "Orange"}, - {2, "Blue"}, {3, "Green"}, {4, "Gray"}, - {5, "Red"}, {0, NULL}}; -consvar_t cons_backcolor = {"con_backcolor", "3", CV_SAVE, backcolor_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +static CV_PossibleValue_t backcolor_cons_t[] = {{0, "White"}, {1, "Gray"}, {2, "Brown"}, + {3, "Red"}, {4, "Orange"}, {5, "Yellow"}, + {6, "Green"}, {7, "Blue"}, {8, "Cyan"}, + {0, NULL}}; +consvar_t cons_backcolor = {"con_backcolor", "Green", CV_CALL|CV_SAVE, backcolor_cons_t, CONS_backcolor_Change, 0, NULL, NULL, 0, 0, NULL}; static void CON_Print(char *msg); @@ -219,8 +224,9 @@ static void CONS_Bind_f(void) // CONSOLE SETUP //====================================================================== -// Prepare a colormap for GREEN ONLY translucency over background -// +// Font colormap colors +// TODO: This could probably be improved somehow... +// These colormaps are 99% identical, with just a few changed bytes UINT8 *yellowmap; UINT8 *purplemap; UINT8 *lgreenmap; @@ -229,44 +235,49 @@ UINT8 *graymap; UINT8 *redmap; UINT8 *orangemap; -// Console BG colors -UINT8 *cwhitemap; -UINT8 *corangemap; -UINT8 *cbluemap; -UINT8 *cgreenmap; -UINT8 *cgraymap; -UINT8 *credmap; +// Console BG color +UINT8 *consolebgmap = NULL; -void CON_ReSetupBackColormap(UINT16 num) +void CON_SetupBackColormap(void) { - UINT16 i, j; - UINT8 k; - UINT8 *pal = W_CacheLumpName(R_GetPalname(num), PU_CACHE); + UINT16 i, palsum; + UINT8 j, palindex; + UINT8 *pal = W_CacheLumpName(GetPalette(), PU_CACHE); - // setup the green translucent background colormaps - for (i = 0, k = 0; i < 768; i += 3, k++) + if (!consolebgmap) + consolebgmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); + + switch (cons_backcolor.value) { - j = pal[i] + pal[i+1] + pal[i+2]; - cwhitemap[k] = (UINT8)(15 - (j>>6)); - corangemap[k] = (UINT8)(95 - (j>>6)); - cbluemap[k] = (UINT8)(239 - (j>>6)); - cgreenmap[k] = (UINT8)(175 - (j>>6)); - cgraymap[k] = (UINT8)(31 - (j>>6)); - credmap[k] = (UINT8)(143 - (j>>6)); + case 0: palindex = 15; break; // White + case 1: palindex = 31; break; // Gray + case 2: palindex = 63; break; // Brown + case 3: palindex = 143; break; // Red + case 4: palindex = 95; break; // Orange + case 5: palindex = 111; break; // Yellow + case 6: palindex = 175; break; // Green + case 7: palindex = 239; break; // Blue + case 8: palindex = 219; break; // Cyan + // Default green + default: palindex = 175; break; +} + + // setup background colormap + for (i = 0, j = 0; i < 768; i += 3, j++) + { + palsum = (pal[i] + pal[i+1] + pal[i+2]) >> 6; + consolebgmap[j] = (UINT8)(palindex - palsum); } } -static void CON_SetupBackColormap(void) +static void CONS_backcolor_Change(void) { - INT32 i, j, k; - UINT8 *pal; + CON_SetupBackColormap(); +} - cwhitemap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); - corangemap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); - cbluemap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); - cgreenmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); - cgraymap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); - credmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); +static void CON_SetupColormaps(void) +{ + INT32 i; yellowmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); graymap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); @@ -276,20 +287,6 @@ static void CON_SetupBackColormap(void) redmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); orangemap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); - pal = W_CacheLumpName("PLAYPAL", PU_CACHE); - - // setup the green translucent background colormaps - for (i = 0, k = 0; i < 768; i += 3, k++) - { - j = pal[i] + pal[i+1] + pal[i+2]; - cwhitemap[k] = (UINT8)(15 - (j>>6)); - corangemap[k] = (UINT8)(95 - (j>>6)); - cbluemap[k] = (UINT8)(239 - (j>>6)); - cgreenmap[k] = (UINT8)(175 - (j>>6)); - cgraymap[k] = (UINT8)(31 - (j>>6)); - credmap[k] = (UINT8)(143 - (j>>6)); - } - // setup the other colormaps, for console text // these don't need to be aligned, unless you convert the @@ -320,6 +317,9 @@ static void CON_SetupBackColormap(void) redmap[9] = (UINT8)127; orangemap[3] = (UINT8)85; orangemap[9] = (UINT8)90; + + // Init back colormap + CON_SetupBackColormap(); } // Setup the console text buffer @@ -343,7 +343,7 @@ void CON_Init(void) con_width = 0; CON_RecalcSize(); - CON_SetupBackColormap(); + CON_SetupColormaps(); //note: CON_Ticker should always execute at least once before D_Display() con_clipviewtop = -1; // -1 does not clip @@ -386,14 +386,10 @@ void CON_Init(void) // static void CON_InputInit(void) { - INT32 i; - // prepare the first prompt line memset(inputlines, 0, sizeof (inputlines)); - for (i = 0; i < 32; i++) - inputlines[i][0] = CON_PROMPTCHAR; inputline = 0; - input_cx = 1; + input_cur = input_sel = input_len = 0; } //====================================================================== @@ -618,13 +614,91 @@ void CON_Ticker(void) } } +// +// ---- +// +// Shortcuts for adding and deleting characters, strings, and sections +// Necessary due to moving cursor +// + +static void CON_InputClear(void) +{ + memset(inputlines[inputline], 0, CON_MAXPROMPTCHARS); + input_cur = input_sel = input_len = 0; +} + +static void CON_InputSetString(const char *c) +{ + memset(inputlines[inputline], 0, CON_MAXPROMPTCHARS); + strcpy(inputlines[inputline], c); + input_cur = input_sel = input_len = strlen(c); +} + +static void CON_InputAddString(const char *c) +{ + size_t csize = strlen(c); + if (input_len + csize > CON_MAXPROMPTCHARS-1) + return; + if (input_cur != input_len) + memmove(&inputlines[inputline][input_cur+csize], &inputlines[inputline][input_cur], input_len-input_cur); + memcpy(&inputlines[inputline][input_cur], c, csize); + input_len += csize; + input_sel = (input_cur += csize); +} + +static void CON_InputDelSelection(void) +{ + size_t start, end, len; + if (input_cur > input_sel) + { + start = input_sel; + end = input_cur; + } + else + { + start = input_cur; + end = input_sel; + } + len = (end - start); + + if (end != input_len) + memmove(&inputlines[inputline][start], &inputlines[inputline][end], input_len-end); + memset(&inputlines[inputline][input_len - len], 0, len); + + input_len -= len; + input_sel = input_cur = start; +} + +static void CON_InputAddChar(char c) +{ + if (input_len >= CON_MAXPROMPTCHARS-1) + return; + if (input_cur != input_len) + memmove(&inputlines[inputline][input_cur+1], &inputlines[inputline][input_cur], input_len-input_cur); + inputlines[inputline][input_cur++] = c; + inputlines[inputline][++input_len] = 0; + input_sel = input_cur; +} + +static void CON_InputDelChar(void) +{ + if (!input_cur) + return; + if (input_cur != input_len) + memmove(&inputlines[inputline][input_cur-1], &inputlines[inputline][input_cur], input_len-input_cur); + inputlines[inputline][--input_len] = 0; + input_sel = --input_cur; +} + +// +// ---- +// + // Handles console key input // boolean CON_Responder(event_t *ev) { - static boolean consdown; - static boolean shiftdown; - static boolean ctrldown; + static UINT8 consdown = false; // console is treated differently due to rare usage // sequential completions a la 4dos static char completion[80]; @@ -639,13 +713,8 @@ boolean CON_Responder(event_t *ev) // let go keyup events, don't eat them if (ev->type != ev_keydown && ev->type != ev_console) { - if (ev->data1 == KEY_LSHIFT || ev->data1 == KEY_RSHIFT) - shiftdown = false; - else if (ev->data1 == KEY_LCTRL || ev->data1 == KEY_RCTRL) - ctrldown = false; - else if (ev->data1 == gamecontrol[gc_console][0] || ev->data1 == gamecontrol[gc_console][1]) + if (ev->data1 == gamecontrol[gc_console][0] || ev->data1 == gamecontrol[gc_console][1]) consdown = false; - return false; } @@ -684,94 +753,110 @@ boolean CON_Responder(event_t *ev) consoletoggle = true; return true; } - } - // eat shift only if console active - if (key == KEY_LSHIFT || key == KEY_RSHIFT) - { - shiftdown = true; + // Always eat ctrl/shift/alt if console open, so the menu doesn't get ideas + if (key == KEY_LSHIFT || key == KEY_RSHIFT + || key == KEY_LCTRL || key == KEY_RCTRL + || key == KEY_LALT || key == KEY_RALT) return true; - } - // same for ctrl - if (key == KEY_LCTRL || key == KEY_RCTRL) + // ctrl modifier -- changes behavior, adds shortcuts + if (ctrldown) { - ctrldown = true; - return true; + // show all cvars/commands that match what we have inputted + if (key == KEY_TAB) + { + size_t i, len; + + if (!completion[0]) + { + if (!input_len || input_len >= 40 || strchr(inputlines[inputline], ' ')) + return true; + strcpy(completion, inputlines[inputline]); + comskips = varskips = 0; + } + len = strlen(completion); + + //first check commands + CONS_Printf("\nCommands:\n"); + for (i = 0, cmd = COM_CompleteCommand(completion, i); cmd; cmd = COM_CompleteCommand(completion, ++i)) + CONS_Printf(" \x83" "%s" "\x80" "%s\n", completion, cmd+len); + if (i == 0) CONS_Printf(" (none)\n"); + + //now we move on to CVARs + CONS_Printf("Variables:\n"); + for (i = 0, cmd = CV_CompleteVar(completion, i); cmd; cmd = CV_CompleteVar(completion, ++i)) + CONS_Printf(" \x83" "%s" "\x80" "%s\n", completion, cmd+len); + if (i == 0) CONS_Printf(" (none)\n"); + + return true; + } + // --- + + if (key == KEY_HOME) // oldest text in buffer + { + con_scrollup = (con_totallines-((con_curlines-16)>>3)); + return true; + } + else if (key == KEY_END) // most recent text in buffer + { + con_scrollup = 0; + return true; + } + + if (key == 'x' || key == 'X') + { + if (input_sel > input_cur) + I_ClipboardCopy(&inputlines[inputline][input_cur], input_sel-input_cur); + else + I_ClipboardCopy(&inputlines[inputline][input_sel], input_cur-input_sel); + CON_InputDelSelection(); + completion[0] = 0; + return true; + } + else if (key == 'c' || key == 'C') + { + if (input_sel > input_cur) + I_ClipboardCopy(&inputlines[inputline][input_cur], input_sel-input_cur); + else + I_ClipboardCopy(&inputlines[inputline][input_sel], input_cur-input_sel); + return true; + } + else if (key == 'v' || key == 'V') + { + const char *paste = I_ClipboardPaste(); + if (input_sel != input_cur) + CON_InputDelSelection(); + if (paste != NULL) + CON_InputAddString(paste); + completion[0] = 0; + return true; + } + + // Select all + if (key == 'a' || key == 'A') + { + input_sel = 0; + input_cur = input_len; + return true; + } + + // don't eat the key + return false; } // command completion forward (tab) and backward (shift-tab) if (key == KEY_TAB) { - // show all cvars/commands that match what we have inputted - if (ctrldown) - { - UINT32 i; - size_t stop = input_cx - 1; - char nameremainder[255]; - - if (input_cx < 2 || strlen(inputlines[inputline]+1) >= 80) - return true; - - strcpy(completion, inputlines[inputline]+1); - - // trimming: stop at the first newline - for (i = 0; i < input_cx - 1; ++i) - { - if (completion[i] == ' ') - { - completion[i] = '\0'; - stop = i; - break; - } - } - - i = 0; - - //first check commands - CONS_Printf("\nCommands:\n"); - - for (cmd = COM_CompleteCommand(completion, i); cmd; cmd = COM_CompleteCommand(completion, i)) - { - strncpy(nameremainder, cmd+(stop), strlen(cmd)-(stop)); - nameremainder[strlen(cmd)-(stop)] = '\0'; - - CONS_Printf(" \x83" "%s" "\x80" "%s\n", completion, nameremainder); - ++i; - } - if (i == 0) - CONS_Printf(" (none)\n"); - - i = 0; - - //now we move on to CVARs - CONS_Printf("Variables:\n"); - - for (cmd = CV_CompleteVar(completion, i); cmd; cmd = CV_CompleteVar(completion, i)) - { - strncpy(nameremainder, cmd+(stop), strlen(cmd)-(stop)); - nameremainder[strlen(cmd)-(stop)] = '\0'; - - CONS_Printf(" \x83" "%s" "\x80" "%s\n", completion, nameremainder); - ++i; - } - if (i == 0) - CONS_Printf(" (none)\n"); - - return true; - } - // sequential command completion forward and backward // remember typing for several completions (a-la-4dos) - if (inputlines[inputline][input_cx-1] != ' ') + if (!completion[0]) { - if (strlen(inputlines[inputline]+1) < 80) - strcpy(completion, inputlines[inputline]+1); - else - completion[0] = 0; - + if (!input_len || input_len >= 40 || strchr(inputlines[inputline], ' ')) + return true; + strcpy(completion, inputlines[inputline]); comskips = varskips = 0; } else @@ -783,37 +868,26 @@ boolean CON_Responder(event_t *ev) if (--varskips < 0) comskips = -comskips - 2; } - else if (comskips > 0) - comskips--; + else if (comskips > 0) comskips--; } else { - if (comskips < 0) - varskips++; - else - comskips++; + if (comskips < 0) varskips++; + else comskips++; } } if (comskips >= 0) { cmd = COM_CompleteCommand(completion, comskips); - if (!cmd) - // dirty: make sure if comskips is zero, to have a neg value + if (!cmd) // dirty: make sure if comskips is zero, to have a neg value comskips = -comskips - 1; } if (comskips < 0) cmd = CV_CompleteVar(completion, varskips); if (cmd) - { - memset(inputlines[inputline]+1, 0, CON_MAXPROMPTCHARS-1); - strcpy(inputlines[inputline]+1, cmd); - input_cx = strlen(cmd) + 1; - inputlines[inputline][input_cx] = ' '; - input_cx++; - inputlines[inputline][input_cx] = 0; - } + CON_InputSetString(va("%s ", cmd)); else { if (comskips > 0) @@ -839,47 +913,80 @@ boolean CON_Responder(event_t *ev) return true; } - if (key == KEY_HOME) // oldest text in buffer + if (key == KEY_LEFTARROW) { - con_scrollup = (con_totallines-((con_curlines-16)>>3)); + if (input_cur != 0) + --input_cur; + if (!shiftdown) + input_sel = input_cur; return true; } - else if (key == KEY_END) // most recent text in buffer + else if (key == KEY_RIGHTARROW) { - con_scrollup = 0; + if (input_cur < input_len) + ++input_cur; + if (!shiftdown) + input_sel = input_cur; return true; } + else if (key == KEY_HOME) + { + input_cur = 0; + if (!shiftdown) + input_sel = input_cur; + return true; + } + else if (key == KEY_END) + { + input_cur = input_len; + if (!shiftdown) + input_sel = input_cur; + return true; + } + + // At this point we're messing with input + // Clear completion + completion[0] = 0; // command enter if (key == KEY_ENTER) { - if (input_cx < 2) + if (!input_len) return true; // push the command - COM_BufAddText(inputlines[inputline]+1); + COM_BufAddText(inputlines[inputline]); COM_BufAddText("\n"); - CONS_Printf("%s\n", inputlines[inputline]); + CONS_Printf("\x86""%c""\x80""%s\n", CON_PROMPTCHAR, inputlines[inputline]); inputline = (inputline+1) & 31; inputhist = inputline; - - memset(inputlines[inputline], 0, CON_MAXPROMPTCHARS); - inputlines[inputline][0] = CON_PROMPTCHAR; - input_cx = 1; + CON_InputClear(); return true; } - // backspace command prompt - if (key == KEY_BACKSPACE) + // backspace and delete command prompt + if (input_sel != input_cur) { - if (input_cx > 1) + if (key == KEY_BACKSPACE || key == KEY_DEL) { - input_cx--; - inputlines[inputline][input_cx] = 0; + CON_InputDelSelection(); + return true; } + } + else if (key == KEY_BACKSPACE) + { + CON_InputDelChar(); + return true; + } + else if (key == KEY_DEL) + { + if (input_cur == input_len) + return true; + ++input_cur; + CON_InputDelChar(); return true; } @@ -888,18 +995,15 @@ boolean CON_Responder(event_t *ev) { // copy one of the previous inputlines to the current do - { inputhist = (inputhist - 1) & 31; // cycle back - } while (inputhist != inputline && !inputlines[inputhist][1]); + while (inputhist != inputline && !inputlines[inputhist][0]); // stop at the last history input line, which is the // current line + 1 because we cycle through the 32 input lines if (inputhist == inputline) inputhist = (inputline + 1) & 31; - M_Memcpy(inputlines[inputline], inputlines[inputhist], CON_MAXPROMPTCHARS); - input_cx = strlen(inputlines[inputline]); - + CON_InputSetString(inputlines[inputhist]); return true; } @@ -909,23 +1013,14 @@ boolean CON_Responder(event_t *ev) if (inputhist == inputline) return true; do - { inputhist = (inputhist + 1) & 31; - } while (inputhist != inputline && !inputlines[inputhist][1]); - - memset(inputlines[inputline], 0, CON_MAXPROMPTCHARS); + while (inputhist != inputline && !inputlines[inputhist][0]); // back to currentline if (inputhist == inputline) - { - inputlines[inputline][0] = CON_PROMPTCHAR; - input_cx = 1; - } + CON_InputClear(); else - { - strcpy(inputlines[inputline], inputlines[inputhist]); - input_cx = strlen(inputlines[inputline]); - } + CON_InputSetString(inputlines[inputhist]); return true; } @@ -950,15 +1045,12 @@ boolean CON_Responder(event_t *ev) return false; // add key to cmd line here - if (input_cx < CON_MAXPROMPTCHARS) - { - if (key >= 'A' && key <= 'Z' && !shiftdown) //this is only really necessary for dedicated servers - key = key + 'a' - 'A'; + if (key >= 'A' && key <= 'Z' && !shiftdown) //this is only really necessary for dedicated servers + key = key + 'a' - 'A'; - inputlines[inputline][input_cx] = (char)key; - inputlines[inputline][input_cx + 1] = 0; - input_cx++; - } + if (input_sel != input_cur) + CON_InputDelSelection(); + CON_InputAddChar(key); return true; } @@ -1242,26 +1334,89 @@ void CONS_Error(const char *msg) // static void CON_DrawInput(void) { - char *p; - size_t c; - INT32 x, y; INT32 charwidth = (INT32)con_scalefactor << 3; - - // input line scrolls left if it gets too long - p = inputlines[inputline]; - if (input_cx >= con_width-11) - p += input_cx - (con_width-11) + 1; + const char *p = inputlines[inputline]; + size_t c, clen, cend; + UINT8 lellip = 0, rellip = 0; + INT32 x, y, i; y = con_curlines - 12 * con_scalefactor; + x = charwidth*2; - for (c = 0, x = charwidth; c < con_width-11; c++, x += charwidth) - V_DrawCharacter(x, y, p[c] | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value); + clen = con_width-13; - // draw the blinking cursor - // - x = ((input_cx >= con_width-11) ? (INT32)(con_width-11) : (INT32)((input_cx + 1)) * charwidth); - if (con_tick < 4) - V_DrawCharacter(x, y, '_' | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value); + if (input_len <= clen) + { + c = 0; + clen = input_len; + } + else // input line scrolls left if it gets too long + { + clen -= 2; // There will always be some extra truncation -- but where is what we'll find out + + if (input_cur <= clen/2) + { + // Close enough to right edge to show all + c = 0; + // Always will truncate right side from this position, so always draw right ellipsis + rellip = 1; + } + else + { + // Cursor in the middle (or right side) of input + // Move over for the ellipsis + c = input_cur - (clen/2) + 2; + x += charwidth*2; + lellip = 1; + + if (c + clen >= input_len) + { + // Cursor in the right side of input + // We were too far over, so move back + c = input_len - clen; + } + else + { + // Cursor in the middle -- ellipses on both sides + clen -= 2; + rellip = 1; + } + } + } + + if (lellip) + { + x -= charwidth*3; + if (input_sel < c) + V_DrawFill(x, y, charwidth*3, (10 * con_scalefactor), 107 | V_NOSCALESTART); + for (i = 0; i < 3; ++i, x += charwidth) + V_DrawCharacter(x, y, '.' | cv_constextsize.value | V_GRAYMAP | V_NOSCALESTART, !cv_allcaps.value); + } + else + V_DrawCharacter(x-charwidth, y, CON_PROMPTCHAR | cv_constextsize.value | V_GRAYMAP | V_NOSCALESTART, !cv_allcaps.value); + + for (cend = c + clen; c < cend; ++c, x += charwidth) + { + if ((input_sel > c && input_cur <= c) || (input_sel <= c && input_cur > c)) + { + V_DrawFill(x, y, charwidth, (10 * con_scalefactor), 107 | V_NOSCALESTART); + V_DrawCharacter(x, y, p[c] | cv_constextsize.value | V_YELLOWMAP | V_NOSCALESTART, !cv_allcaps.value); + } + else + V_DrawCharacter(x, y, p[c] | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value); + + if (c == input_cur && con_tick >= 4) + V_DrawCharacter(x, y + (con_scalefactor*2), '_' | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value); + } + if (cend == input_cur && con_tick >= 4) + V_DrawCharacter(x, y + (con_scalefactor*2), '_' | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value); + if (rellip) + { + if (input_sel > cend) + V_DrawFill(x, y, charwidth*3, (10 * con_scalefactor), 107 | V_NOSCALESTART); + for (i = 0; i < 3; ++i, x += charwidth) + V_DrawCharacter(x, y, '.' | cv_constextsize.value | V_GRAYMAP | V_NOSCALESTART, !cv_allcaps.value); + } } // draw the last lines of console text to the top of the screen @@ -1417,7 +1572,7 @@ static void CON_DrawConsole(void) { // inu: no more width (was always 0 and vid.width) if (rendermode != render_none) - V_DrawFadeConsBack(con_curlines, cons_backcolor.value); // translucent background + V_DrawFadeConsBack(con_curlines); // translucent background } // draw console text lines from top to bottom diff --git a/src/console.h b/src/console.h index 47af65e21..8cf6483ff 100644 --- a/src/console.h +++ b/src/console.h @@ -40,11 +40,10 @@ extern consvar_t cons_backcolor; extern UINT8 *yellowmap, *purplemap, *lgreenmap, *bluemap, *graymap, *redmap, *orangemap; -// Console bg colors: -extern UINT8 *cwhitemap, *corangemap, *cbluemap, *cgreenmap, *cgraymap, - *credmap; +// Console bg color (auto updated to match) +extern UINT8 *consolebgmap; -void CON_ReSetupBackColormap(UINT16 num); +void CON_SetupBackColormap(void); void CON_ClearHUD(void); // clear heads up messages void CON_Ticker(void); diff --git a/src/d_main.c b/src/d_main.c index b61ec4143..2caf50087 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -73,6 +73,7 @@ int snprintf(char *str, size_t n, const char *fmt, ...); #include "dehacked.h" // Dehacked list test #include "m_cond.h" // condition initialization #include "fastcmp.h" +#include "keys.h" #ifdef CMAKECONFIG #include "config.h" @@ -176,6 +177,38 @@ void D_PostEvent(const event_t *ev) void D_PostEvent_end(void) {}; #endif +// modifier keys +UINT8 shiftdown = 0; // 0x1 left, 0x2 right +UINT8 ctrldown = 0; // 0x1 left, 0x2 right +UINT8 altdown = 0; // 0x1 left, 0x2 right +// +// D_ModifierKeyResponder +// Sets global shift/ctrl/alt variables, never actually eats events +// +static inline void D_ModifierKeyResponder(event_t *ev) +{ + if (ev->type == ev_keydown) switch (ev->data1) + { + case KEY_LSHIFT: shiftdown |= 0x1; return; + case KEY_RSHIFT: shiftdown |= 0x2; return; + case KEY_LCTRL: ctrldown |= 0x1; return; + case KEY_RCTRL: ctrldown |= 0x2; return; + case KEY_LALT: altdown |= 0x1; return; + case KEY_RALT: altdown |= 0x2; return; + default: return; + } + else if (ev->type == ev_keyup) switch (ev->data1) + { + case KEY_LSHIFT: shiftdown &= ~0x1; return; + case KEY_RSHIFT: shiftdown &= ~0x2; return; + case KEY_LCTRL: ctrldown &= ~0x1; return; + case KEY_RCTRL: ctrldown &= ~0x2; return; + case KEY_LALT: altdown &= ~0x1; return; + case KEY_RALT: altdown &= ~0x2; return; + default: return; + } +} + // // D_ProcessEvents // Send all the events of the given timestamp down the responder chain @@ -188,6 +221,9 @@ void D_ProcessEvents(void) { ev = &events[eventtail]; + // Set global shift/ctrl/alt down variables + D_ModifierKeyResponder(ev); // never eats events + // Screenshots over everything so that they can be taken anywhere. if (M_ScreenshotResponder(ev)) continue; // ate the event diff --git a/src/djgppdos/i_system.c b/src/djgppdos/i_system.c index 854d68f4d..dae9ed16e 100644 --- a/src/djgppdos/i_system.c +++ b/src/djgppdos/i_system.c @@ -1721,6 +1721,18 @@ INT32 I_PutEnv(char *variable) return putenv(variable); } +INT32 I_ClipboardCopy(const char *data, size_t size) +{ + (void)data; + (void)size; + return -1; +} + +char *I_ClipboardPaste(void) +{ + return NULL; +} + const CPUInfoFlags *I_CPUInfo(void) { static CPUInfoFlags DOS_CPUInfo; diff --git a/src/doomdef.h b/src/doomdef.h index 7d883849d..f993dadf8 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -394,6 +394,9 @@ extern INT32 cv_debug; // Misc stuff for later... // ======================= +// Modifier key variables, accessible anywhere +extern UINT8 shiftdown, ctrldown, altdown; + // if we ever make our alloc stuff... #define ZZ_Alloc(x) Z_Malloc(x, PU_STATIC, NULL) diff --git a/src/dummy/i_system.c b/src/dummy/i_system.c index c1e48b60b..a3fe3077c 100644 --- a/src/dummy/i_system.c +++ b/src/dummy/i_system.c @@ -162,6 +162,18 @@ INT32 I_PutEnv(char *variable) return -1; } +INT32 I_ClipboardCopy(const char *data, size_t size) +{ + (void)data; + (void)size; + return -1; +} + +char *I_ClipboardPaste(void) +{ + return NULL; +} + void I_RegisterSysCommands(void) {} #include "../sdl/dosstr.c" diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index 60183b58e..f23753ee5 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -656,6 +656,7 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color) { FOutVector v[4]; FSurfaceInfo Surf; + float sdupx, sdupy; if (w < 0 || h < 0) return; // consistency w/ software @@ -664,10 +665,16 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color) // | /| // |/ | // 0--1 - v[0].x = v[3].x = (x - 160.0f)/160.0f; - v[2].x = v[1].x = ((x+w) - 160.0f)/160.0f; - v[0].y = v[1].y = -(y - 100.0f)/100.0f; - v[2].y = v[3].y = -((y+h) - 100.0f)/100.0f; + sdupx = FIXED_TO_FLOAT(vid.fdupx)*2.0f; + sdupy = FIXED_TO_FLOAT(vid.fdupy)*2.0f; + + if (color & V_NOSCALESTART) + sdupx = sdupy = 2.0f; + + v[0].x = v[3].x = (x*sdupx)/vid.width - 1; + v[2].x = v[1].x = (x*sdupx + w*sdupx)/vid.width - 1; + v[0].y = v[1].y = 1-(y*sdupy)/vid.height; + v[2].y = v[3].y = 1-(y*sdupy + h*sdupy)/vid.height; //Hurdler: do we still use this argb color? if not, we should remove it v[0].argb = v[1].argb = v[2].argb = v[3].argb = 0xff00ff00; //; diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 8e48ec110..4ec2e346a 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -308,6 +308,23 @@ static md2_model_t *md2_readModel(const char *filename) model->header.numSkins = 1; +#define MD2LIMITCHECK(field, max, msgname) \ + if (field > max) \ + { \ + CONS_Alert(CONS_ERROR, "md2_readModel: %s has too many " msgname " (# found: %d, maximum: %d)\n", filename, field, max); \ + md2_freeModel (model); \ + return 0; \ + } + + // Uncomment if these are actually needed +// MD2LIMITCHECK(model->header.numSkins, MD2_MAX_SKINS, "skins") +// MD2LIMITCHECK(model->header.numTexCoords, MD2_MAX_TEXCOORDS, "texture coordinates") + MD2LIMITCHECK(model->header.numTriangles, MD2_MAX_TRIANGLES, "triangles") + MD2LIMITCHECK(model->header.numFrames, MD2_MAX_FRAMES, "frames") + MD2LIMITCHECK(model->header.numVertices, MD2_MAX_VERTICES, "vertices") + +#undef MD2LIMITCHECK + // read skins fseek(file, model->header.offsetSkins, SEEK_SET); if (model->header.numSkins > 0) @@ -319,8 +336,6 @@ static md2_model_t *md2_readModel(const char *filename) md2_freeModel (model); return 0; } - - ; } // read texture coordinates @@ -334,8 +349,6 @@ static md2_model_t *md2_readModel(const char *filename) md2_freeModel (model); return 0; } - - } // read triangles @@ -769,6 +782,7 @@ void HWR_InitMD2(void) md2_playermodels[s].grpatch = NULL; md2_playermodels[s].skin = -1; md2_playermodels[s].notfound = true; + md2_playermodels[s].error = false; } for (i = 0; i < NUMSPRITES; i++) { @@ -777,6 +791,7 @@ void HWR_InitMD2(void) md2_models[i].grpatch = NULL; md2_models[i].skin = -1; md2_models[i].notfound = true; + md2_models[i].error = false; } // read the md2.dat file @@ -1269,6 +1284,8 @@ void HWR_DrawMD2(gr_vissprite_t *spr) else md2 = &md2_models[spr->mobj->sprite]; + if (md2->error) + return; // we already failed loading this before :( if (!md2->model) { //CONS_Debug(DBG_RENDER, "Loading MD2... (%s)", sprnames[spr->mobj->sprite]); @@ -1282,6 +1299,7 @@ void HWR_DrawMD2(gr_vissprite_t *spr) else { //CONS_Debug(DBG_RENDER, " FAILED\n"); + md2->error = true; // prevent endless fail return; } } diff --git a/src/hardware/hw_md2.h b/src/hardware/hw_md2.h index 36078268b..5a7e6d2b3 100644 --- a/src/hardware/hw_md2.h +++ b/src/hardware/hw_md2.h @@ -123,6 +123,7 @@ typedef struct void *blendgrpatch; boolean notfound; INT32 skin; + boolean error; } md2_t; extern md2_t md2_models[NUMSPRITES]; diff --git a/src/hu_stuff.c b/src/hu_stuff.c index ec747305e..e33a54305 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -757,15 +757,8 @@ void HU_clearChatChars(void) // boolean HU_Responder(event_t *ev) { - static boolean shiftdown = false; UINT8 c; - if (ev->data1 == KEY_LSHIFT || ev->data1 == KEY_RSHIFT) - { - shiftdown = (ev->type == ev_keydown); - return chat_on; - } - if (ev->type != ev_keydown) return false; diff --git a/src/i_system.h b/src/i_system.h index c161851e0..d61f2d16e 100644 --- a/src/i_system.h +++ b/src/i_system.h @@ -296,6 +296,14 @@ char *I_GetEnv(const char *name); INT32 I_PutEnv(char *variable); +/** \brief Put data in system clipboard +*/ +INT32 I_ClipboardCopy(const char *data, size_t size); + +/** \brief Retrieve data from system clipboard +*/ +const char *I_ClipboardPaste(void); + void I_RegisterSysCommands(void); #endif diff --git a/src/m_menu.c b/src/m_menu.c index 78c381273..d7b4d9080 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -182,9 +182,6 @@ static INT32 vidm_selected = 0; static INT32 vidm_nummodes; static INT32 vidm_column_size; -// what a headache. -static boolean shiftdown = false; - // // PROTOTYPES // @@ -2080,11 +2077,6 @@ boolean M_Responder(event_t *ev) || gamestate == GS_CREDITS || gamestate == GS_EVALUATION) return false; - if (ev->type == ev_keyup && (ev->data1 == KEY_LSHIFT || ev->data1 == KEY_RSHIFT)) - { - shiftdown = false; - return false; - } if (noFurtherInput) { // Ignore input after enter/escape/other buttons @@ -2098,10 +2090,6 @@ boolean M_Responder(event_t *ev) // added 5-2-98 remap virtual keys (mouse & joystick buttons) switch (ch) { - case KEY_LSHIFT: - case KEY_RSHIFT: - shiftdown = true; - break; //return false; case KEY_MOUSE1: case KEY_JOY1: case KEY_JOY1 + 2: diff --git a/src/nds/i_system.c b/src/nds/i_system.c index 0ed58029c..3e5c4b8c6 100644 --- a/src/nds/i_system.c +++ b/src/nds/i_system.c @@ -269,6 +269,18 @@ INT32 I_PutEnv(char *variable) return -1; } +INT32 I_ClipboardCopy(const char *data, size_t size) +{ + (void)data; + (void)size; + return -1; +} + +char *I_ClipboardPaste(void) +{ + return NULL; +} + void I_RegisterSysCommands(void) {} #include "../sdl/dosstr.c" diff --git a/src/p_setup.c b/src/p_setup.c index f1d3a68c8..d65637355 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2585,7 +2585,7 @@ boolean P_SetupLevel(boolean skipprecip) lastloadedmaplumpnum = W_GetNumForName(maplumpname = G_BuildMapName(gamemap)); R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette); - CON_ReSetupBackColormap(mapheaderinfo[gamemap-1]->palette); + CON_SetupBackColormap(); // SRB2 determines the sky texture to be used depending on the map header. P_SetupLevelSky(mapheaderinfo[gamemap-1]->skynum, true); diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index ea8ade8c1..71ee3f794 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -2647,6 +2647,47 @@ INT32 I_PutEnv(char *variable) #endif } +INT32 I_ClipboardCopy(const char *data, size_t size) +{ + char storage[256]; + if (size > 255) + size = 255; + memcpy(storage, data, size); + storage[size] = 0; + + if (SDL_SetClipboardText(storage)) + return 0; + return -1; +} + +const char *I_ClipboardPaste(void) +{ + static char clipboard_modified[256]; + char *clipboard_contents, *i = clipboard_modified; + + if (!SDL_HasClipboardText()) + return NULL; + clipboard_contents = SDL_GetClipboardText(); + memcpy(clipboard_modified, clipboard_contents, 255); + SDL_free(clipboard_contents); + clipboard_modified[255] = 0; + + while (*i) + { + if (*i == '\n' || *i == '\r') + { // End on newline + *i = 0; + break; + } + else if (*i == '\t') + *i = ' '; // Tabs become spaces + else if (*i < 32 || (unsigned)*i > 127) + *i = '?'; // Nonprintable chars become question marks + ++i; + } + return (const char *)&clipboard_modified; +} + /** \brief The isWadPathOk function \param path string path to check diff --git a/src/sdl/ogl_sdl.h b/src/sdl/ogl_sdl.h index 7e144644c..2d6209f2b 100644 --- a/src/sdl/ogl_sdl.h +++ b/src/sdl/ogl_sdl.h @@ -24,7 +24,6 @@ boolean OglSdlSurface(INT32 w, INT32 h); void OglSdlFinishUpdate(boolean vidwait); -extern SDL_Window *window; extern SDL_Renderer *renderer; extern SDL_GLContext sdlglcontext; extern Uint16 realwidth; diff --git a/src/sdl/sdlmain.h b/src/sdl/sdlmain.h index 7ac32f4b3..fea1e1648 100644 --- a/src/sdl/sdlmain.h +++ b/src/sdl/sdlmain.h @@ -71,4 +71,7 @@ void I_GetConsoleEvents(void); void SDLforceUngrabMouse(void); +// Needed for some WIN32 functions +extern SDL_Window *window; + #endif diff --git a/src/sdl12/i_system.c b/src/sdl12/i_system.c index 888a6a507..ed0db653d 100644 --- a/src/sdl12/i_system.c +++ b/src/sdl12/i_system.c @@ -2666,6 +2666,18 @@ INT32 I_PutEnv(char *variable) #endif } +INT32 I_ClipboardCopy(const char *data, size_t size) +{ + (void)data; + (void)size; + return -1; +} + +char *I_ClipboardPaste(void) +{ + return NULL; +} + /** \brief The isWadPathOk function \param path string path to check diff --git a/src/v_video.c b/src/v_video.c index 3cc6d195f..f6a966e67 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -774,43 +774,51 @@ void V_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c) if (!screens[0]) return; - if (x == 0 && y == 0 && w == BASEVIDWIDTH && h == BASEVIDHEIGHT) - { // Clear the entire screen, from dest to deststop. Yes, this really works. - memset(screens[0], (UINT8)(c&255), vid.width * vid.height * vid.bpp); - return; - } - - dest = screens[0] + y*dupy*vid.width + x*dupx; - deststop = screens[0] + vid.rowbytes * vid.height; - - if (w == BASEVIDWIDTH) - w = vid.width; - else - w *= dupx; - if (h == BASEVIDHEIGHT) - h = vid.height; - else - h *= dupy; - - if (x && y && x + w < vid.width && y + h < vid.height) + if (c & V_NOSCALESTART) { - // Center it if necessary - if (vid.width != BASEVIDWIDTH * dupx) - { - // dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx, - // so center this imaginary screen - if (c & V_SNAPTORIGHT) - dest += (vid.width - (BASEVIDWIDTH * dupx)); - else if (!(c & V_SNAPTOLEFT)) - dest += (vid.width - (BASEVIDWIDTH * dupx)) / 2; + dest = screens[0] + y*vid.width + x; + deststop = screens[0] + vid.rowbytes * vid.height; + } + else + { + if (x == 0 && y == 0 && w == BASEVIDWIDTH && h == BASEVIDHEIGHT) + { // Clear the entire screen, from dest to deststop. Yes, this really works. + memset(screens[0], (UINT8)(c&255), vid.width * vid.height * vid.bpp); + return; } - if (vid.height != BASEVIDHEIGHT * dupy) + + dest = screens[0] + y*dupy*vid.width + x*dupx; + deststop = screens[0] + vid.rowbytes * vid.height; + + if (w == BASEVIDWIDTH) + w = vid.width; + else + w *= dupx; + if (h == BASEVIDHEIGHT) + h = vid.height; + else + h *= dupy; + + if (x && y && x + w < vid.width && y + h < vid.height) { - // same thing here - if (c & V_SNAPTOBOTTOM) - dest += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width; - else if (!(c & V_SNAPTOTOP)) - dest += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width / 2; + // Center it if necessary + if (vid.width != BASEVIDWIDTH * dupx) + { + // dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx, + // so center this imaginary screen + if (c & V_SNAPTORIGHT) + dest += (vid.width - (BASEVIDWIDTH * dupx)); + else if (!(c & V_SNAPTOLEFT)) + dest += (vid.width - (BASEVIDWIDTH * dupx)) / 2; + } + if (vid.height != BASEVIDHEIGHT * dupy) + { + // same thing here + if (c & V_SNAPTOBOTTOM) + dest += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width; + else if (!(c & V_SNAPTOTOP)) + dest += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width / 2; + } } } @@ -968,45 +976,38 @@ void V_DrawFadeScreen(void) } // Simple translucency with one color, over a set number of lines starting from the top. -void V_DrawFadeConsBack(INT32 plines, INT32 pcolor) +void V_DrawFadeConsBack(INT32 plines) { - UINT8 *deststop, *colormap, *buf; + UINT8 *deststop, *buf; #ifdef HWRENDER // not win32 only 19990829 by Kin if (rendermode != render_soft && rendermode != render_none) { UINT32 hwcolor; - switch (pcolor) + switch (cons_backcolor.value) { - case 0: hwcolor = 0xffffff00; break; //white - case 1: hwcolor = 0xff800000; break; //orange - case 2: hwcolor = 0x0000ff00; break; //blue - case 3: hwcolor = 0x00800000; break; //green - case 4: hwcolor = 0x80808000; break; //gray - case 5: hwcolor = 0xff000000; break; //red - default: hwcolor = 0x00800000; break; //green + case 0: hwcolor = 0xffffff00; break; // White + case 1: hwcolor = 0x80808000; break; // Gray + case 2: hwcolor = 0x40201000; break; // Brown + case 3: hwcolor = 0xff000000; break; // Red + case 4: hwcolor = 0xff800000; break; // Orange + case 5: hwcolor = 0x80800000; break; // Yellow + case 6: hwcolor = 0x00800000; break; // Green + case 7: hwcolor = 0x0000ff00; break; // Blue + case 8: hwcolor = 0x4080ff00; break; // Cyan + // Default green + default: hwcolor = 0x00800000; break; } HWR_DrawConsoleBack(hwcolor, plines); return; } #endif - switch (pcolor) - { - case 0: colormap = cwhitemap; break; - case 1: colormap = corangemap; break; - case 2: colormap = cbluemap; break; - case 3: colormap = cgreenmap; break; - case 4: colormap = cgraymap; break; - case 5: colormap = credmap; break; - default: colormap = cgreenmap; break; - } - // heavily simplified -- we don't need to know x or y position, // just the stop position deststop = screens[0] + vid.rowbytes * min(plines, vid.height); for (buf = screens[0]; buf < deststop; ++buf) - *buf = colormap[*buf]; + *buf = consolebgmap[*buf]; } // Gets string colormap, used for 0x80 color codes diff --git a/src/v_video.h b/src/v_video.h index 70255d0ef..353f84c1d 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -145,7 +145,7 @@ void V_DrawFlatFill(INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatnum); // fade down the screen buffer before drawing the menu over void V_DrawFadeScreen(void); -void V_DrawFadeConsBack(INT32 plines, INT32 pcolor); +void V_DrawFadeConsBack(INT32 plines); // draw a single character void V_DrawCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed); diff --git a/src/win32/win_sys.c b/src/win32/win_sys.c index 0331080c8..80b89a6e6 100644 --- a/src/win32/win_sys.c +++ b/src/win32/win_sys.c @@ -3598,6 +3598,18 @@ INT32 I_PutEnv(char *variable) return putenv(variable); } +INT32 I_ClipboardCopy(const char *data, size_t size) +{ + (void)data; + (void)size; + return -1; +} + +const char *I_ClipboardPaste(void) +{ + return NULL; +} + typedef BOOL (WINAPI *p_IsProcessorFeaturePresent) (DWORD); const CPUInfoFlags *I_CPUInfo(void) diff --git a/src/win32ce/win_sys.c b/src/win32ce/win_sys.c index 88764ef73..3b6a47258 100644 --- a/src/win32ce/win_sys.c +++ b/src/win32ce/win_sys.c @@ -3470,6 +3470,18 @@ INT32 I_PutEnv(char *variable) return putenv(variable); } +INT32 I_ClipboardCopy(const char *data, size_t size) +{ + (void)data; + (void)size; + return -1; +} + +char *I_ClipboardPaste(void) +{ + return NULL; +} + typedef BOOL (WINAPI *MyFunc3) (DWORD); const CPUInfoFlags *I_CPUInfo(void)