mirror of
https://github.com/kevinbentley/Descent3.git
synced 2025-01-23 03:58:59 +00:00
dc138e4912
This definition was used to control the accessibility of some class members, changing protected qualifiers to public. This introduced unnecessary coupling between components and headers. All conditional access specifiers have been set to public, which should not be a problem given the low number of classes that actually used affected members. Another albeit more complex solution could have been to use friend classes.
514 lines
12 KiB
C++
514 lines
12 KiB
C++
/*
|
|
* Descent 3
|
|
* Copyright (C) 2024 Parallax Software
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
--- HISTORICAL COMMENTS FOLLOW ---
|
|
|
|
* $Logfile: /DescentIII/Main/linux/lnxcon.cpp $
|
|
* $Revision: 1.2 $
|
|
* $Date: 2004/02/25 00:04:06 $
|
|
* $Author: ryan $
|
|
*
|
|
* <insert description of file here>
|
|
*
|
|
* $Log: lnxcon.cpp,v $
|
|
* Revision 1.2 2004/02/25 00:04:06 ryan
|
|
* Removed loki_utils dependency and ported to MacOS X (runs, but incomplete).
|
|
*
|
|
* Revision 1.1.1.1 2000/04/18 00:00:39 icculus
|
|
* initial checkin
|
|
*
|
|
*
|
|
* 7 7/19/99 12:54p Jeff
|
|
* created lnxcon_raw.cpp so ncurses is now only used for SVGALib, cuts
|
|
* down on redraw
|
|
*
|
|
* 6 6/24/99 4:43p Jeff
|
|
* removed ncurses dependency
|
|
*
|
|
* 5 4/22/99 2:04a Jeff
|
|
* support for null console
|
|
*
|
|
* 4 4/19/99 4:52p Jeff
|
|
* removed useless calls to curses lib for keyboard setup
|
|
*
|
|
* 3 4/19/99 3:58a Jeff
|
|
* got console working again (keyboard based off ddio)
|
|
*
|
|
* 2 4/14/99 1:59a Jeff
|
|
* fixed case mismatched #includes
|
|
*
|
|
* 1 1/12/99 3:42a Jeff
|
|
*
|
|
* $NoKeywords: $
|
|
*/
|
|
|
|
#include "application.h"
|
|
#include "AppConsole.h"
|
|
#include "TaskSystem.h"
|
|
#include "mono.h"
|
|
#include "pstring.h"
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <ctype.h>
|
|
|
|
#include "linux/dyna_curses.h"
|
|
|
|
#include <algorithm>
|
|
|
|
//////////////////////////////////////////////////
|
|
// Defines
|
|
#define CON_MAX_STRINGLEN 768
|
|
|
|
#define CON_MAINWND 0x01
|
|
#define CON_INPUTWND 0x02
|
|
|
|
enum { Console_normal, Console_null, Console_raw } Console_mode;
|
|
|
|
////////////////////////////////////////////////
|
|
// NULL driver functions
|
|
void con_null_Printf(const char *fmt, ...);
|
|
bool con_null_Input(char *buf, int buflen);
|
|
void con_null_Defer(void);
|
|
bool con_null_Create(void);
|
|
void con_null_Destroy(void);
|
|
void con_null_Puts(int window, const char *str);
|
|
|
|
////////////////////////////////////////////////
|
|
// raw driver functions
|
|
void con_raw_Printf(const char *fmt, ...);
|
|
bool con_raw_Input(char *buf, int buflen);
|
|
void con_raw_Defer(void);
|
|
bool con_raw_Create(void);
|
|
void con_raw_Destroy(void);
|
|
void con_raw_Puts(int window, const char *str);
|
|
|
|
//////////////////////////////////////////////////
|
|
// Global Variables
|
|
char *Con_read_buf = NULL; // The next buffer of text from user input
|
|
char *Con_inp_buf = NULL, Con_inp_pos = 0; // Currently updating input buffer of text (and it's position)
|
|
char Con_last_command[CON_MAX_STRINGLEN]; // The last command entered by the user
|
|
int Con_cols = 0, Con_rows = 0; // The size of the main window (input window is (1 row, Con_cols))
|
|
bool Con_newline = false;
|
|
bool Con_init = false; // Console has been initialized
|
|
WINDOW *Con_main_wnd_ptr = NULL, *Con_input_wnd_ptr = NULL; // Window handles for the subwindows
|
|
|
|
#ifdef mem_malloc
|
|
#undef mem_malloc
|
|
#endif
|
|
#ifdef mem_free
|
|
#undef mem_free
|
|
#endif
|
|
#define mem_malloc(x) malloc(x)
|
|
#define mem_free(x) free(x)
|
|
|
|
//////////////////////////////////////////////////
|
|
// Prototypes
|
|
void con_Update(int windows); // Refreshes a window
|
|
void con_Defer(void); // Performs the actions for the frame
|
|
void con_DoKeyboard(void); // Handles any keyboard input
|
|
void con_Puts(int window, const char *str);
|
|
//////////////////////////////////////////////////
|
|
// Functions
|
|
void con_Update(int windows) {
|
|
if (!Con_init) // console hasn't been initialized yet, short circuit
|
|
return;
|
|
|
|
if (Console_mode == Console_null || Console_mode == Console_raw) {
|
|
return;
|
|
}
|
|
|
|
if (windows & CON_MAINWND) // update the main window
|
|
wnoutrefresh(Con_main_wnd_ptr);
|
|
if (windows & CON_INPUTWND) { // update the input data window
|
|
// clear the line
|
|
wclear(Con_input_wnd_ptr);
|
|
|
|
mvwprintw(Con_input_wnd_ptr, 0, 0, "%s", Con_inp_buf);
|
|
touchwin(Con_input_wnd_ptr);
|
|
wnoutrefresh(Con_input_wnd_ptr);
|
|
leaveok(Con_input_wnd_ptr, false);
|
|
}
|
|
// update the screen
|
|
doupdate();
|
|
|
|
int len = strlen(Con_inp_buf);
|
|
mvwin(Con_input_wnd_ptr, Con_rows, len);
|
|
move(Con_rows, len);
|
|
}
|
|
|
|
void con_Printf(const char *fmt, ...) {
|
|
if (!Con_init) // console hasn't been initialized yet, short circuit
|
|
return;
|
|
|
|
char buf[CON_MAX_STRINGLEN];
|
|
va_list args;
|
|
|
|
// filter out messages
|
|
va_start(args, fmt);
|
|
vsnprintf(buf, sizeof(buf), fmt, args);
|
|
va_end(args);
|
|
|
|
// filter out unprintable characters
|
|
char *p, *fp, filter_buf[CON_MAX_STRINGLEN];
|
|
p = buf;
|
|
fp = filter_buf;
|
|
|
|
while (*p) {
|
|
if (*p == 0x01) {
|
|
// this is a color, skip the next 3
|
|
p += 4;
|
|
} else {
|
|
if (isalnum(*p) || ispunct(*p) || (*p == ' ') || (*p == '\n') || (*p == '\r') || (*p == '\b')) {
|
|
*fp = *p;
|
|
fp++;
|
|
}
|
|
p++;
|
|
}
|
|
}
|
|
*fp = '\0';
|
|
|
|
switch (Console_mode) {
|
|
case Console_null:
|
|
con_null_Puts(0, filter_buf);
|
|
break;
|
|
case Console_raw:
|
|
con_raw_Puts(0, filter_buf);
|
|
break;
|
|
case Console_normal:
|
|
con_Puts(CON_MAINWND, filter_buf);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool con_Input(char *buf, int buflen) {
|
|
if (!Con_init) { // the console hasn't been initialized yet
|
|
*buf = '\0';
|
|
return false;
|
|
}
|
|
|
|
if (Console_mode == Console_null) {
|
|
*buf = '\0';
|
|
return false;
|
|
}
|
|
|
|
if (Console_mode == Console_raw) {
|
|
return con_raw_Input(buf, buflen);
|
|
}
|
|
|
|
if (!Con_read_buf) { // there is no read buffer...yipes
|
|
*buf = '\0';
|
|
return false;
|
|
}
|
|
|
|
if (Con_read_buf[0]) {
|
|
// we have a new buffer of input...send it away
|
|
strncpy(buf, Con_read_buf, buflen - 1);
|
|
buf[buflen - 1] = 0;
|
|
Con_read_buf[0] = 0;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void con_Defer(void) {
|
|
if (!Con_init) // the console hasn't been initialized yet
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (Console_mode == Console_null) {
|
|
con_null_Defer();
|
|
return;
|
|
}
|
|
|
|
if (Console_mode == Console_raw) {
|
|
con_raw_Defer();
|
|
return;
|
|
}
|
|
|
|
// handle any keyboard input
|
|
con_DoKeyboard();
|
|
}
|
|
|
|
bool con_Create(int flags) {
|
|
// determine what type of console to open up
|
|
if (flags & APPFLAG_USESERVICE) {
|
|
// use the NULL driver!
|
|
Console_mode = Console_null;
|
|
} else {
|
|
if (flags & APPFLAG_USESVGA) {
|
|
// use the regular ncurses driver
|
|
Console_mode = Console_normal;
|
|
} else {
|
|
// use stdout driver
|
|
Console_mode = Console_raw;
|
|
}
|
|
}
|
|
|
|
if (Console_mode == Console_null) {
|
|
Con_init = con_null_Create();
|
|
return Con_init;
|
|
}
|
|
|
|
if (Console_mode == Console_raw) {
|
|
Con_init = con_raw_Create();
|
|
return Con_init;
|
|
}
|
|
|
|
if (!LoadCursesLib(true)) {
|
|
fprintf(stderr, "LoadLib: Unable to load ncurses lib\n");
|
|
exit(-1);
|
|
} else {
|
|
fprintf(stderr, "LoadLib: Loaded ncurses lib\n");
|
|
}
|
|
|
|
// start up the curses library
|
|
initscr();
|
|
|
|
Con_cols = COLS;
|
|
Con_rows = LINES - 1; // one less, since the bottom window takes up one row
|
|
|
|
// create the sub windows
|
|
Con_main_wnd_ptr = newwin(Con_rows, Con_cols, 0, 0);
|
|
Con_input_wnd_ptr = newwin(1, Con_cols, Con_rows, 0);
|
|
|
|
if (!Con_main_wnd_ptr || !Con_input_wnd_ptr) {
|
|
// error creating subdirectories.
|
|
return false;
|
|
}
|
|
|
|
// clear the subwindows to make them nice
|
|
wclear(Con_main_wnd_ptr);
|
|
wclear(Con_input_wnd_ptr);
|
|
wrefresh(Con_main_wnd_ptr);
|
|
wrefresh(Con_input_wnd_ptr);
|
|
scrollok(Con_main_wnd_ptr, true);
|
|
leaveok(Con_input_wnd_ptr, true);
|
|
leaveok(Con_main_wnd_ptr, true);
|
|
|
|
// allocate any memory needed for buffers
|
|
Con_inp_buf = (char *)mem_malloc(sizeof(char) * (Con_cols + 4));
|
|
Con_read_buf = (char *)mem_malloc(sizeof(char) * (Con_cols + 4));
|
|
if (!Con_inp_buf || !Con_read_buf) {
|
|
// error allocating memory
|
|
return false;
|
|
}
|
|
memset(Con_inp_buf, 0, sizeof(char) * (Con_cols + 4));
|
|
memset(Con_read_buf, 0, sizeof(char) * (Con_cols + 4));
|
|
Con_last_command[0] = '\0';
|
|
|
|
// setup the keyboard for use
|
|
//! crmode();
|
|
//! keypad(stdscr,TRUE);
|
|
//! noecho();
|
|
//! cbreak();
|
|
// nodelay(stdscr,true);
|
|
|
|
Con_inp_pos = 0;
|
|
Con_init = true;
|
|
|
|
move(0, 0);
|
|
con_Update(CON_INPUTWND);
|
|
con_Update(CON_MAINWND);
|
|
|
|
return true;
|
|
}
|
|
|
|
void con_Destroy(void) {
|
|
if (Console_mode == Console_null) {
|
|
con_null_Destroy();
|
|
return;
|
|
}
|
|
if (Console_mode == Console_raw) {
|
|
con_raw_Destroy();
|
|
return;
|
|
}
|
|
|
|
// reset the keyboard
|
|
//! echo();
|
|
//! nocbreak();
|
|
|
|
// delete the sub windows
|
|
if (Con_main_wnd_ptr)
|
|
delwin(Con_main_wnd_ptr);
|
|
Con_main_wnd_ptr = NULL;
|
|
if (Con_input_wnd_ptr)
|
|
delwin(Con_input_wnd_ptr);
|
|
Con_input_wnd_ptr = NULL;
|
|
|
|
// free any allocated memory
|
|
if (Con_inp_buf) {
|
|
mem_free(Con_inp_buf);
|
|
Con_inp_buf = NULL;
|
|
}
|
|
|
|
if (Con_read_buf) {
|
|
mem_free(Con_read_buf);
|
|
Con_read_buf = NULL;
|
|
}
|
|
Con_cols = Con_rows = 0;
|
|
|
|
// shutdown curses
|
|
endwin();
|
|
|
|
LoadCursesLib(false);
|
|
}
|
|
|
|
// put some data up on the screen
|
|
void con_Puts(int window, const char *str) {
|
|
if (Console_mode == Console_null) {
|
|
con_null_Puts(window, str);
|
|
return;
|
|
}
|
|
if (Console_mode == Console_raw) {
|
|
con_raw_Puts(window, str);
|
|
return;
|
|
}
|
|
|
|
int string_len = strlen(str);
|
|
if (!string_len)
|
|
return;
|
|
|
|
if (window & CON_MAINWND) {
|
|
// add the string to the main window
|
|
if (Con_main_wnd_ptr) {
|
|
wprintw(Con_main_wnd_ptr, str);
|
|
}
|
|
}
|
|
|
|
if (window & CON_INPUTWND) {
|
|
// add the string to the input window
|
|
|
|
// fill in the buffer
|
|
if (Con_input_wnd_ptr)
|
|
wprintw(Con_input_wnd_ptr, str);
|
|
}
|
|
|
|
con_Update(window);
|
|
}
|
|
|
|
// HACK!!! this shouldn't be dependant...oh well
|
|
int ddio_KeyInKey();
|
|
int ddio_KeyToAscii(int code);
|
|
|
|
void con_DoKeyboard(void) {
|
|
int keypressed = ddio_KeyInKey();
|
|
|
|
while (keypressed != 0) {
|
|
// we got a key...handle it
|
|
switch (keypressed) {
|
|
case 0xCB: // KEY_LEFT: // Left arrow
|
|
Con_inp_pos = std::max(Con_inp_pos - 1, 0);
|
|
con_Update(CON_INPUTWND);
|
|
break;
|
|
|
|
case 0xCD: // KEY_RIGHT: // Right arrow
|
|
{
|
|
int len = strlen(Con_inp_buf);
|
|
Con_inp_pos = std::min(Con_inp_pos + 1, len);
|
|
con_Update(CON_INPUTWND);
|
|
} break;
|
|
|
|
case 0xC8: // KEY_UP: // Up arrow
|
|
// Replace the current buffer that is being typed with the last completed command (if there was one)
|
|
if (Con_last_command[0] != 0) {
|
|
memset(Con_inp_buf, 0, Con_cols + 4);
|
|
strcpy(Con_inp_buf, Con_last_command);
|
|
|
|
Con_inp_pos = strlen(Con_last_command);
|
|
|
|
con_Update(CON_INPUTWND);
|
|
}
|
|
break;
|
|
|
|
case 0xD3: // KEY_DELETE: // Delete
|
|
{
|
|
// Move all the characters that followed the
|
|
// deleted character (on the same line) one
|
|
// space back (to the left) in the matrix.
|
|
for (int x = Con_inp_pos; x < Con_cols; x++)
|
|
Con_inp_buf[x] = Con_inp_buf[x + 1];
|
|
|
|
con_Update(CON_INPUTWND);
|
|
} break;
|
|
case 0x0E: // KEY_BACKSP:
|
|
{
|
|
// Move the caret back one space, and then
|
|
// process this like the DEL key.
|
|
if (Con_inp_pos > 0) {
|
|
Con_inp_pos--;
|
|
|
|
for (int x = Con_inp_pos; x < Con_cols; x++)
|
|
Con_inp_buf[x] = Con_inp_buf[x + 1];
|
|
|
|
con_Update(CON_INPUTWND);
|
|
}
|
|
} break;
|
|
case 0x1C: // KEY_ENTER:
|
|
{
|
|
// Go to the beginning of the next line.
|
|
// The bottom line wraps around to the top.
|
|
strcpy(Con_read_buf, Con_inp_buf);
|
|
strcat(Con_inp_buf, "\n");
|
|
|
|
// add the string to the buffer
|
|
con_Puts(CON_MAINWND, Con_inp_buf);
|
|
|
|
// only save the buffer if there is text in the buffer
|
|
char *p = Con_read_buf;
|
|
while (*p) {
|
|
if (isalnum(*p)) {
|
|
strcpy(Con_last_command, Con_read_buf);
|
|
break;
|
|
}
|
|
p++;
|
|
}
|
|
|
|
memset(Con_inp_buf, 0, Con_cols + 4);
|
|
Con_inp_pos = 0;
|
|
con_Update(CON_INPUTWND);
|
|
} break;
|
|
case 0x01: // KEY_ESC: // Escape
|
|
{
|
|
memset(Con_inp_buf, 0, Con_cols + 4);
|
|
Con_inp_pos = 0;
|
|
con_Update(CON_INPUTWND);
|
|
} break;
|
|
default:
|
|
if (Con_inp_pos < (Con_cols - 2)) {
|
|
// Add the character to the text buffer.
|
|
unsigned char str[2];
|
|
str[0] = ddio_KeyToAscii(keypressed);
|
|
str[1] = 0;
|
|
if (str[0] != 255) {
|
|
Con_inp_buf[Con_inp_pos] = str[0];
|
|
Con_inp_buf[Con_inp_pos + 1] = '\0';
|
|
con_Update(CON_INPUTWND);
|
|
Con_inp_pos++;
|
|
}
|
|
}
|
|
}
|
|
|
|
keypressed = ddio_KeyInKey();
|
|
}
|
|
}
|