sdlterm/src/sdlterm.cc
changeset 51 dce7325109c1
parent 50 c5b8b9d2da95
child 52 50a1857557da
equal deleted inserted replaced
50:c5b8b9d2da95 51:dce7325109c1
     4 #include <algorithm>
     4 #include <algorithm>
     5 
     5 
     6 
     6 
     7 void ColorMap::index_to_rgb(int index, SDL_Color &color)
     7 void ColorMap::index_to_rgb(int index, SDL_Color &color)
     8 {
     8 {
     9 	color.r = _map[index][0];
     9     color.r = _map[index][0];
    10 	color.g = _map[index][1];
    10     color.g = _map[index][1];
    11 	color.b = _map[index][2];
    11     color.b = _map[index][2];
    12 }
    12 }
    13 
    13 
    14 
    14 
    15 SDL_Surface *GlyphCache::lookup_glyph(Uint16 ch)
    15 SDL_Surface *GlyphCache::lookup_glyph(Uint16 ch)
    16 {
    16 {
    17 	auto iter = _glyph_map.find(ch);
    17     auto iter = _glyph_map.find(ch);
    18 	if (iter == _glyph_map.end())
    18     if (iter == _glyph_map.end())
    19 	{
    19     {
    20 		return NULL;
    20         return NULL;
    21 	}
    21     }
    22 	return iter->second;
    22     return iter->second;
    23 }
    23 }
    24 
    24 
    25 
    25 
    26 void GlyphCache::put_glyph(Uint16 ch, SDL_Surface *srf)
    26 void GlyphCache::put_glyph(Uint16 ch, SDL_Surface *srf)
    27 {
    27 {
    28 	_glyph_map[ch] = srf;
    28     _glyph_map[ch] = srf;
    29 }
    29 }
    30 
    30 
    31 
    31 
    32 void GlyphCache::flush()
    32 void GlyphCache::flush()
    33 {
    33 {
    34 	for (auto iter = _glyph_map.begin(); iter != _glyph_map.end(); iter++)
    34     for (auto iter = _glyph_map.begin(); iter != _glyph_map.end(); iter++)
    35 	{
    35     {
    36 		SDL_FreeSurface(iter->second);
    36         SDL_FreeSurface(iter->second);
    37 	}
    37     }
    38 	_glyph_map.clear();
    38     _glyph_map.clear();
    39 }
    39 }
    40 
    40 
    41 
    41 
    42 GlyphRenderer::GlyphRenderer()
    42 GlyphRenderer::GlyphRenderer()
    43  : _font_regular(NULL), _font_bold(NULL), _cell_width(0), _cell_height(0), _cache(), _colormap()
    43  : _font_regular(NULL), _font_bold(NULL), _cell_width(0), _cell_height(0), _cache(), _colormap()
    44 {
    44 {
    45 	if (TTF_Init() == -1)
    45     if (TTF_Init() == -1)
    46 	{
    46     {
    47 	    printf("TTF_Init: %s\n", TTF_GetError());
    47         printf("TTF_Init: %s\n", TTF_GetError());
    48 	    throw std::exception();
    48         throw std::exception();
    49 	}
    49     }
    50 }
    50 }
    51 
    51 
    52 
    52 
    53 GlyphRenderer::~GlyphRenderer()
    53 GlyphRenderer::~GlyphRenderer()
    54 {
    54 {
    55 	_cache.flush();
    55     _cache.flush();
    56 	close_font();
    56     close_font();
    57 	TTF_Quit();
    57     TTF_Quit();
    58 }
    58 }
    59 
    59 
    60 
    60 
    61 void GlyphRenderer::open_font(const char *fname_regular, const char *fname_bold, int ptsize)
    61 void GlyphRenderer::open_font(const char *fname_regular, const char *fname_bold, int ptsize)
    62 {
    62 {
    63 	close_font();
    63     close_font();
    64 
    64 
    65 	// open regular font
    65     // open regular font
    66 	_font_regular = TTF_OpenFont(fname_regular, ptsize);
    66     _font_regular = TTF_OpenFont(fname_regular, ptsize);
    67 	if (!_font_regular)
    67     if (!_font_regular)
    68 	{
    68     {
    69 		printf("TTF_OpenFont: %s\n", TTF_GetError());
    69         printf("TTF_OpenFont: %s\n", TTF_GetError());
    70 		throw std::exception();
    70         throw std::exception();
    71 	}
    71     }
    72 
    72 
    73 	// open bold font
    73     // open bold font
    74 	_font_bold = TTF_OpenFont(fname_bold, ptsize);
    74     _font_bold = TTF_OpenFont(fname_bold, ptsize);
    75 	if (!_font_bold)
    75     if (!_font_bold)
    76 	{
    76     {
    77 		printf("TTF_OpenFont: %s\n", TTF_GetError());
    77         printf("TTF_OpenFont: %s\n", TTF_GetError());
    78 		throw std::exception();
    78         throw std::exception();
    79 	}
    79     }
    80 
    80 
    81 	// update metrics for regular font
    81     // update metrics for regular font
    82 	int advance;
    82     int advance;
    83 	if (TTF_GlyphMetrics(_font_regular, 'M', NULL, NULL, NULL, NULL, &advance) == -1)
    83     if (TTF_GlyphMetrics(_font_regular, 'M', NULL, NULL, NULL, NULL, &advance) == -1)
    84 	{
    84     {
    85 	    printf("TTF_GlyphMetrics: %s\n", TTF_GetError());
    85         printf("TTF_GlyphMetrics: %s\n", TTF_GetError());
    86 	}
    86     }
    87 	_cell_width = advance;
    87     _cell_width = advance;
    88 	_cell_height = TTF_FontHeight(_font_regular);
    88     _cell_height = TTF_FontHeight(_font_regular);
    89 
    89 
    90 	// read metrics for bold font
    90     // read metrics for bold font
    91 	if (TTF_GlyphMetrics(_font_bold, 'M', NULL, NULL, NULL, NULL, &advance) == -1)
    91     if (TTF_GlyphMetrics(_font_bold, 'M', NULL, NULL, NULL, NULL, &advance) == -1)
    92 	{
    92     {
    93 		printf("TTF_GlyphMetrics: %s\n", TTF_GetError());
    93         printf("TTF_GlyphMetrics: %s\n", TTF_GetError());
    94 	}
    94     }
    95 	if (advance > _cell_width)
    95     if (advance > _cell_width)
    96 	{
    96     {
    97 		_cell_width = advance;
    97         _cell_width = advance;
    98 	}
    98     }
    99 	int height = TTF_FontHeight(_font_bold);
    99     int height = TTF_FontHeight(_font_bold);
   100 	if (height > _cell_height)
   100     if (height > _cell_height)
   101 	{
   101     {
   102 		_cell_height = height;
   102         _cell_height = height;
   103 	}
   103     }
   104 }
   104 }
   105 
   105 
   106 
   106 
   107 void GlyphRenderer::close_font()
   107 void GlyphRenderer::close_font()
   108 {
   108 {
   109 	if (_font_regular)
   109     if (_font_regular)
   110 	{
   110     {
   111 		TTF_CloseFont(_font_regular);
   111         TTF_CloseFont(_font_regular);
   112 		_font_regular = NULL;
   112         _font_regular = NULL;
   113 	}
   113     }
   114 	if (_font_bold)
   114     if (_font_bold)
   115 	{
   115     {
   116 		TTF_CloseFont(_font_bold);
   116         TTF_CloseFont(_font_bold);
   117 		_font_bold = NULL;
   117         _font_bold = NULL;
   118 	}
   118     }
   119 }
   119 }
   120 
   120 
   121 
   121 
   122 SDL_Surface *GlyphRenderer::render_cell(Uint16 ch, Uint16 attr)
   122 SDL_Surface *GlyphRenderer::render_cell(Uint16 ch, Uint16 attr)
   123 {
   123 {
   124 	SDL_Surface *cell_surface;
   124     SDL_Surface *cell_surface;
   125 	TTF_Font *font;
   125     TTF_Font *font;
   126 	SDL_Color fgcolor, bgcolor;
   126     SDL_Color fgcolor, bgcolor;
   127 
   127 
   128 	// try cache
   128     // try cache
   129 	cell_surface = _cache.lookup_glyph(ch);
   129     cell_surface = _cache.lookup_glyph(ch);
   130 	if (cell_surface)
   130     if (cell_surface)
   131 	{
   131     {
   132 		return cell_surface;
   132         return cell_surface;
   133 	}
   133     }
   134 
   134 
   135 	// load attributes
   135     // load attributes
   136 	_colormap.index_to_rgb(attr & 0x000F, fgcolor);
   136     _colormap.index_to_rgb(attr & 0x000F, fgcolor);
   137 	_colormap.index_to_rgb((attr & 0x00F0) >> 4, bgcolor);
   137     _colormap.index_to_rgb((attr & 0x00F0) >> 4, bgcolor);
   138 	Style style = (Style) ((attr & 0xFF00) >> 8);
   138     Style style = (Style) ((attr & 0xFF00) >> 8);
   139 	font = (style == Style::BOLD) ? _font_bold : _font_regular;
   139     font = (style == Style::BOLD) ? _font_bold : _font_regular;
   140 
   140 
   141 	// create surface for whole cell and fill it with bg color
   141     // create surface for whole cell and fill it with bg color
   142 	cell_surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
   142     cell_surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
   143 			_cell_width, _cell_height, 32, 0, 0, 0, 0);
   143             _cell_width, _cell_height, 32, 0, 0, 0, 0);
   144 	SDL_Rect dst_rect;
   144     SDL_Rect dst_rect;
   145 	dst_rect.x = 0;
   145     dst_rect.x = 0;
   146 	dst_rect.y = 0;
   146     dst_rect.y = 0;
   147 	dst_rect.w = _cell_width;
   147     dst_rect.w = _cell_width;
   148 	dst_rect.h = _cell_height;
   148     dst_rect.h = _cell_height;
   149 	Uint32 bgcolor_mapped = SDL_MapRGB(cell_surface->format, bgcolor.r, bgcolor.g, bgcolor.b);
   149     Uint32 bgcolor_mapped = SDL_MapRGB(cell_surface->format, bgcolor.r, bgcolor.g, bgcolor.b);
   150 	SDL_FillRect(cell_surface, &dst_rect, bgcolor_mapped);
   150     SDL_FillRect(cell_surface, &dst_rect, bgcolor_mapped);
   151 
   151 
   152 	// render glyph, blit it onto cell surface
   152     // render glyph, blit it onto cell surface
   153 	if (ch)
   153     if (ch)
   154 	{
   154     {
   155 		SDL_Surface *glyph_surface = TTF_RenderGlyph_Shaded(font, ch, fgcolor, bgcolor);
   155         SDL_Surface *glyph_surface = TTF_RenderGlyph_Shaded(font, ch, fgcolor, bgcolor);
   156 		int minx, maxy;
   156         int minx, maxy;
   157 		TTF_GlyphMetrics(font, ch, &minx, NULL, NULL, &maxy, NULL);
   157         TTF_GlyphMetrics(font, ch, &minx, NULL, NULL, &maxy, NULL);
   158 		dst_rect.x = minx;
   158         dst_rect.x = minx;
   159 		dst_rect.y = TTF_FontAscent(font) - maxy;
   159         dst_rect.y = TTF_FontAscent(font) - maxy;
   160 		SDL_BlitSurface(glyph_surface, NULL, cell_surface, &dst_rect);
   160         SDL_BlitSurface(glyph_surface, NULL, cell_surface, &dst_rect);
   161 		SDL_FreeSurface(glyph_surface);
   161         SDL_FreeSurface(glyph_surface);
   162 	}
   162     }
   163 
   163 
   164 	// convert to display format
   164     // convert to display format
   165 	SDL_Surface *tmp_surface = cell_surface;
   165     SDL_Surface *tmp_surface = cell_surface;
   166 	cell_surface = SDL_DisplayFormat(tmp_surface);
   166     cell_surface = SDL_DisplayFormat(tmp_surface);
   167 	SDL_FreeSurface(tmp_surface);
   167     SDL_FreeSurface(tmp_surface);
   168 
   168 
   169 	// put to cache
   169     // put to cache
   170 	_cache.put_glyph(ch, cell_surface);
   170     _cache.put_glyph(ch, cell_surface);
   171 
   171 
   172 	return cell_surface;
   172     return cell_surface;
   173 }
   173 }
   174 
   174 
   175 
   175 
   176 void TerminalScreen::select_font(const char *fname_regular, const char *fname_bold, int ptsize)
   176 void TerminalScreen::select_font(const char *fname_regular, const char *fname_bold, int ptsize)
   177 {
   177 {
   178 	_render.open_font(fname_regular, fname_bold, ptsize);
   178     _render.open_font(fname_regular, fname_bold, ptsize);
   179 	_reset_cells();
   179     _reset_cells();
   180 }
   180 }
   181 
   181 
   182 void TerminalScreen::resize(int pxwidth, int pxheight)
   182 void TerminalScreen::resize(int pxwidth, int pxheight)
   183 {
   183 {
   184     _screen_surface = SDL_SetVideoMode(pxwidth, pxheight, 0, SDL_SWSURFACE|SDL_ANYFORMAT|SDL_RESIZABLE);
   184     _screen_surface = SDL_SetVideoMode(pxwidth, pxheight, 0, SDL_SWSURFACE|SDL_ANYFORMAT|SDL_RESIZABLE);
   185 
   185 
   186     if (_screen_surface == NULL)
   186     if (_screen_surface == NULL)
   187     {
   187     {
   188 		fprintf(stderr, "Unable to set video: %s\n", SDL_GetError());
   188         fprintf(stderr, "Unable to set video: %s\n", SDL_GetError());
   189 		throw std::exception();
   189         throw std::exception();
   190     }
   190     }
   191 
   191 
   192     SDL_WM_SetCaption("terminal", NULL);
   192     SDL_WM_SetCaption("terminal", NULL);
   193 
   193 
   194     _pixel_width = pxwidth;
   194     _pixel_width = pxwidth;
   198 }
   198 }
   199 
   199 
   200 
   200 
   201 void TerminalScreen::erase()
   201 void TerminalScreen::erase()
   202 {
   202 {
   203 	std::fill(_cells_front.begin(), _cells_front.end(), TerminalCell());
   203     std::fill(_cells_front.begin(), _cells_front.end(), TerminalCell());
   204 }
   204 }
   205 
   205 
   206 
   206 
   207 void TerminalScreen::putch(int x, int y, Uint16 ch, Uint16 attr)
   207 void TerminalScreen::putch(int x, int y, Uint16 ch, Uint16 attr)
   208 {
   208 {
   209 	TerminalCell &cell = _cells_front[y * _width + x];
   209     TerminalCell &cell = _cells_front[y * _width + x];
   210 	cell.ch = ch;
   210     cell.ch = ch;
   211 	cell.attr = attr;
   211     cell.attr = attr;
   212 }
   212 }
   213 
   213 
   214 
   214 
   215 void TerminalScreen::commit()
   215 void TerminalScreen::commit()
   216 {
   216 {
   217 	auto front_iter = _cells_front.begin();
   217     auto front_iter = _cells_front.begin();
   218 	auto back_iter = _cells_back.begin();
   218     auto back_iter = _cells_back.begin();
   219 	SDL_Surface *cell_surface;
   219     SDL_Surface *cell_surface;
   220 	SDL_Rect dst_rect;
   220     SDL_Rect dst_rect;
   221 	for (int y = 0; y < _height; y++)
   221     for (int y = 0; y < _height; y++)
   222 	{
   222     {
   223 		for (int x = 0; x < _width; x++)
   223         for (int x = 0; x < _width; x++)
   224 		{
   224         {
   225 			if (*front_iter != *back_iter)
   225             if (*front_iter != *back_iter)
   226 			{
   226             {
   227 				dst_rect.x = x * _cell_width;
   227                 dst_rect.x = x * _cell_width;
   228 				dst_rect.y = y * _cell_height;
   228                 dst_rect.y = y * _cell_height;
   229 				cell_surface = _render.render_cell(front_iter->ch, front_iter->attr);
   229                 cell_surface = _render.render_cell(front_iter->ch, front_iter->attr);
   230 				SDL_BlitSurface(cell_surface, NULL, _screen_surface, &dst_rect);
   230                 SDL_BlitSurface(cell_surface, NULL, _screen_surface, &dst_rect);
   231 				*back_iter = *front_iter;
   231                 *back_iter = *front_iter;
   232 			}
   232             }
   233 			front_iter++;
   233             front_iter++;
   234 			back_iter++;
   234             back_iter++;
   235 		}
   235         }
   236 	}
   236     }
   237 
   237 
   238 	SDL_UpdateRect(_screen_surface, 0, 0, 0, 0);
   238     SDL_UpdateRect(_screen_surface, 0, 0, 0, 0);
   239 }
   239 }
   240 
   240 
   241 
   241 
   242 void TerminalScreen::_reset_cells()
   242 void TerminalScreen::_reset_cells()
   243 {
   243 {
   244 	_cell_width = _render.get_cell_width();
   244     _cell_width = _render.get_cell_width();
   245 	_cell_height = _render.get_cell_height();
   245     _cell_height = _render.get_cell_height();
   246 	if (!_cell_width || !_cell_height)
   246     if (!_cell_width || !_cell_height)
   247 		return;
   247         return;
   248 
   248 
   249 	_width = _pixel_width / _cell_width;
   249     _width = _pixel_width / _cell_width;
   250 	_height = _pixel_height / _cell_height;
   250     _height = _pixel_height / _cell_height;
   251 	if (!_width || !_height)
   251     if (!_width || !_height)
   252 		return;
   252         return;
   253 
   253 
   254 	int num_cells = _width * _height;
   254     int num_cells = _width * _height;
   255 	_cells_front.resize(num_cells, TerminalCell());
   255     _cells_front.resize(num_cells, TerminalCell());
   256 	_cells_back.resize(num_cells, TerminalCell());
   256     _cells_back.resize(num_cells, TerminalCell());
   257 }
   257 }
   258 
   258 
   259 
   259 
   260 Terminal::Terminal()
   260 Terminal::Terminal()
   261  : _screen(), _attr(7), _mousemove_last_x(-1)
   261  : _screen(), _attr(7), _mousemove_last_x(-1)
   262 {
   262 {
   263     if (SDL_Init(SDL_INIT_VIDEO) == -1)
   263     if (SDL_Init(SDL_INIT_VIDEO) == -1)
   264     {
   264     {
   265 		fprintf(stderr, "Unable to initialize SDL: %s\n", SDL_GetError());
   265         fprintf(stderr, "Unable to initialize SDL: %s\n", SDL_GetError());
   266 		throw std::exception();
   266         throw std::exception();
   267     }
   267     }
   268     SDL_EnableUNICODE(1);
   268     SDL_EnableUNICODE(1);
   269 }
   269 }
   270 
   270 
   271 
   271 
   272 Terminal::~Terminal()
   272 Terminal::~Terminal()
   273 {
   273 {
   274 	SDL_Quit();
   274     SDL_Quit();
   275 }
   275 }
   276 
   276 
   277 
   277 
   278 void Terminal::get_next_event(Event &event)
   278 void Terminal::get_next_event(Event &event)
   279 {
   279 {
   280 	static SDL_Event sdl_event;
   280     static SDL_Event sdl_event;
   281 
   281 
   282 	while (SDL_WaitEvent(&sdl_event))
   282     while (SDL_WaitEvent(&sdl_event))
   283 	{
   283     {
   284 		switch (sdl_event.type)
   284         switch (sdl_event.type)
   285 		{
   285         {
   286 			case SDL_QUIT:
   286             case SDL_QUIT:
   287 				event.type = Event::QUIT;
   287                 event.type = Event::QUIT;
   288 				return;
   288                 return;
   289 
   289 
   290 			case SDL_KEYDOWN:
   290             case SDL_KEYDOWN:
   291 			{
   291             {
   292 				//switch(event.key.keysym.sym)
   292                 //switch(event.key.keysym.sym)
   293 				event.type = Event::KEYPRESS;
   293                 event.type = Event::KEYPRESS;
   294 				const char *keyname = _translate_keyname(sdl_event.key.keysym.sym);
   294                 const char *keyname = _translate_keyname(sdl_event.key.keysym.sym);
   295 				// return only keyname or unicode, never both
   295                 // return only keyname or unicode, never both
   296 				if (keyname)
   296                 if (keyname)
   297 				{
   297                 {
   298 					strncpy(event.key.keyname, keyname, 10);
   298                     strncpy(event.key.keyname, keyname, 10);
   299 					event.key.unicode = 0;
   299                     event.key.unicode = 0;
   300 				}
   300                 }
   301 				else
   301                 else
   302 				{
   302                 {
   303 					event.key.keyname[0] = 0;
   303                     event.key.keyname[0] = 0;
   304 					event.key.unicode = sdl_event.key.keysym.unicode;
   304                     event.key.unicode = sdl_event.key.keysym.unicode;
   305 					if (!event.key.unicode)
   305                     if (!event.key.unicode)
   306 						break; // continue loop (unknown key)
   306                         break; // continue loop (unknown key)
   307 				}
   307                 }
   308 				return;
   308                 return;
   309 			}
   309             }
   310 
   310 
   311 			case SDL_MOUSEBUTTONDOWN:
   311             case SDL_MOUSEBUTTONDOWN:
   312 			case SDL_MOUSEBUTTONUP:
   312             case SDL_MOUSEBUTTONUP:
   313 				event.type = (sdl_event.type == SDL_MOUSEBUTTONDOWN) ? Event::MOUSEDOWN : Event::MOUSEUP;
   313                 event.type = (sdl_event.type == SDL_MOUSEBUTTONDOWN) ? Event::MOUSEDOWN : Event::MOUSEUP;
   314 				event.mouse.x = sdl_event.button.x / _screen.get_cell_width();
   314                 event.mouse.x = sdl_event.button.x / _screen.get_cell_width();
   315 				event.mouse.y = sdl_event.button.y / _screen.get_cell_height();
   315                 event.mouse.y = sdl_event.button.y / _screen.get_cell_height();
   316 				event.mouse.button = sdl_event.button.button;
   316                 event.mouse.button = sdl_event.button.button;
   317 				_mousemove_last_x = -1;
   317                 _mousemove_last_x = -1;
   318 				return;
   318                 return;
   319 
   319 
   320 			case SDL_MOUSEMOTION:
   320             case SDL_MOUSEMOTION:
   321 				event.type = Event::MOUSEMOVE;
   321                 event.type = Event::MOUSEMOVE;
   322 				event.mouse.x = sdl_event.motion.x / _screen.get_cell_width();
   322                 event.mouse.x = sdl_event.motion.x / _screen.get_cell_width();
   323 				event.mouse.y = sdl_event.motion.y / _screen.get_cell_height();
   323                 event.mouse.y = sdl_event.motion.y / _screen.get_cell_height();
   324 				if (_mousemove_last_x != event.mouse.x ||
   324                 if (_mousemove_last_x != event.mouse.x ||
   325 		            _mousemove_last_y != event.mouse.y)
   325                     _mousemove_last_y != event.mouse.y)
   326 				{
   326                 {
   327 					_mousemove_last_x = event.mouse.x;
   327                     _mousemove_last_x = event.mouse.x;
   328 					_mousemove_last_y = event.mouse.y;
   328                     _mousemove_last_y = event.mouse.y;
   329 					return;
   329                     return;
   330 				}
   330                 }
   331 				break; // continue loop when mouse position did not change
   331                 break; // continue loop when mouse position did not change
   332 
   332 
   333 			default:
   333             default:
   334 				break; // continue loop
   334                 break; // continue loop
   335 		}
   335         }
   336 	}
   336     }
   337 }
   337 }
   338 
   338 
   339 
   339 
   340 const char *Terminal::_translate_keyname(SDLKey sym)
   340 const char *Terminal::_translate_keyname(SDLKey sym)
   341 {
   341 {
   342 	switch (sym)
   342     switch (sym)
   343 	{
   343     {
   344 		case SDLK_BACKSPACE: 	return "backspace";
   344         case SDLK_BACKSPACE:    return "backspace";
   345 		case SDLK_TAB:			return "tab";
   345         case SDLK_TAB:          return "tab";
   346 		case SDLK_RETURN:		return "enter";
   346         case SDLK_RETURN:       return "enter";
   347 		case SDLK_KP_ENTER:		return "enter";
   347         case SDLK_KP_ENTER:     return "enter";
   348 		case SDLK_ESCAPE:		return "escape";
   348         case SDLK_ESCAPE:       return "escape";
   349 		case SDLK_DELETE:		return "delete";
   349         case SDLK_DELETE:       return "delete";
   350 		case SDLK_INSERT:		return "insert";
   350         case SDLK_INSERT:       return "insert";
   351 		case SDLK_UP:			return "up";
   351         case SDLK_UP:           return "up";
   352 		case SDLK_DOWN:			return "down";
   352         case SDLK_DOWN:         return "down";
   353 		case SDLK_LEFT:			return "left";
   353         case SDLK_LEFT:         return "left";
   354 		case SDLK_RIGHT:		return "right";
   354         case SDLK_RIGHT:        return "right";
   355 		case SDLK_HOME:			return "home";
   355         case SDLK_HOME:         return "home";
   356 		case SDLK_END:			return "end";
   356         case SDLK_END:          return "end";
   357 		case SDLK_PAGEUP:		return "pageup";
   357         case SDLK_PAGEUP:       return "pageup";
   358 		case SDLK_PAGEDOWN:		return "pagedown";
   358         case SDLK_PAGEDOWN:     return "pagedown";
   359 		case SDLK_F1:			return "f1";
   359         case SDLK_F1:           return "f1";
   360 		case SDLK_F2:			return "f2";
   360         case SDLK_F2:           return "f2";
   361 		case SDLK_F3:			return "f3";
   361         case SDLK_F3:           return "f3";
   362 		case SDLK_F4:			return "f4";
   362         case SDLK_F4:           return "f4";
   363 		case SDLK_F5:			return "f5";
   363         case SDLK_F5:           return "f5";
   364 		case SDLK_F6:			return "f6";
   364         case SDLK_F6:           return "f6";
   365 		case SDLK_F7:			return "f7";
   365         case SDLK_F7:           return "f7";
   366 		case SDLK_F8:			return "f8";
   366         case SDLK_F8:           return "f8";
   367 		case SDLK_F9:			return "f9";
   367         case SDLK_F9:           return "f9";
   368 		case SDLK_F10:			return "f10";
   368         case SDLK_F10:          return "f10";
   369 		case SDLK_F11:			return "f11";
   369         case SDLK_F11:          return "f11";
   370 		case SDLK_F12:			return "f12";
   370         case SDLK_F12:          return "f12";
   371 		case SDLK_PRINT:		return "print";
   371         case SDLK_PRINT:        return "print";
   372 		case SDLK_SCROLLOCK:	return "scrllock";
   372         case SDLK_SCROLLOCK:    return "scrllock";
   373 		case SDLK_PAUSE:	    return "pause";
   373         case SDLK_PAUSE:        return "pause";
   374 		default: return NULL;
   374         default: return NULL;
   375 	}
   375     }
   376 }
   376 }
   377 
   377