shithub: choc

Download patch

ref: 9d7126c11b5f1577b00987b8d5f0f7f761b012d7
parent: 2c4e3a7dbf89608355d1ce49c221d41b3e2fa7a8
author: Simon Howard <fraggle@gmail.com>
date: Mon Jun 4 14:32:50 EDT 2007

Rename txt_main.c to txt_sdl.c; add txt_sdl.h for SDL-specific API
functions, while keeping txt_main.h for the common API. Add
TXT_SDL_SetEventCallback to allow programs to intercept SDL events in
the textscreen main loop.

Subversion-branch: /trunk/chocolate-doom
Subversion-revision: 892

--- a/textscreen/Makefile.am
+++ b/textscreen/Makefile.am
@@ -15,12 +15,13 @@
 	txt_gui.c                txt_gui.h                \
 	txt_inputbox.c           txt_inputbox.h           \
 	txt_io.c                 txt_io.h                 \
-	txt_main.c               txt_main.h               \
+	                         txt_main.h               \
 	txt_button.c             txt_button.h             \
 	txt_label.c              txt_label.h              \
 	txt_radiobutton.c        txt_radiobutton.h        \
 	txt_separator.c          txt_separator.h          \
 	txt_spinctrl.c           txt_spinctrl.h           \
+	txt_sdl.c                txt_sdl.h                \
 	txt_strut.c              txt_strut.h              \
 	txt_table.c              txt_table.h              \
 	txt_widget.c             txt_widget.h             \
--- a/textscreen/txt_desktop.c
+++ b/textscreen/txt_desktop.c
@@ -19,6 +19,7 @@
 // 02111-1307, USA.
 //
 
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
--- a/textscreen/txt_main.c
+++ /dev/null
@@ -1,525 +1,0 @@
-// Emacs style mode select   -*- C++ -*- 
-//-----------------------------------------------------------------------------
-//
-// Copyright(C) 2005,2006 Simon Howard
-//
-// 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 2
-// 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, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-// 02111-1307, USA.
-//
-//-----------------------------------------------------------------------------
-//
-// Text mode emulation in SDL
-//
-//-----------------------------------------------------------------------------
-
-#include "SDL.h"
-
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "doomkeys.h"
-
-#include "txt_main.h"
-#include "txt_font.h"
-
-#define CHAR_W 8
-#define CHAR_H 16
-
-// Time between character blinks in ms
-
-#define BLINK_PERIOD 250
-
-static SDL_Surface *screen;
-static unsigned char *screendata;
-static int key_mapping = 1;
-
-//#define TANGO
-
-#ifndef TANGO
-
-static SDL_Color ega_colors[] = 
-{
-    {0x00, 0x00, 0x00, 0x00},          // 0: Black
-    {0x00, 0x00, 0xa8, 0x00},          // 1: Blue
-    {0x00, 0xa8, 0x00, 0x00},          // 2: Green
-    {0x00, 0xa8, 0xa8, 0x00},          // 3: Cyan
-    {0xa8, 0x00, 0x00, 0x00},          // 4: Red
-    {0xa8, 0x00, 0xa8, 0x00},          // 5: Magenta
-    {0xa8, 0x54, 0x00, 0x00},          // 6: Brown
-    {0xa8, 0xa8, 0xa8, 0x00},          // 7: Grey
-    {0x54, 0x54, 0x54, 0x00},          // 8: Dark grey
-    {0x54, 0x54, 0xfe, 0x00},          // 9: Bright blue
-    {0x54, 0xfe, 0x54, 0x00},          // 10: Bright green
-    {0x54, 0xfe, 0xfe, 0x00},          // 11: Bright cyan
-    {0xfe, 0x54, 0x54, 0x00},          // 12: Bright red
-    {0xfe, 0x54, 0xfe, 0x00},          // 13: Bright magenta
-    {0xfe, 0xfe, 0x54, 0x00},          // 14: Yellow
-    {0xfe, 0xfe, 0xfe, 0x00},          // 15: Bright white
-};
-
-#else
-
-// Colors that fit the Tango desktop guidelines: see
-// http://tango.freedesktop.org/ also
-// http://uwstopia.nl/blog/2006/07/tango-terminal
-
-static SDL_Color ega_colors[] = 
-{
-    {0x2e, 0x34, 0x36, 0x00},          // 0: Black
-    {0x34, 0x65, 0xa4, 0x00},          // 1: Blue
-    {0x4e, 0x9a, 0x06, 0x00},          // 2: Green
-    {0x06, 0x98, 0x9a, 0x00},          // 3: Cyan
-    {0xcc, 0x00, 0x00, 0x00},          // 4: Red
-    {0x75, 0x50, 0x7b, 0x00},          // 5: Magenta
-    {0xc4, 0xa0, 0x00, 0x00},          // 6: Brown
-    {0xd3, 0xd7, 0xcf, 0x00},          // 7: Grey
-    {0x55, 0x57, 0x53, 0x00},          // 8: Dark grey
-    {0x72, 0x9f, 0xcf, 0x00},          // 9: Bright blue
-    {0x8a, 0xe2, 0x34, 0x00},          // 10: Bright green
-    {0x34, 0xe2, 0xe2, 0x00},          // 11: Bright cyan
-    {0xef, 0x29, 0x29, 0x00},          // 12: Bright red
-    {0x34, 0xe2, 0xe2, 0x00},          // 13: Bright magenta
-    {0xfc, 0xe9, 0x4f, 0x00},          // 14: Yellow
-    {0xee, 0xee, 0xec, 0x00},          // 15: Bright white
-};
-
-#endif
-
-//
-// Initialise text mode screen
-//
-// Returns 1 if successful, 0 if an error occurred
-//
-
-int TXT_Init(void)
-{
-    SDL_InitSubSystem(SDL_INIT_VIDEO);
-    
-    screen = SDL_SetVideoMode(TXT_SCREEN_W * CHAR_W, TXT_SCREEN_H * CHAR_H, 8, 0);
-
-    if (screen == NULL)
-        return 0;
-
-    SDL_SetColors(screen, ega_colors, 0, 16);
-    SDL_EnableUNICODE(1);
-
-    screendata = malloc(TXT_SCREEN_W * TXT_SCREEN_H * 2);
-    memset(screendata, 0, TXT_SCREEN_W * TXT_SCREEN_H * 2);
-
-    // Ignore all mouse motion events
-
-    SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
-
-    // Repeat key presses so we can hold down arrows to scroll down the
-    // menu, for example. This is what setup.exe does.
-
-    SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
-
-    return 1;
-}
-
-void TXT_Shutdown(void)
-{
-    free(screendata);
-    SDL_QuitSubSystem(SDL_INIT_VIDEO);
-}
-
-unsigned char *TXT_GetScreenData(void)
-{
-    return screendata;
-}
-
-static inline void UpdateCharacter(int x, int y)
-{
-    unsigned char character;
-    unsigned char *p;
-    unsigned char *s, *s1;
-    int bg, fg;
-    int x1, y1;
-
-    p = &screendata[(y * TXT_SCREEN_W + x) * 2];
-    character = p[0];
-
-    fg = p[1] & 0xf;
-    bg = (p[1] >> 4) & 0xf;
-
-    if (bg & 0x8)
-    {
-        // blinking
-
-        bg &= ~0x8;
-
-        if (((SDL_GetTicks() / BLINK_PERIOD) % 2) == 0)
-        {
-            fg = bg;
-        }
-    }
-
-    p = &int10_font_16[character * CHAR_H];
-
-    s = ((unsigned char *) screen->pixels) 
-          + (y * CHAR_H * screen->pitch) + (x * CHAR_W);
-
-    for (y1=0; y1<CHAR_H; ++y1)
-    {
-        s1 = s;
-
-        for (x1=0; x1<CHAR_W; ++x1)
-        {
-            if (*p & (1 << (7-x1)))
-            {
-                *s1++ = fg;
-            }
-            else
-            {
-                *s1++ = bg;
-            }
-        }
-
-        ++p;
-        s += screen->pitch;
-    }
-}
-
-void TXT_UpdateScreenArea(int x, int y, int w, int h)
-{
-    int x1, y1;
-
-    for (y1=y; y1<y+h; ++y1)
-    {
-        for (x1=x; x1<x+w; ++x1)
-        {
-            UpdateCharacter(x1, y1);
-        }
-    }
-
-    SDL_UpdateRect(screen, x * CHAR_W, y * CHAR_H, w * CHAR_W, h * CHAR_H);
-}
-
-void TXT_UpdateScreen(void)
-{
-    TXT_UpdateScreenArea(0, 0, TXT_SCREEN_W, TXT_SCREEN_H);
-}
-
-void TXT_GetMousePosition(int *x, int *y)
-{
-    SDL_GetMouseState(x, y);
-
-    *x /= CHAR_W;
-    *y /= CHAR_H;
-}
-
-//
-// Translates the SDL key
-//
-
-static int TranslateKey(SDL_keysym *sym)
-{
-    switch(sym->sym)
-    {
-        case SDLK_LEFT:        return KEY_LEFTARROW;
-        case SDLK_RIGHT:       return KEY_RIGHTARROW;
-        case SDLK_DOWN:        return KEY_DOWNARROW;
-        case SDLK_UP:          return KEY_UPARROW;
-        case SDLK_ESCAPE:      return KEY_ESCAPE;
-        case SDLK_RETURN:      return KEY_ENTER;
-        case SDLK_TAB:         return KEY_TAB;
-        case SDLK_F1:          return KEY_F1;
-        case SDLK_F2:          return KEY_F2;
-        case SDLK_F3:          return KEY_F3;
-        case SDLK_F4:          return KEY_F4;
-        case SDLK_F5:          return KEY_F5;
-        case SDLK_F6:          return KEY_F6;
-        case SDLK_F7:          return KEY_F7;
-        case SDLK_F8:          return KEY_F8;
-        case SDLK_F9:          return KEY_F9;
-        case SDLK_F10:         return KEY_F10;
-        case SDLK_F11:         return KEY_F11;
-        case SDLK_F12:         return KEY_F12;
-
-        case SDLK_BACKSPACE:   return KEY_BACKSPACE;
-        case SDLK_DELETE:      return KEY_DEL;
-
-        case SDLK_PAUSE:       return KEY_PAUSE;
-
-        case SDLK_KP_EQUALS:   return KEY_EQUALS;
-
-        case SDLK_LSHIFT:
-        case SDLK_RSHIFT:
-                               return KEY_RSHIFT;
-
-        case SDLK_LCTRL:
-        case SDLK_RCTRL:
-                               return KEY_RCTRL;
-
-        case SDLK_LALT:
-        case SDLK_LMETA:
-        case SDLK_RALT:
-        case SDLK_RMETA:
-                               return KEY_RALT;
-
-        case SDLK_CAPSLOCK:    return KEY_CAPSLOCK;
-        case SDLK_SCROLLOCK:   return KEY_SCRLCK;
-
-        case SDLK_KP0:         return KEYP_0;
-        case SDLK_KP1:         return KEYP_1;
-        case SDLK_KP2:         return KEYP_2;
-        case SDLK_KP3:         return KEYP_3;
-        case SDLK_KP4:         return KEYP_4;
-        case SDLK_KP5:         return KEYP_5;
-        case SDLK_KP6:         return KEYP_6;
-        case SDLK_KP7:         return KEYP_7;
-        case SDLK_KP8:         return KEYP_8;
-        case SDLK_KP9:         return KEYP_9;
-
-        case SDLK_HOME:        return KEY_HOME;
-        case SDLK_INSERT:      return KEY_INS;
-        case SDLK_END:         return KEY_END;
-        case SDLK_PAGEUP:      return KEY_PGUP;
-        case SDLK_PAGEDOWN:    return KEY_PGDN;
-        case SDLK_KP_MULTIPLY: return KEYP_MULTIPLY;
-        case SDLK_KP_PLUS:     return KEYP_PLUS;
-        case SDLK_KP_MINUS:    return KEYP_MINUS;
-        case SDLK_KP_DIVIDE:   return KEYP_DIVIDE;
-
-        default:               break;
-    }
-
-    // Returned value is different, depending on whether key mapping is
-    // enabled.  Key mapping is preferable most of the time, for typing
-    // in text, etc.  However, when we want to read raw keyboard codes
-    // for the setup keyboard configuration dialog, we want the raw
-    // key code.
-
-    if (key_mapping)
-    {
-        return sym->unicode;
-    }
-    else
-    {
-        return tolower(sym->sym);
-    }
-}
-
-
-signed int TXT_GetChar(void)
-{
-    SDL_Event ev;
-
-    while (SDL_PollEvent(&ev))
-    {
-        switch (ev.type)
-        {
-            case SDL_MOUSEBUTTONDOWN:
-                if (ev.button.button == SDL_BUTTON_LEFT)
-                    return TXT_MOUSE_LEFT;
-                else if (ev.button.button == SDL_BUTTON_RIGHT)
-                    return TXT_MOUSE_RIGHT;
-                else if (ev.button.button == SDL_BUTTON_MIDDLE)
-                    return TXT_MOUSE_MIDDLE;
-                break;
-
-            case SDL_KEYDOWN:
-                return TranslateKey(&ev.key.keysym);
-
-            case SDL_QUIT:
-                // Quit = escape
-                return 27;
-
-            default:
-                break;
-        }
-    }
-
-    return -1;
-}
-
-static char *SpecialKeyName(int key)
-{
-    switch (key)
-    {
-        case ' ':             return "SPACE";
-        case KEY_RIGHTARROW:  return "RIGHT";
-        case KEY_LEFTARROW:   return "LEFT";
-        case KEY_UPARROW:     return "UP";
-        case KEY_DOWNARROW:   return "DOWN";
-        case KEY_ESCAPE:      return "ESC";
-        case KEY_ENTER:       return "ENTER";
-        case KEY_TAB:         return "TAB";
-        case KEY_F1:          return "F1";
-        case KEY_F2:          return "F2";
-        case KEY_F3:          return "F3";
-        case KEY_F4:          return "F4";
-        case KEY_F5:          return "F5";
-        case KEY_F6:          return "F6";
-        case KEY_F7:          return "F7";
-        case KEY_F8:          return "F8";
-        case KEY_F9:          return "F9";
-        case KEY_F10:         return "F10";
-        case KEY_F11:         return "F11";
-        case KEY_F12:         return "F12";
-        case KEY_BACKSPACE:   return "BKSP";
-        case KEY_PAUSE:       return "PAUSE";
-        case KEY_EQUALS:      return "EQUALS";
-        case KEY_MINUS:       return "MINUS";
-        case KEY_RSHIFT:      return "SHIFT";
-        case KEY_RCTRL:       return "CTRL";
-        case KEY_RALT:        return "ALT";
-        case KEY_CAPSLOCK:    return "CAPS";
-        case KEY_SCRLCK:      return "SCRLCK";
-        case KEY_HOME:        return "HOME";
-        case KEY_END:         return "END";
-        case KEY_PGUP:        return "PGUP";
-        case KEY_PGDN:        return "PGDN";
-        case KEY_INS:         return "INS";
-        case KEY_DEL:         return "DEL";
-                 /*
-        case KEYP_0:          return "PAD0";
-        case KEYP_1:          return "PAD1";
-        case KEYP_2:          return "PAD2";
-        case KEYP_3:          return "PAD3";
-        case KEYP_4:          return "PAD4";
-        case KEYP_5:          return "PAD5";
-        case KEYP_6:          return "PAD6";
-        case KEYP_7:          return "PAD7";
-        case KEYP_8:          return "PAD8";
-        case KEYP_9:          return "PAD9";
-        case KEYP_UPARROW:    return "PAD_U";
-        case KEYP_DOWNARROW:  return "PAD_D";
-        case KEYP_LEFTARROW:  return "PAD_L";
-        case KEYP_RIGHTARROW: return "PAD_R";
-        case KEYP_MULTIPLY:   return "PAD*";
-        case KEYP_PLUS:       return "PAD+";
-        case KEYP_MINUS:      return "PAD-";
-        case KEYP_DIVIDE:     return "PAD/";
-                   */
-        default:              return NULL;
-    }
-}
-
-void TXT_GetKeyDescription(int key, char *buf)
-{
-    char *keyname;
-
-    keyname = SpecialKeyName(key);
-
-    if (keyname != NULL)
-    {
-        strcpy(buf, keyname);
-    }
-    else if (isprint(key))
-    {
-        sprintf(buf, "%c", toupper(key));
-    }
-    else
-    {
-        sprintf(buf, "??%i", key);
-    }
-}
-
-// Searches the desktop screen buffer to determine whether there are any
-// blinking characters.
-
-int TXT_ScreenHasBlinkingChars(void)
-{
-    int x, y;
-    unsigned char *p;
-
-    // Check all characters in screen buffer
-
-    for (y=0; y<TXT_SCREEN_H; ++y)
-    {
-        for (x=0; x<TXT_SCREEN_W; ++x) 
-        {
-            p = &screendata[(y * TXT_SCREEN_W + x) * 2];
-
-            if (p[1] & 0x80)
-            {
-                // This character is blinking
-
-                return 1;
-            }
-        }
-    }
-
-    // None found
-
-    return 0;
-}
-
-// Sleeps until an event is received, the screen needs to be redrawn, 
-// or until timeout expires (if timeout != 0)
-
-void TXT_Sleep(int timeout)
-{
-    unsigned int start_time;
-
-    if (TXT_ScreenHasBlinkingChars())
-    {
-        int time_to_next_blink;
-
-        time_to_next_blink = BLINK_PERIOD - (SDL_GetTicks() % BLINK_PERIOD);
-
-        // There are blinking characters on the screen, so we 
-        // must time out after a while
-       
-        if (timeout == 0 || timeout > time_to_next_blink)
-        {
-            // Add one so it is always positive
-
-            timeout = time_to_next_blink + 1;
-        }
-    }
-
-    if (timeout == 0)
-    {
-        // We can just wait forever until an event occurs
-
-        SDL_WaitEvent(NULL);
-    }
-    else
-    {
-        // Sit in a busy loop until the timeout expires or we have to
-        // redraw the blinking screen
-
-        start_time = SDL_GetTicks();
-
-        while (SDL_GetTicks() < start_time + timeout)
-        {
-            if (SDL_PollEvent(NULL) != 0)
-            {
-                // Received an event, so stop waiting
-
-                break;
-            }
-
-            // Don't hog the CPU
-
-            SDL_Delay(1);
-        }
-    }
-}
-
-void TXT_EnableKeyMapping(int enable)
-{
-    key_mapping = enable;
-}
-
-void TXT_SetWindowTitle(char *title)
-{
-    SDL_WM_SetCaption(title, NULL);
-}
-
--- a/textscreen/txt_main.h
+++ b/textscreen/txt_main.h
@@ -20,7 +20,7 @@
 //
 //-----------------------------------------------------------------------------
 //
-// Text mode emulation in SDL
+// Base interface that abstracts the text mode screen.
 //
 //-----------------------------------------------------------------------------
 
@@ -27,10 +27,10 @@
 #ifndef TXT_MAIN_H
 #define TXT_MAIN_H
 
-// The textscreen API itself doesn't need SDL; however, SDL needs its
-// headers included where main() is defined.
+// For the moment, txt_sdl.c is the only implementation of the base 
+// text mode screen API:
 
-#include "SDL.h"
+#include "txt_sdl.h"
 
 // Special keypress values that correspond to mouse button clicks
 //
--- /dev/null
+++ b/textscreen/txt_sdl.c
@@ -1,0 +1,548 @@
+// Emacs style mode select   -*- C++ -*- 
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2005,2006 Simon Howard
+//
+// 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 2
+// 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, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+//
+// Text mode emulation in SDL
+//
+//-----------------------------------------------------------------------------
+
+#include "SDL.h"
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "doomkeys.h"
+
+#include "txt_main.h"
+#include "txt_sdl.h"
+#include "txt_font.h"
+
+#define CHAR_W 8
+#define CHAR_H 16
+
+// Time between character blinks in ms
+
+#define BLINK_PERIOD 250
+
+static SDL_Surface *screen;
+static unsigned char *screendata;
+static int key_mapping = 1;
+
+static TxtSDLEventCallbackFunc event_callback;
+static void *event_callback_data;
+
+//#define TANGO
+
+#ifndef TANGO
+
+static SDL_Color ega_colors[] = 
+{
+    {0x00, 0x00, 0x00, 0x00},          // 0: Black
+    {0x00, 0x00, 0xa8, 0x00},          // 1: Blue
+    {0x00, 0xa8, 0x00, 0x00},          // 2: Green
+    {0x00, 0xa8, 0xa8, 0x00},          // 3: Cyan
+    {0xa8, 0x00, 0x00, 0x00},          // 4: Red
+    {0xa8, 0x00, 0xa8, 0x00},          // 5: Magenta
+    {0xa8, 0x54, 0x00, 0x00},          // 6: Brown
+    {0xa8, 0xa8, 0xa8, 0x00},          // 7: Grey
+    {0x54, 0x54, 0x54, 0x00},          // 8: Dark grey
+    {0x54, 0x54, 0xfe, 0x00},          // 9: Bright blue
+    {0x54, 0xfe, 0x54, 0x00},          // 10: Bright green
+    {0x54, 0xfe, 0xfe, 0x00},          // 11: Bright cyan
+    {0xfe, 0x54, 0x54, 0x00},          // 12: Bright red
+    {0xfe, 0x54, 0xfe, 0x00},          // 13: Bright magenta
+    {0xfe, 0xfe, 0x54, 0x00},          // 14: Yellow
+    {0xfe, 0xfe, 0xfe, 0x00},          // 15: Bright white
+};
+
+#else
+
+// Colors that fit the Tango desktop guidelines: see
+// http://tango.freedesktop.org/ also
+// http://uwstopia.nl/blog/2006/07/tango-terminal
+
+static SDL_Color ega_colors[] = 
+{
+    {0x2e, 0x34, 0x36, 0x00},          // 0: Black
+    {0x34, 0x65, 0xa4, 0x00},          // 1: Blue
+    {0x4e, 0x9a, 0x06, 0x00},          // 2: Green
+    {0x06, 0x98, 0x9a, 0x00},          // 3: Cyan
+    {0xcc, 0x00, 0x00, 0x00},          // 4: Red
+    {0x75, 0x50, 0x7b, 0x00},          // 5: Magenta
+    {0xc4, 0xa0, 0x00, 0x00},          // 6: Brown
+    {0xd3, 0xd7, 0xcf, 0x00},          // 7: Grey
+    {0x55, 0x57, 0x53, 0x00},          // 8: Dark grey
+    {0x72, 0x9f, 0xcf, 0x00},          // 9: Bright blue
+    {0x8a, 0xe2, 0x34, 0x00},          // 10: Bright green
+    {0x34, 0xe2, 0xe2, 0x00},          // 11: Bright cyan
+    {0xef, 0x29, 0x29, 0x00},          // 12: Bright red
+    {0x34, 0xe2, 0xe2, 0x00},          // 13: Bright magenta
+    {0xfc, 0xe9, 0x4f, 0x00},          // 14: Yellow
+    {0xee, 0xee, 0xec, 0x00},          // 15: Bright white
+};
+
+#endif
+
+//
+// Initialise text mode screen
+//
+// Returns 1 if successful, 0 if an error occurred
+//
+
+int TXT_Init(void)
+{
+    SDL_InitSubSystem(SDL_INIT_VIDEO);
+    
+    screen = SDL_SetVideoMode(TXT_SCREEN_W * CHAR_W, TXT_SCREEN_H * CHAR_H, 8, 0);
+
+    if (screen == NULL)
+        return 0;
+
+    SDL_SetColors(screen, ega_colors, 0, 16);
+    SDL_EnableUNICODE(1);
+
+    screendata = malloc(TXT_SCREEN_W * TXT_SCREEN_H * 2);
+    memset(screendata, 0, TXT_SCREEN_W * TXT_SCREEN_H * 2);
+
+    // Ignore all mouse motion events
+
+    SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
+
+    // Repeat key presses so we can hold down arrows to scroll down the
+    // menu, for example. This is what setup.exe does.
+
+    SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
+
+    return 1;
+}
+
+void TXT_Shutdown(void)
+{
+    free(screendata);
+    SDL_QuitSubSystem(SDL_INIT_VIDEO);
+}
+
+unsigned char *TXT_GetScreenData(void)
+{
+    return screendata;
+}
+
+static inline void UpdateCharacter(int x, int y)
+{
+    unsigned char character;
+    unsigned char *p;
+    unsigned char *s, *s1;
+    int bg, fg;
+    int x1, y1;
+
+    p = &screendata[(y * TXT_SCREEN_W + x) * 2];
+    character = p[0];
+
+    fg = p[1] & 0xf;
+    bg = (p[1] >> 4) & 0xf;
+
+    if (bg & 0x8)
+    {
+        // blinking
+
+        bg &= ~0x8;
+
+        if (((SDL_GetTicks() / BLINK_PERIOD) % 2) == 0)
+        {
+            fg = bg;
+        }
+    }
+
+    p = &int10_font_16[character * CHAR_H];
+
+    s = ((unsigned char *) screen->pixels) 
+          + (y * CHAR_H * screen->pitch) + (x * CHAR_W);
+
+    for (y1=0; y1<CHAR_H; ++y1)
+    {
+        s1 = s;
+
+        for (x1=0; x1<CHAR_W; ++x1)
+        {
+            if (*p & (1 << (7-x1)))
+            {
+                *s1++ = fg;
+            }
+            else
+            {
+                *s1++ = bg;
+            }
+        }
+
+        ++p;
+        s += screen->pitch;
+    }
+}
+
+void TXT_UpdateScreenArea(int x, int y, int w, int h)
+{
+    int x1, y1;
+
+    for (y1=y; y1<y+h; ++y1)
+    {
+        for (x1=x; x1<x+w; ++x1)
+        {
+            UpdateCharacter(x1, y1);
+        }
+    }
+
+    SDL_UpdateRect(screen, x * CHAR_W, y * CHAR_H, w * CHAR_W, h * CHAR_H);
+}
+
+void TXT_UpdateScreen(void)
+{
+    TXT_UpdateScreenArea(0, 0, TXT_SCREEN_W, TXT_SCREEN_H);
+}
+
+void TXT_GetMousePosition(int *x, int *y)
+{
+    SDL_GetMouseState(x, y);
+
+    *x /= CHAR_W;
+    *y /= CHAR_H;
+}
+
+//
+// Translates the SDL key
+//
+
+static int TranslateKey(SDL_keysym *sym)
+{
+    switch(sym->sym)
+    {
+        case SDLK_LEFT:        return KEY_LEFTARROW;
+        case SDLK_RIGHT:       return KEY_RIGHTARROW;
+        case SDLK_DOWN:        return KEY_DOWNARROW;
+        case SDLK_UP:          return KEY_UPARROW;
+        case SDLK_ESCAPE:      return KEY_ESCAPE;
+        case SDLK_RETURN:      return KEY_ENTER;
+        case SDLK_TAB:         return KEY_TAB;
+        case SDLK_F1:          return KEY_F1;
+        case SDLK_F2:          return KEY_F2;
+        case SDLK_F3:          return KEY_F3;
+        case SDLK_F4:          return KEY_F4;
+        case SDLK_F5:          return KEY_F5;
+        case SDLK_F6:          return KEY_F6;
+        case SDLK_F7:          return KEY_F7;
+        case SDLK_F8:          return KEY_F8;
+        case SDLK_F9:          return KEY_F9;
+        case SDLK_F10:         return KEY_F10;
+        case SDLK_F11:         return KEY_F11;
+        case SDLK_F12:         return KEY_F12;
+
+        case SDLK_BACKSPACE:   return KEY_BACKSPACE;
+        case SDLK_DELETE:      return KEY_DEL;
+
+        case SDLK_PAUSE:       return KEY_PAUSE;
+
+        case SDLK_KP_EQUALS:   return KEY_EQUALS;
+
+        case SDLK_LSHIFT:
+        case SDLK_RSHIFT:
+                               return KEY_RSHIFT;
+
+        case SDLK_LCTRL:
+        case SDLK_RCTRL:
+                               return KEY_RCTRL;
+
+        case SDLK_LALT:
+        case SDLK_LMETA:
+        case SDLK_RALT:
+        case SDLK_RMETA:
+                               return KEY_RALT;
+
+        case SDLK_CAPSLOCK:    return KEY_CAPSLOCK;
+        case SDLK_SCROLLOCK:   return KEY_SCRLCK;
+
+        case SDLK_KP0:         return KEYP_0;
+        case SDLK_KP1:         return KEYP_1;
+        case SDLK_KP2:         return KEYP_2;
+        case SDLK_KP3:         return KEYP_3;
+        case SDLK_KP4:         return KEYP_4;
+        case SDLK_KP5:         return KEYP_5;
+        case SDLK_KP6:         return KEYP_6;
+        case SDLK_KP7:         return KEYP_7;
+        case SDLK_KP8:         return KEYP_8;
+        case SDLK_KP9:         return KEYP_9;
+
+        case SDLK_HOME:        return KEY_HOME;
+        case SDLK_INSERT:      return KEY_INS;
+        case SDLK_END:         return KEY_END;
+        case SDLK_PAGEUP:      return KEY_PGUP;
+        case SDLK_PAGEDOWN:    return KEY_PGDN;
+        case SDLK_KP_MULTIPLY: return KEYP_MULTIPLY;
+        case SDLK_KP_PLUS:     return KEYP_PLUS;
+        case SDLK_KP_MINUS:    return KEYP_MINUS;
+        case SDLK_KP_DIVIDE:   return KEYP_DIVIDE;
+
+        default:               break;
+    }
+
+    // Returned value is different, depending on whether key mapping is
+    // enabled.  Key mapping is preferable most of the time, for typing
+    // in text, etc.  However, when we want to read raw keyboard codes
+    // for the setup keyboard configuration dialog, we want the raw
+    // key code.
+
+    if (key_mapping)
+    {
+        return sym->unicode;
+    }
+    else
+    {
+        return tolower(sym->sym);
+    }
+}
+
+
+signed int TXT_GetChar(void)
+{
+    SDL_Event ev;
+
+    while (SDL_PollEvent(&ev))
+    {
+        // If there is an event callback, allow it to intercept this
+        // event.
+
+        if (event_callback != NULL)
+        {
+            if (event_callback(&ev, event_callback_data))
+            {
+                continue;
+            }
+        }
+
+        // Process the event.
+
+        switch (ev.type)
+        {
+            case SDL_MOUSEBUTTONDOWN:
+                if (ev.button.button == SDL_BUTTON_LEFT)
+                    return TXT_MOUSE_LEFT;
+                else if (ev.button.button == SDL_BUTTON_RIGHT)
+                    return TXT_MOUSE_RIGHT;
+                else if (ev.button.button == SDL_BUTTON_MIDDLE)
+                    return TXT_MOUSE_MIDDLE;
+                break;
+
+            case SDL_KEYDOWN:
+                return TranslateKey(&ev.key.keysym);
+
+            case SDL_QUIT:
+                // Quit = escape
+                return 27;
+
+            default:
+                break;
+        }
+    }
+
+    return -1;
+}
+
+static char *SpecialKeyName(int key)
+{
+    switch (key)
+    {
+        case ' ':             return "SPACE";
+        case KEY_RIGHTARROW:  return "RIGHT";
+        case KEY_LEFTARROW:   return "LEFT";
+        case KEY_UPARROW:     return "UP";
+        case KEY_DOWNARROW:   return "DOWN";
+        case KEY_ESCAPE:      return "ESC";
+        case KEY_ENTER:       return "ENTER";
+        case KEY_TAB:         return "TAB";
+        case KEY_F1:          return "F1";
+        case KEY_F2:          return "F2";
+        case KEY_F3:          return "F3";
+        case KEY_F4:          return "F4";
+        case KEY_F5:          return "F5";
+        case KEY_F6:          return "F6";
+        case KEY_F7:          return "F7";
+        case KEY_F8:          return "F8";
+        case KEY_F9:          return "F9";
+        case KEY_F10:         return "F10";
+        case KEY_F11:         return "F11";
+        case KEY_F12:         return "F12";
+        case KEY_BACKSPACE:   return "BKSP";
+        case KEY_PAUSE:       return "PAUSE";
+        case KEY_EQUALS:      return "EQUALS";
+        case KEY_MINUS:       return "MINUS";
+        case KEY_RSHIFT:      return "SHIFT";
+        case KEY_RCTRL:       return "CTRL";
+        case KEY_RALT:        return "ALT";
+        case KEY_CAPSLOCK:    return "CAPS";
+        case KEY_SCRLCK:      return "SCRLCK";
+        case KEY_HOME:        return "HOME";
+        case KEY_END:         return "END";
+        case KEY_PGUP:        return "PGUP";
+        case KEY_PGDN:        return "PGDN";
+        case KEY_INS:         return "INS";
+        case KEY_DEL:         return "DEL";
+                 /*
+        case KEYP_0:          return "PAD0";
+        case KEYP_1:          return "PAD1";
+        case KEYP_2:          return "PAD2";
+        case KEYP_3:          return "PAD3";
+        case KEYP_4:          return "PAD4";
+        case KEYP_5:          return "PAD5";
+        case KEYP_6:          return "PAD6";
+        case KEYP_7:          return "PAD7";
+        case KEYP_8:          return "PAD8";
+        case KEYP_9:          return "PAD9";
+        case KEYP_UPARROW:    return "PAD_U";
+        case KEYP_DOWNARROW:  return "PAD_D";
+        case KEYP_LEFTARROW:  return "PAD_L";
+        case KEYP_RIGHTARROW: return "PAD_R";
+        case KEYP_MULTIPLY:   return "PAD*";
+        case KEYP_PLUS:       return "PAD+";
+        case KEYP_MINUS:      return "PAD-";
+        case KEYP_DIVIDE:     return "PAD/";
+                   */
+        default:              return NULL;
+    }
+}
+
+void TXT_GetKeyDescription(int key, char *buf)
+{
+    char *keyname;
+
+    keyname = SpecialKeyName(key);
+
+    if (keyname != NULL)
+    {
+        strcpy(buf, keyname);
+    }
+    else if (isprint(key))
+    {
+        sprintf(buf, "%c", toupper(key));
+    }
+    else
+    {
+        sprintf(buf, "??%i", key);
+    }
+}
+
+// Searches the desktop screen buffer to determine whether there are any
+// blinking characters.
+
+int TXT_ScreenHasBlinkingChars(void)
+{
+    int x, y;
+    unsigned char *p;
+
+    // Check all characters in screen buffer
+
+    for (y=0; y<TXT_SCREEN_H; ++y)
+    {
+        for (x=0; x<TXT_SCREEN_W; ++x) 
+        {
+            p = &screendata[(y * TXT_SCREEN_W + x) * 2];
+
+            if (p[1] & 0x80)
+            {
+                // This character is blinking
+
+                return 1;
+            }
+        }
+    }
+
+    // None found
+
+    return 0;
+}
+
+// Sleeps until an event is received, the screen needs to be redrawn, 
+// or until timeout expires (if timeout != 0)
+
+void TXT_Sleep(int timeout)
+{
+    unsigned int start_time;
+
+    if (TXT_ScreenHasBlinkingChars())
+    {
+        int time_to_next_blink;
+
+        time_to_next_blink = BLINK_PERIOD - (SDL_GetTicks() % BLINK_PERIOD);
+
+        // There are blinking characters on the screen, so we 
+        // must time out after a while
+       
+        if (timeout == 0 || timeout > time_to_next_blink)
+        {
+            // Add one so it is always positive
+
+            timeout = time_to_next_blink + 1;
+        }
+    }
+
+    if (timeout == 0)
+    {
+        // We can just wait forever until an event occurs
+
+        SDL_WaitEvent(NULL);
+    }
+    else
+    {
+        // Sit in a busy loop until the timeout expires or we have to
+        // redraw the blinking screen
+
+        start_time = SDL_GetTicks();
+
+        while (SDL_GetTicks() < start_time + timeout)
+        {
+            if (SDL_PollEvent(NULL) != 0)
+            {
+                // Received an event, so stop waiting
+
+                break;
+            }
+
+            // Don't hog the CPU
+
+            SDL_Delay(1);
+        }
+    }
+}
+
+void TXT_EnableKeyMapping(int enable)
+{
+    key_mapping = enable;
+}
+
+void TXT_SetWindowTitle(char *title)
+{
+    SDL_WM_SetCaption(title, NULL);
+}
+
+void TXT_SDL_SetEventCallback(TxtSDLEventCallbackFunc callback, void *user_data)
+{
+    event_callback = callback;
+    event_callback_data = user_data;
+}
+
--- /dev/null
+++ b/textscreen/txt_sdl.h
@@ -1,0 +1,50 @@
+// Emacs style mode select   -*- C++ -*- 
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2005,2006 Simon Howard
+//
+// 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 2
+// 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, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+//
+// Text mode emulation in SDL
+//
+//-----------------------------------------------------------------------------
+
+#ifndef TXT_SDL_H
+#define TXT_SDL_H
+
+// The textscreen API itself doesn't need SDL; however, SDL needs its
+// headers included where main() is defined.
+
+#include "SDL.h"
+
+// Event callback function type: a function of this type can be used
+// to intercept events in the textscreen event processing loop.  
+// Returning 1 will cause the event to be eaten; the textscreen code
+// will not see it.
+
+typedef int (*TxtSDLEventCallbackFunc)(SDL_Event *event, void *user_data);
+
+// Set a callback function to call in the SDL event loop.  Useful for
+// intercepting events.  Pass callback=NULL to clear an existing
+// callback function.
+// user_data is a void pointer to be passed to the callback function.
+
+void TXT_SDL_SetEventCallback(TxtSDLEventCallbackFunc callback, void *user_data);
+
+#endif /* #ifndef TXT_SDL_H */
+