Make 'Escape' exit the console instead of the game if console is down
[attac-man.git] / oglconsole.c
blobec153a7426967174a097597c1da736c4375bd91f
1 /* oglconsole -- gpl license here */
3 /* This strategy seems to offer the convenience of zero-configuration, but
4 * obviously it also offers defining GLHEADERINCLUDE */
5 #ifdef GLHEADERINCLUDE
6 # include GLHEADERINCLUDE
7 #else
8 # ifdef __MACH__
9 # include <OpenGL/gl.h>
10 # else
11 # include <GL/gl.h>
12 # endif
13 #endif
15 #include "oglconsole.h"
17 #include <string.h>
18 #include <stdarg.h>
19 #include <stdlib.h>
20 #include <stdio.h>
22 #define C ((_OGLCONSOLE_Console*)console)
24 /* OGLCONSOLE font */
25 #include "ConsoleFont.c"
26 #define FIRST_CHARACTER ' '
27 #define LAST_CHARACTER '~'
29 #define CHAR_PIXEL_W 6
30 #define CHAR_PIXEL_H 13
31 #define CHAR_WIDTH 0.0234375 /* ogl tex coords */
32 #define CHAR_HEIGHT 0.203125 /* ogl tex coords */
34 /* This is how long the animation should take to make the transition between
35 * "hidden" and "visible" console visibility modes (expressed in milliseconds) */
36 #define SLIDE_MS 700
38 /* If we don't know how to retrieve the time then we can just use a number of
39 * frames to divide up the time it takes to transition between "hidden" and
40 * "visible" console visibility modes */
41 #define SLIDE_STEPS 25
43 GLuint OGLCONSOLE_glFontHandle = 0;
44 int
45 OGLCONSOLE_CreateFont(void)
48 int err = glGetError();
49 if (err)
50 printf("GL ERROR: %i\n", err);
52 #ifdef DEBUG
53 puts("Creating OGLCONSOLE font");
54 #endif
56 /* Get a font index from OpenGL */
57 glGenTextures(1, &OGLCONSOLE_glFontHandle);
59 int err = glGetError();
60 if (err)
61 printf("glGenTextures() error: %i\n", err);
64 /* Select our font */
65 glBindTexture(GL_TEXTURE_2D, OGLCONSOLE_glFontHandle);
67 int err = glGetError();
68 if (err)
69 printf("glBindTexture() error: %i\n", err);
72 /* Set some parameters i guess */
73 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
74 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
76 /* Upload our font */
77 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
78 OGLCONSOLE_FontData.width, OGLCONSOLE_FontData.height, 0,
79 GL_RGB, GL_UNSIGNED_BYTE, OGLCONSOLE_FontData.pixel_data);
82 int err = glGetError();
83 if (err)
84 printf("glTexImage2D() error: %i\n", err);
87 #ifdef DEBUG
88 puts("Created OGLCONSOLE font");
89 #endif
90 return 1;
93 /* TODO: Expose these macros to the user? */
95 /* This is the longest command line that the user can enter TODO: Make dynamic
96 * so that the user can enter any length line */
97 #define MAX_INPUT_LENGTH 256
99 /* This is the number of command line entries that the console will remember (so
100 * that the user can use the up/down keys to see and easily re-execute his past
101 * commands) */
102 #define MAX_HISTORY_COUNT 25
104 /* This is the default number of lines for the console to remember (that is to
105 * say, the user can scroll up and down to see what has been printed to the
106 * console in the past, and this is the number of those lines, plus the number
107 * of lines shown on the screen at all times) */
108 #define DEFAULT_MAX_LINES 100
110 /* OGLCONSOLE console structure */
111 typedef struct {
112 GLdouble mvMatrix[16];
113 int mvMatrixUse;
115 GLdouble pMatrix[16];
116 int pMatrixUse;
118 /* Screen+scrollback lines (console output) */
119 char *lines;
120 int maxLines, lineQueueIndex, lineScrollIndex;
122 /* History scrollback (command input) */
123 char history[MAX_HISTORY_COUNT][MAX_INPUT_LENGTH];
124 int historyQueueIndex, historyScrollIndex;
126 /* Current input line */
127 char inputLine[MAX_INPUT_LENGTH];
128 int inputCursorPos, inputLineLength;
130 /* Rows and columns of text to display */
131 int textWidth, textHeight;
133 /* Current column of text where new text will be inserted */
134 char *outputCursor;
135 int outputNewline;
137 /* Width and height of a single character for the GL */
138 GLdouble characterWidth, characterHeight;
140 /* Basic options */
141 int visibility;
143 /* Various callback functions defined by the user */
144 void (*enterKeyCallback) (OGLCONSOLE_Console console, char *cmd);
146 } _OGLCONSOLE_Console;
148 /* To save code, I've gone with an imperative "modal" kind of interface */
149 _OGLCONSOLE_Console *programConsole = NULL;
151 /* This console is the console currently receiving user input */
152 _OGLCONSOLE_Console *userConsole = NULL;
154 /* Set the callback for a console */
155 void
156 OGLCONSOLE_EnterKey(void (*cbfun) (OGLCONSOLE_Console console, char *cmd))
158 programConsole->enterKeyCallback = cbfun;
161 void
162 OGLCONSOLE_DefaultEnterKeyCallback(OGLCONSOLE_Console console, char __attribute__((unused)) *cmd)
164 OGLCONSOLE_Output(console,
165 "No enter key callback is registered for this console!\n");
168 OGLCONSOLE_Console
169 OGLCONSOLE_Create()
171 _OGLCONSOLE_Console *console;
172 GLint viewport[4];
174 /* If font hasn't been created, we create it */
175 if (!glIsTexture(OGLCONSOLE_glFontHandle))
176 OGLCONSOLE_CreateFont();
178 /* Allocate memory for our console */
179 console = (void *) malloc(sizeof (_OGLCONSOLE_Console));
181 /* Textual dimensions */
182 glGetIntegerv(GL_VIEWPORT, viewport);
183 console->textWidth = viewport[2] / CHAR_PIXEL_W;
184 console->textHeight = viewport[3] / CHAR_PIXEL_H;
185 console->characterWidth = 1.0 / console->textWidth;
186 console->characterHeight = 1.0 / console->textHeight;
188 /* Different values have different meanings for xMatrixUse:
189 0) Do not change the matrix before rendering
190 1) Upload the console's matrix before rendering
191 2) Multiply the console's matrix before rendering */
193 /* Initialize its projection matrix */
194 console->pMatrixUse = 1;
195 glMatrixMode(GL_PROJECTION);
196 glPushMatrix();
197 glOrtho(0, console->textWidth, 0, console->textHeight, -1, 1);
198 glGetDoublev(GL_MODELVIEW_MATRIX, console->pMatrix);
199 glPopMatrix();
201 /* Initialize its modelview matrix */
202 console->mvMatrixUse = 1;
203 glMatrixMode(GL_MODELVIEW);
204 glPushMatrix();
205 glLoadIdentity();
206 glTranslated(-1, -1, 0);
207 glScaled(2, 2, 1);
208 glGetDoublev(GL_MODELVIEW_MATRIX, console->mvMatrix);
209 glPopMatrix();
211 /* Screen and scrollback lines */
212 /* This is the total number of screen lines in memory (start blank) */
213 console->maxLines = DEFAULT_MAX_LINES;
214 /* Allocate space for text */
215 console->lines =
216 (char *) malloc(console->maxLines * (console->textWidth + 1));
217 /* Initialize to empty strings */
218 memset(console->lines, 0, console->maxLines * (console->textWidth + 1));
219 /* This variable represents whether or not a newline has been left */
220 console->outputNewline = 0;
221 /* This cursor points to the X pos where console output is next destined */
222 console->outputCursor = console->lines;
223 /* This cursor points to what line console output is next destined for */
224 console->lineQueueIndex = 0;
225 /* This cursor points to what line the console view is scrolled to */
226 console->lineScrollIndex = console->maxLines - console->textHeight + 1;
228 /* Initialize the user's input (command line) */
229 console->inputLineLength = 0;
230 console->inputCursorPos = 0;
231 console->inputLine[0] = '\0';
233 /* History lines */
234 memset(console->history, 0, MAX_INPUT_LENGTH * MAX_HISTORY_COUNT);
235 console->historyQueueIndex = 0;
236 console->historyScrollIndex = -1;
238 /* Callbacks */
239 console->enterKeyCallback = OGLCONSOLE_DefaultEnterKeyCallback;
241 /* The console starts life invisible */
242 console->visibility = 0;
244 /* If no consoles existed before, we select this one for convenience */
245 if (!programConsole)
246 programConsole = console;
247 if (!userConsole)
248 userConsole = console;
250 /* Temporary shit */
251 OGLCONSOLE_Output((void *) console, "Console initialized\n");
253 OGLCONSOLE_Output((void *) console,
254 "Console display lines: %i\n", console->textHeight);
256 OGLCONSOLE_Output((void *) console,
257 "Console display columns: %i\n", console->textWidth);
259 OGLCONSOLE_Output((void *) console,
260 "Console input length: %i\n", MAX_INPUT_LENGTH);
262 /* Return the opaque pointer to the programmer */
263 return (OGLCONSOLE_Console) console;
266 /* This functoin is only used internally; the user ultimately invokes this
267 * function through either a call to Destroy() or Quit(); the purpose of this
268 * mechanism is to warn the user if he has explicitly destroyed a console that
269 * was engaged in operation at the time they destroyed it (the only two
270 * operations a console can be engaged in are receiving programmer interaction,
271 * or receiving end-user interaction. fyi, "user" always refers to the
272 * programmer, end-user refers to the real end-user) */
273 void
274 OGLCONSOLE_DestroyReal(OGLCONSOLE_Console console, int warn)
276 free(C);
278 if (warn) {
279 if (programConsole == C) {
280 fprintf(stderr,
281 "Warning: OGLCONSOLE you just destroyed the programConsole!\n");
282 programConsole = NULL;
285 if (userConsole == C) {
286 fprintf(stderr,
287 "Warning: OGLCONSOLE you just destroyed the userConsole!\n");
288 userConsole = NULL;
293 /* The user can call this function to free a console. A warning is printed to
294 * stderr if the user has destroyed a console destroyed while it was receiving
295 * input, see DestroyReal() for details TODO: there are currently no semantics
296 * under consideration for explicitly destroying an 'engaged' console WITHOUT
297 * having a warning issued, nor is there a way to deselect a console without
298 * also selecting a new one as of yet */
299 void
300 OGLCONSOLE_Destroy(OGLCONSOLE_Console console)
302 OGLCONSOLE_DestroyReal(console, 1);
305 /* This function frees all of the consoles that the library is actively aware
306 * of, and is intended to be used by programs that have only a single console;
307 * technically this particular function will free up to two consoles, but don't
308 * count on it because that may change; no warnings are issued by this function */
309 void
310 OGLCONSOLE_Quit()
312 OGLCONSOLE_DestroyReal((void *) programConsole, 0);
313 if (programConsole != userConsole)
314 OGLCONSOLE_DestroyReal((void *) userConsole, 0);
315 programConsole = NULL;
316 userConsole = NULL;
319 /* Select a console to receive input from the user (read: programmer); this
320 * function is intended for use by applications which create MORE THAN ONE
321 * console, since every newly created console is automatically selected for
322 * programmer input ('programmer input' refers to calling any function which
323 * does not specify a console explicitly in its parameter list. the console
324 * which is 'engaged' by 'programmer input' at the time of calling one of these
325 * functions is the console that function will operate on */
326 void
327 OGLCONSOLE_EditConsole(OGLCONSOLE_Console console)
329 programConsole = C;
332 /* Show or hide a console */
333 void
334 OGLCONSOLE_SetVisibility(int __attribute__ ((unused)) visible)
338 /* Get current configuration information about a console */
339 void
340 OGLCONSOLE_Info(void)
342 puts("TODO: print some console info here");
345 /* This routine is meant for applications with a single console, if you use
346 * multiple consoles in your program, use Render() instead */
347 void
348 OGLCONSOLE_Draw()
350 OGLCONSOLE_Render((void *) userConsole);
353 /* Internal functions for drawing text. You don't want these, do you? */
354 void OGLCONSOLE_DrawString(char *s, double x, double y, double w, double h,
355 double z);
356 void OGLCONSOLE_DrawWrapString(char *s, double x, double y, double w, double h,
357 double z, int wrap);
358 void OGLCONSOLE_DrawCharacter(int c, double x, double y, double w, double h,
359 double z);
361 /* This function draws a single specific console; if you only use one console in
362 * your program, use Draw() instead */
363 void
364 OGLCONSOLE_Render(OGLCONSOLE_Console console)
366 /* Don't render hidden console */
367 if (C->visibility == 0)
368 return;
370 glMatrixMode(GL_PROJECTION);
371 glPushMatrix();
372 glLoadMatrixd(C->pMatrix);
374 glMatrixMode(GL_MODELVIEW);
375 glPushMatrix();
376 glLoadMatrixd(C->mvMatrix);
378 glPushAttrib(GL_ALL_ATTRIB_BITS);
380 /* glEnable(GL_BLEND);
381 glBlendFunc(GL_ONE, GL_ONE);*/
383 /* TODO: This SHOULD become an option at some point because the
384 * infrastructure for "real" consoles in the game (like you could walk up to
385 * a computer terminal and manipulate a console on a computer using
386 * oglconsole) already exists; you'd want depth testing in that case */
387 glDisable(GL_DEPTH_TEST);
389 /* Render hiding / showing console in a special manner. Zero means hidden. 1
390 * means visible. All other values are traveling toward zero or one. TODO:
391 * Make this time dependent */
392 if (C->visibility != 1) {
393 double d; /* bra size */
394 int v = C->visibility;
396 /* Count down in both directions */
397 if (v < 0) {
398 v ^= -1;
399 C->visibility++;
400 } else {
401 v = SLIDE_STEPS - v;
402 C->visibility--;
405 d = 0.04 * v;
406 glTranslated(0, 1 - d, 0);
409 /* First we draw our console's background TODO: Add something fancy? */
410 glDisable(GL_TEXTURE_2D);
411 glEnable(GL_BLEND);
413 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
414 // glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_COLOR);
415 glColor4d(.1, 0, 0, 0.5);
417 glBegin(GL_QUADS);
418 glVertex3d(0, 0, 0);
419 glVertex3d(1, 0, 0);
420 glVertex3d(1, 1, 0);
421 glVertex3d(0, 1, 0);
422 glEnd();
424 // Change blend mode for drawing text
425 glBlendFunc(GL_ONE, GL_ONE);
427 /* Select the console font */
428 glEnable(GL_TEXTURE_2D);
429 glBindTexture(GL_TEXTURE_2D, OGLCONSOLE_glFontHandle);
431 /* Recolor text */
432 glColor3d(0, 1, 0);
434 /* Render console contents */
435 glBegin(GL_QUADS);
437 /* Graphical line, and line in lines[] */
438 int gLine, tLine = C->lineScrollIndex;
440 /* Iterate through each line being displayed */
441 for (gLine = 0; gLine < C->textHeight; gLine++) {
442 /* Draw this line of text adjusting for user scrolling up/down */
443 OGLCONSOLE_DrawString(C->lines + (tLine * C->textWidth),
445 (C->textHeight -
446 gLine) * C->characterHeight,
447 C->characterWidth,
448 C->characterHeight, 0);
450 /* Grab next line of text using wheel-queue wrapping */
451 if (++tLine >= C->maxLines)
452 tLine = 0;
455 /* Here we draw the current commandline, it will either be a line from
456 * the command history or the line being edited atm */
457 if (C->historyScrollIndex >= 0) {
458 glColor3d(1, 0, 0);
459 OGLCONSOLE_DrawString(C->history[C->historyScrollIndex],
460 0, 0,
461 C->characterWidth,
462 C->characterHeight, 0);
463 } else {
464 /* Draw input line cyan */
465 glColor3d(0, 1, 1);
466 OGLCONSOLE_DrawString(C->inputLine,
467 0, 0,
468 C->characterWidth,
469 C->characterHeight, 0);
471 /* Draw cursor beige */
472 glColor3d(1, 1, .5);
473 OGLCONSOLE_DrawCharacter('_' - ' ',
474 C->inputCursorPos *
475 C->characterWidth, 0,
476 C->characterWidth,
477 C->characterHeight, 0);
480 glEnd();
482 /* Relinquish our rendering settings */
483 glMatrixMode(GL_PROJECTION);
484 glPopMatrix();
486 glMatrixMode(GL_MODELVIEW);
487 glPopMatrix();
489 glPopAttrib();
492 /* Issue rendering commands for a single a string */
493 void
494 OGLCONSOLE_DrawString(char *s, double x, double y, double w, double h, double z)
496 while (*s) {
497 OGLCONSOLE_DrawCharacter(*s - ' ', x, y, w, h, z);
498 s++;
499 x += w;
503 /* Issue rendering commands for a single a string */
504 void
505 OGLCONSOLE_DrawWrapString(char *s, double x, double y, double w, double h,
506 double z, int wrap)
508 int pos = 0;
509 double X = x;
511 while (*s) {
512 OGLCONSOLE_DrawCharacter(*s - ' ', X, y, w, h, z);
513 s++;
514 X += w;
516 if (++pos >= wrap) {
517 pos = 0;
518 y += h;
519 X = x;
524 /* Issue rendering commands for a single character */
525 void
526 OGLCONSOLE_DrawCharacter(int c, double x, double y, double w, double h,
527 double z)
529 // static int message = 0;
530 double cx, cy, cX, cY;
532 // if (c < FIRST_CHARACTER || c > LAST_CHARACTER)
533 // c = (c - FIRST_CHARACTER) % (LAST_CHARACTER - FIRST_CHARACTER);
534 // else c -= FIRST_CHARACTER;
536 cx = (c % 42) * CHAR_WIDTH;
537 cy = 1.0 - (c / 42) * CHAR_HEIGHT;
538 cX = cx + CHAR_WIDTH;
539 cY = 1.0 - (c / 42 + 1) * CHAR_HEIGHT;
541 /* if (message != c)
543 printf("For %i we got %f, %f\n", c, x, y);
544 message = c;
547 /* This should occur outside of this function for optimiation TODO: MOVE IT */
548 glTexCoord2d(cx, cy);
549 glVertex3d(x, y, z);
550 glTexCoord2d(cX, cy);
551 glVertex3d(x + w, y, z);
552 glTexCoord2d(cX, cY);
553 glVertex3d(x + w, y + h, z);
554 glTexCoord2d(cx, cY);
555 glVertex3d(x, y + h, z);
558 /* This is the final, internal function for printing text to a console */
559 void
560 OGLCONSOLE_Output(OGLCONSOLE_Console console, const char *s, ...)
562 va_list argument;
564 /* cache some console properties */
565 int lineQueueIndex = C->lineQueueIndex;
566 int lineScrollIndex = C->lineScrollIndex;
567 int textWidth = C->textWidth;
568 int maxLines = C->maxLines;
570 /* String buffer */
571 char output[4096];
573 /* string copy cursors */
574 char *consoleCursor, *outputCursor = output;
576 /* Acrue arguments in argument list */
577 va_start(argument, s);
578 vsnprintf(output, 4096, s, argument);
579 va_end(argument);
581 /* This cursor tells us where in the console display we are currently
582 * copying text into from the "output" string */
583 consoleCursor = C->outputCursor;
585 while (*outputCursor) {
586 /* Here we check to see if any conditions require console line
587 * advancement. These two conditions are:
588 1) Hitting the end of the screen
589 2) Getting a newlien character */
590 if ((C->outputNewline) ||
591 (consoleCursor - (C->lines + lineQueueIndex * textWidth))
592 >= (textWidth - 1)) {
593 C->outputNewline = 0;
595 //puts("incrementing to the next line");
597 /* Inrement text-line index, with wrapping */
598 if (++lineQueueIndex >= maxLines)
599 lineQueueIndex = 0;
601 /* Scroll the console display one line TODO: Don't scroll if the console is
602 * currently scrolled away from the end of output? */
603 if (++lineScrollIndex >= maxLines)
604 lineScrollIndex = 0;
606 /* Reposition the cursor at the beginning of the new line */
607 consoleCursor =
608 C->lines + lineQueueIndex * C->textWidth;
611 /* If we encounter a newline character, we set the newline flag, which
612 * tells the console to advance one line before it prints the next
613 * character. The reason we do it this way is to defer line-advancement,
614 * and thus we needn't suffer through a needless blank line between
615 * console output and the command line, wasting precious screen
616 * real-estate */
617 if (*outputCursor == '\n') {
618 C->outputNewline = 1;
619 outputCursor++;
620 continue;
623 /* copy a single character */
624 *(consoleCursor++) = *(outputCursor++);
627 /* Unless we're at the very end of our current line, we finish up by capping
628 * a NULL terminator on the current line */
629 if (consoleCursor != C->lines + (lineQueueIndex + 1) * C->textWidth - 1)
630 *consoleCursor = '\0';
632 /* Restore cached values */
633 C->lineQueueIndex = lineQueueIndex;
634 C->lineScrollIndex = lineScrollIndex;
635 C->outputCursor = consoleCursor; // TODO: confusing variable names
637 /* old way of copying the text into the console */
638 //strcpy(C->lines[C->lineQueueIndex], output);
639 #ifdef DEBUG
640 printf("Copied \"%s\" into line %i\n", output, C->lineQueueIndex);
641 #endif
644 /* Mono-Console Users: print text to the console; multi-console users use
645 * Output() */
646 void
647 OGLCONSOLE_Print(char *s, ...)
649 va_list argument;
650 char output[4096];
652 /* Acrue arguments in argument list */
653 va_start(argument, s);
654 vsnprintf(output, 4096, s, argument);
655 va_end(argument);
657 /* TODO: Find some way to pass the va_list arguments to OGLCONSOLE_Output
658 * so that we don't waste extra time with the "%s" bullshit */
659 OGLCONSOLE_Output((OGLCONSOLE_Console) userConsole, "%s", output);
662 #if 0
663 /* Multi-Console Users: print text to a specific console; mono-console users use
664 * Print() */
665 void
666 OGLCONSOLE_Output(OGLCONSOLE_Console console, char *s)
668 /* TODO: Chop up output to wrap text */
670 /* TODO: Add auto-scroll (the commented out code here is a failed attempt,
671 * my brain is too scattered to do it) */
672 /* If the console isn't scrolled up, then we move the scroll point */
673 /* if (C->lineQueueIndex - C->lineScrollIndex == C->textHeight)
674 if (++C->lineScrollIndex - C->lineScrollIndex >= MAX_LINE_COUNT)
675 C->lineScrollIndex = 0;*/
678 #endif
680 /* Internal encapsulation of the act for adding a command the user executed to
681 * their command history for that particular console */
682 void
683 OGLCONSOLE_AddHistory(_OGLCONSOLE_Console * console, char *s)
685 if (++C->historyQueueIndex > MAX_HISTORY_COUNT)
686 C->historyQueueIndex = 0;
688 strcpy(C->history[C->historyQueueIndex], s);
691 void
692 OGLCONSOLE_YankHistory(_OGLCONSOLE_Console * console)
694 /* First we have to see if we are browsing our command history */
695 if (console->historyScrollIndex != -1) {
696 /* Copy the selected command into the current input line */
697 strcpy(console->inputLine,
698 console->history[console->historyScrollIndex]);
700 /* Set up this shite */
701 console->inputCursorPos =
702 console->inputLineLength = strlen(console->inputLine);
704 /* Drop out of history browsing mode */
705 console->historyScrollIndex = -1;
709 #ifndef OGLCONSOLE_USE_SDL
710 #error **************************************************************************
711 #error
712 #error
713 #error
714 #error Only SDL is supported so far: you must define the OGLCONSOLE_USE_SDL macro
715 #error
716 #error
717 #error
718 #error **************************************************************************
719 #endif
721 /* This function tries to handle the incoming SDL event. In the future there may
722 * be non-SDL analogs for input systems such as GLUT. Returns true if the event
723 * was handled by the console. If console is hidden, no events are handled. */
724 #ifdef OGLCONSOLE_USE_SDL
725 #include "SDL.h"
726 #define KEY_BACKSPACE SDLK_BACKSPACE
727 #define KEY_DELETE SDLK_DELETE
728 #define KEY_RETURN SDLK_RETURN
729 #define KEY_UP SDLK_UP
730 #define KEY_DOWN SDLK_DOWN
731 #define KEY_LEFT SDLK_LEFT
732 #define KEY_RIGHT SDLK_RIGHT
733 #define KEY_PAGEUP SDLK_PAGEUP
734 #define KEY_PAGEDOWN SDLK_PAGEDOWN
735 #define KMOD_CAPITALIZE (KMOD_LSHIFT|KMOD_RSHIFT|KMOD_CAPS)
737 OGLCONSOLE_SDLEvent(SDL_Event * e)
739 /* If the terminal is hidden we only check for show/hide key */
740 if (userConsole->visibility < 1) {
741 if (e->type == SDL_KEYDOWN && e->key.keysym.sym == '`') {
742 // TODO: Fetch values from OS?
743 // TODO: Expose them to the program
744 SDL_EnableKeyRepeat(250, 30);
745 userConsole->visibility += SLIDE_STEPS;
746 return 1;
749 return 0;
752 /* TODO: SDL_KEYPRESS? ENABLE KEY REPEAT USING THE HIDE/SHOW FUNCTION? */
753 if (e->type == SDL_KEYDOWN) {
754 /* Reject most modifier keys TODO: Add some accelerator keys? */
755 if (e->key.keysym.mod & ~(KMOD_CAPITALIZE | KMOD_NUM))
756 return 0;
758 /* Check for hide key */
759 if (e->key.keysym.sym == '`' || e->key.keysym.sym == SDLK_ESCAPE) {
760 /* Tell console to slide into closing */
761 userConsole->visibility -= SLIDE_STEPS;
763 /* Disable key repeat */
764 SDL_EnableKeyRepeat(0, 0);
765 return 1;
768 /* TODO: Find out how to handle CAPSLOCK */
769 if (e->key.keysym.sym >= ' ' && e->key.keysym.sym <= '~') {
770 int k = e->key.keysym.sym;
771 char *c, *d;
773 /* Yank the command history if necessary */
774 OGLCONSOLE_YankHistory(userConsole);
776 /* Capitalize if necessary */
777 if (e->key.keysym.mod & KMOD_CAPITALIZE) {
778 static
779 const int capital[] =
780 { (int) ' ', (int) '!', (int) '"',
781 (int) '#',
782 (int) '$', (int) '%', (int) '&',
783 (int) '"', (int) '(', (int) ')',
784 (int) '*', (int) '+', (int) '<',
785 (int) '_', (int) '>', (int) '?',
786 (int) ')', (int) '!', (int) '@',
787 (int) '#', (int) '$', (int) '%',
788 (int) '^', (int) '&', (int) '*',
789 (int) '(', (int) ':', (int) ':',
790 (int) '<', (int) '+', (int) '>',
791 (int) '?', (int) '@', (int) 'A',
792 (int) 'B', (int) 'C', (int) 'D',
793 (int) 'E', (int) 'F', (int) 'G',
794 (int) 'H', (int) 'I', (int) 'J',
795 (int) 'K', (int) 'L', (int) 'M',
796 (int) 'N', (int) 'O', (int) 'P',
797 (int) 'Q', (int) 'R', (int) 'S',
798 (int) 'T', (int) 'U', (int) 'V',
799 (int) 'W', (int) 'X', (int) 'Y',
800 (int) 'Z', (int) '{', (int) '|',
801 (int) '}', (int) '^', (int) '_',
802 (int) '~', (int) 'A', (int) 'B',
803 (int) 'C', (int) 'D', (int) 'E',
804 (int) 'F', (int) 'G', (int) 'H',
805 (int) 'I', (int) 'J', (int) 'K',
806 (int) 'L', (int) 'M', (int) 'N',
807 (int) 'O', (int) 'P', (int) 'Q',
808 (int) 'R', (int) 'S', (int) 'T',
809 (int) 'U', (int) 'V', (int) 'W',
810 (int) 'X', (int) 'Y', (int) 'Z',
811 (int) '{', (int) '|', (int) '}',
812 (int) '~'
815 /* If we're not explicitly holding a shift key, that means just
816 * capslock, which means we only capitalize letters */
817 if ((k >= 'a' && k <= 'z')
818 || (e->key.keysym.mod & KMOD_SHIFT))
819 k = capital[k - ' '];
822 /* Point to the cursor position and the end of the string */
823 c = userConsole->inputLine +
824 userConsole->inputCursorPos;
825 d = userConsole->inputLine +
826 userConsole->inputLineLength + 1;
828 /* Slide some of the string to the right */
829 for (; d != c; d--)
830 *d = *(d - 1);
832 /* Insert new character */
833 *c = k;
835 /* Increment input line length counter */
836 userConsole->inputLineLength++;
838 /* Advance input cursor position */
839 userConsole->inputCursorPos++;
841 return 1;
844 else if (e->key.keysym.sym == KEY_DELETE
845 || e->key.keysym.sym == KEY_BACKSPACE) {
846 /* Yank the command history if necessary */
847 OGLCONSOLE_YankHistory(userConsole);
849 /* If string is not empty */
850 if (userConsole->inputLineLength) {
851 char *end, *c;
853 /* Backspace is like pressing LEFT and then DELETE */
854 if (e->key.keysym.sym == KEY_BACKSPACE)
855 userConsole->inputCursorPos--;
857 /* With delete we much check more than just inputLineLength */
858 else if (userConsole->inputCursorPos ==
859 userConsole->inputLineLength)
860 return 1;
862 c = userConsole->inputLine +
863 userConsole->inputCursorPos;
864 end =
865 userConsole->inputLine +
866 --userConsole->inputLineLength;
868 while (c <= end) {
869 *c = *(c + 1);
870 c++;
874 return 1;
877 else if (e->key.keysym.sym == KEY_RETURN) {
878 /* Yank the command history if necessary */
879 OGLCONSOLE_YankHistory(userConsole);
881 /* Add user's command to history */
882 OGLCONSOLE_AddHistory(userConsole,
883 userConsole->inputLine);
885 /* Print user's command to the console */
886 OGLCONSOLE_Output((void *) userConsole, "%s\n",
887 userConsole->inputLine);
889 /* Invoke console's enter-key callback function */
890 userConsole->enterKeyCallback((void *) userConsole,
891 userConsole->inputLine);
893 /* Erase command line */
894 userConsole->inputCursorPos = 0;
895 userConsole->inputLineLength = 0;
896 userConsole->inputLine[0] = '\0';
898 return 1;
900 // Page up key
901 else if (e->key.keysym.sym == SDLK_PAGEUP) {
902 userConsole->lineScrollIndex -=
903 userConsole->textHeight / 2;
905 if (userConsole->lineScrollIndex < 0)
906 userConsole->lineScrollIndex +=
907 userConsole->maxLines;
909 printf("scroll index = %i\n",
910 userConsole->lineScrollIndex);
912 // Page down key
913 else if (e->key.keysym.sym == SDLK_PAGEDOWN) {
914 userConsole->lineScrollIndex +=
915 userConsole->textHeight / 2;
917 if (userConsole->lineScrollIndex >=
918 userConsole->maxLines)
919 userConsole->lineScrollIndex -=
920 userConsole->maxLines;
922 printf("scroll index = %i\n",
923 userConsole->lineScrollIndex);
925 // Arrow key up
926 else if (e->key.keysym.sym == KEY_UP) {
927 // Shift key is for scrolling the output display
928 if (e->key.keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT)) {
929 if (--userConsole->lineScrollIndex < 0)
930 userConsole->lineScrollIndex =
931 userConsole->maxLines - 1;
933 // No shift key is for scrolling through command history
934 else {
935 // -1 means we aren't look at history yet
936 if (userConsole->historyScrollIndex == -1) {
937 userConsole->historyScrollIndex =
938 userConsole->historyQueueIndex;
939 } else {
940 // Wrap our history scrolling
941 if (--userConsole->historyScrollIndex <
943 userConsole->
944 historyScrollIndex =
945 MAX_HISTORY_COUNT;
948 // If we've returned to our current position in the command
949 // history, we'll just drop out of history mode
950 if (userConsole->historyScrollIndex ==
951 userConsole->historyQueueIndex + 1)
952 userConsole->historyScrollIndex = -1;
955 return 1;
957 // Arrow key down
958 else if (e->key.keysym.sym == KEY_DOWN) {
959 // Shift key is for scrolling the output display
960 if (e->key.keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT)) {
961 if (++userConsole->lineScrollIndex >=
962 userConsole->maxLines)
963 userConsole->lineScrollIndex = 0;
965 // No shift key is for scrolling through command history
966 else {
967 // -1 means we aren't look at history yet
968 if (userConsole->historyScrollIndex != -1) {
969 // Wrap our history scrolling
970 if (++userConsole->historyScrollIndex >=
971 MAX_HISTORY_COUNT)
972 userConsole->
973 historyScrollIndex = 0;
975 // If we've returned to our current position in the command
976 // history, we'll just drop out of history mode
977 if (userConsole->historyScrollIndex ==
978 userConsole->historyQueueIndex + 1)
979 userConsole->
980 historyScrollIndex = -1;
981 } else {
982 // TODO: be like, no bitch, there's no history down there
985 return 1;
987 // Arrow key left
988 else if (e->key.keysym.sym == KEY_LEFT) {
989 /* Yank the command history if necessary */
990 OGLCONSOLE_YankHistory(userConsole);
992 if (userConsole->inputCursorPos > 0)
993 userConsole->inputCursorPos--;
995 return 1;
997 // Arrow key right
998 else if (e->key.keysym.sym == KEY_RIGHT) {
999 /* Yank the command history if necessary */
1000 OGLCONSOLE_YankHistory(userConsole);
1002 if (userConsole->inputCursorPos <
1003 userConsole->inputLineLength)
1004 userConsole->inputCursorPos++;
1006 return 1;
1010 return 0;
1012 #endif