Yet another UNICODE overhaul - Using seperate buffer for UNICODE chars and only use it in key_ascii() while still using keysyms for the rest of the program so we do not screw up readings by key values altered by modifers - possibly still room to optimize
This commit is contained in:
parent
02e7490c63
commit
02b1872aa9
|
@ -3,6 +3,7 @@ D2X-Rebirth Changelog
|
|||
20081118
|
||||
--------
|
||||
main/console.c: When printing Gamelog, make sure canvas is NULL
|
||||
main/newmenu.c, main/multi.c, main/automap.c, main/gamecntl.c, ui/inputbox.c, ui/menubar.c, arch/sdl/event.c, arch/sdl/key.c, arch/include/key.h: Yet another UNICODE overhaul - Using seperate buffer for UNICODE chars and only use it in key_ascii() while still using keysyms for the rest of the program so we do not screw up readings by key values altered by modifers - possibly still room to optimize
|
||||
|
||||
20081115
|
||||
--------
|
||||
|
|
|
@ -12,23 +12,9 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
|
|||
*/
|
||||
|
||||
/*
|
||||
* $Source: /cvsroot/dxx-rebirth/d2x-rebirth/arch/include/key.h,v $
|
||||
* $Revision: 1.1.1.1 $
|
||||
* $Author: zicodxx $
|
||||
* $Date: 2006/03/17 19:54:32 $
|
||||
*
|
||||
* Header for keyboard functions
|
||||
*
|
||||
* $Log: key.h,v $
|
||||
* Revision 1.1.1.1 2006/03/17 19:54:32 zicodxx
|
||||
* initial import
|
||||
*
|
||||
* Revision 1.2 2001/01/28 16:21:54 bradleyb
|
||||
* More header unification...
|
||||
*
|
||||
* Revision 1.1 2001/01/28 05:46:33 bradleyb
|
||||
* Unified arch headers
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _KEY_H
|
||||
|
@ -37,6 +23,8 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
|
|||
#include "pstypes.h"
|
||||
#include "fix.h"
|
||||
|
||||
#define KEY_BUFFER_SIZE 16
|
||||
|
||||
//==========================================================================
|
||||
// This installs the int9 vector and initializes the keyboard in buffered
|
||||
// ASCII mode. key_close simply undoes that.
|
||||
|
@ -57,6 +45,9 @@ extern unsigned char keyd_editor_mode;
|
|||
// Time in seconds when last key was pressed...
|
||||
extern volatile int keyd_time_when_last_pressed;
|
||||
|
||||
// Stores Unicode values registered in one event_loop call
|
||||
unsigned char unicode_frame_buffer[KEY_BUFFER_SIZE];
|
||||
|
||||
//==========================================================================
|
||||
// These are the "buffered" keypress routines. Use them by setting the
|
||||
// "keyd_buffer_type" variable.
|
||||
|
@ -69,7 +60,7 @@ extern int key_inkey(); // Gets key if one, other returns 0.
|
|||
extern int key_inkey_time(fix *time); // Same as inkey, but returns the time the key was pressed down.
|
||||
extern int key_peekkey(); // Same as inkey, but doesn't remove key from buffer.
|
||||
|
||||
extern unsigned char key_to_ascii(int keycode);
|
||||
extern unsigned char key_ascii();
|
||||
|
||||
extern void key_debug(); // Does an INT3
|
||||
|
||||
|
|
|
@ -12,55 +12,56 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "key.h"
|
||||
|
||||
#include <SDL/SDL.h>
|
||||
|
||||
extern void key_handler(SDL_KeyboardEvent *event);
|
||||
extern void mouse_button_handler(SDL_MouseButtonEvent *mbe);
|
||||
extern void mouse_motion_handler(SDL_MouseMotionEvent *mme);
|
||||
#ifndef USE_LINUX_JOY // stpohle - so we can choose at compile time..
|
||||
extern void joy_button_handler(SDL_JoyButtonEvent *jbe);
|
||||
extern void joy_hat_handler(SDL_JoyHatEvent *jhe);
|
||||
extern void joy_axis_handler(SDL_JoyAxisEvent *jae);
|
||||
#endif
|
||||
|
||||
static int initialised=0;
|
||||
|
||||
void event_poll()
|
||||
{
|
||||
SDL_Event event;
|
||||
int clean_uniframe=1;
|
||||
|
||||
while (SDL_PollEvent(&event)) {
|
||||
switch(event.type) {
|
||||
case SDL_KEYDOWN:
|
||||
case SDL_KEYUP:
|
||||
key_handler((SDL_KeyboardEvent *)&event);
|
||||
break;
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
mouse_button_handler((SDL_MouseButtonEvent *)&event);
|
||||
break;
|
||||
case SDL_MOUSEMOTION:
|
||||
mouse_motion_handler((SDL_MouseMotionEvent *)&event);
|
||||
break;
|
||||
#ifndef USE_LINUX_JOY // stpohle - so we can choose at compile time..
|
||||
case SDL_JOYBUTTONDOWN:
|
||||
case SDL_JOYBUTTONUP:
|
||||
joy_button_handler((SDL_JoyButtonEvent *)&event);
|
||||
break;
|
||||
case SDL_JOYAXISMOTION:
|
||||
joy_axis_handler((SDL_JoyAxisEvent *)&event);
|
||||
break;
|
||||
case SDL_JOYHATMOTION:
|
||||
joy_hat_handler((SDL_JoyHatEvent *)&event);
|
||||
break;
|
||||
case SDL_JOYBALLMOTION:
|
||||
break;
|
||||
#endif
|
||||
case SDL_QUIT: {
|
||||
void quit_request();
|
||||
quit_request();
|
||||
} break;
|
||||
case SDL_KEYDOWN:
|
||||
case SDL_KEYUP:
|
||||
if (clean_uniframe)
|
||||
memset(unicode_frame_buffer,'\0',sizeof(unsigned char)*KEY_BUFFER_SIZE);
|
||||
clean_uniframe=0;
|
||||
key_handler((SDL_KeyboardEvent *)&event);
|
||||
break;
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
mouse_button_handler((SDL_MouseButtonEvent *)&event);
|
||||
break;
|
||||
case SDL_MOUSEMOTION:
|
||||
mouse_motion_handler((SDL_MouseMotionEvent *)&event);
|
||||
break;
|
||||
case SDL_JOYBUTTONDOWN:
|
||||
case SDL_JOYBUTTONUP:
|
||||
joy_button_handler((SDL_JoyButtonEvent *)&event);
|
||||
break;
|
||||
case SDL_JOYAXISMOTION:
|
||||
joy_axis_handler((SDL_JoyAxisEvent *)&event);
|
||||
break;
|
||||
case SDL_JOYHATMOTION:
|
||||
joy_hat_handler((SDL_JoyHatEvent *)&event);
|
||||
break;
|
||||
case SDL_JOYBALLMOTION:
|
||||
break;
|
||||
case SDL_QUIT: {
|
||||
void quit_request();
|
||||
quit_request();
|
||||
} break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
139
arch/sdl/key.c
139
arch/sdl/key.c
|
@ -20,8 +20,6 @@
|
|||
#include "key.h"
|
||||
#include "timer.h"
|
||||
|
||||
#define KEY_BUFFER_SIZE 16
|
||||
|
||||
static unsigned char Installed = 0;
|
||||
|
||||
//-------- Variable accessed by outside functions ---------
|
||||
|
@ -32,6 +30,7 @@ volatile unsigned char keyd_last_pressed;
|
|||
volatile unsigned char keyd_last_released;
|
||||
volatile unsigned char keyd_pressed[256];
|
||||
volatile int keyd_time_when_last_pressed;
|
||||
unsigned char unicode_frame_buffer[KEY_BUFFER_SIZE] = { '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0' };
|
||||
|
||||
typedef struct Key_info {
|
||||
ubyte state; // state of key 1 == down, 0 == up
|
||||
|
@ -295,96 +294,79 @@ key_props key_properties[256] = {
|
|||
{ "", 255, -1 },
|
||||
{ "", 255, -1 },
|
||||
{ "", 255, -1 },
|
||||
{ "!", '!', SDLK_EXCLAIM },
|
||||
{ "@", '@', SDLK_AT },
|
||||
{ "#", '#', SDLK_HASH },
|
||||
{ "$", '$', SDLK_DOLLAR },
|
||||
{ "%", '%', -1 }, // 240
|
||||
{ "^", '^', SDLK_CARET },
|
||||
{ "&", '&', SDLK_AMPERSAND },
|
||||
{ "(", '(', SDLK_LEFTPAREN },
|
||||
{ ")", ')', SDLK_RIGHTPAREN },
|
||||
{ "_", '_', SDLK_UNDERSCORE },
|
||||
{ "+", '+', SDLK_PLUS },
|
||||
{ "{", '{', -1 },
|
||||
{ "}", '}', -1 },
|
||||
{ ":", ':', SDLK_COLON },
|
||||
{ "\"", '"', SDLK_QUOTEDBL }, // 250
|
||||
{ "~", '~', -1 },
|
||||
{ "|", '|', -1 },
|
||||
{ "<", '<', SDLK_LESS },
|
||||
{ ">", '>', SDLK_GREATER },
|
||||
{ "?", '?', SDLK_QUESTION }, // 255
|
||||
};
|
||||
|
||||
// As UNICODE chars have no RELEASED state, we save each one together with the symbol assigned to it.
|
||||
// If a symbol is RELEASED, check the list and we know which unicode we just released!
|
||||
// This way we almost "emulate" the RELEASED state for UNICODE chars.
|
||||
int sym2unimap[KEY_BUFFER_SIZE][2] =
|
||||
{
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ -1, -1 },
|
||||
{ "", 255, -1 },
|
||||
{ "", 255, -1 },
|
||||
{ "", 255, -1 },
|
||||
{ "", 255, -1 },
|
||||
{ "", 255, -1 }, // 240
|
||||
{ "", 255, -1 },
|
||||
{ "", 255, -1 },
|
||||
{ "", 255, -1 },
|
||||
{ "", 255, -1 },
|
||||
{ "", 255, -1 },
|
||||
{ "", 255, -1 },
|
||||
{ "", 255, -1 },
|
||||
{ "", 255, -1 },
|
||||
{ "", 255, -1 },
|
||||
{ "", 255, -1 }, // 250
|
||||
{ "", 255, -1 },
|
||||
{ "", 255, -1 },
|
||||
{ "", 255, -1 },
|
||||
{ "", 255, -1 },
|
||||
{ "", 255, -1 }, // 255
|
||||
};
|
||||
|
||||
char *key_text[256];
|
||||
|
||||
unsigned char key_to_ascii(int keycode)
|
||||
unsigned char key_ascii()
|
||||
{
|
||||
keycode &= 0xFF;
|
||||
return key_properties[keycode].ascii_value;
|
||||
static unsigned char unibuffer[KEY_BUFFER_SIZE] = { '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0' };
|
||||
int i=0, offset=0, count=0;
|
||||
|
||||
offset=strlen((const char*)unibuffer);
|
||||
|
||||
// move temporal chars from unicode_frame_buffer to empty space behind last unibuffer char (if any)
|
||||
for (i=offset; i < KEY_BUFFER_SIZE; i++)
|
||||
if (unicode_frame_buffer[count] != '\0')
|
||||
{
|
||||
unibuffer[i]=unicode_frame_buffer[count];
|
||||
unicode_frame_buffer[count]='\0';
|
||||
count++;
|
||||
}
|
||||
|
||||
// unibuffer is not empty. store first char, remove it, shift all chars one step left and then print our char
|
||||
if (unibuffer[0] != '\0')
|
||||
{
|
||||
unsigned char retval = unibuffer[0];
|
||||
unsigned char unibuffer_shift[KEY_BUFFER_SIZE];
|
||||
memset(unibuffer_shift,'\0',sizeof(unsigned char)*KEY_BUFFER_SIZE);
|
||||
memcpy(unibuffer_shift,unibuffer+1,sizeof(unsigned char)*(KEY_BUFFER_SIZE-1));
|
||||
memcpy(unibuffer,unibuffer_shift,sizeof(unsigned char)*KEY_BUFFER_SIZE);
|
||||
return retval;
|
||||
}
|
||||
else
|
||||
return 255;
|
||||
}
|
||||
|
||||
void key_handler(SDL_KeyboardEvent *event)
|
||||
void key_handler(SDL_KeyboardEvent *event, int counter)
|
||||
{
|
||||
ubyte state;
|
||||
int i, keycode, event_keysym=-1, event_keyuni=-1, key_state;
|
||||
int i, keycode, event_keysym=-1, key_state;
|
||||
Key_info *key;
|
||||
unsigned char temp;
|
||||
|
||||
// Read SDLK symbol and state
|
||||
event_keysym = event->keysym.sym;
|
||||
key_state = (event->state == SDL_PRESSED);
|
||||
|
||||
// Read (latin) unicode
|
||||
if (event->keysym.unicode > 31 && event->keysym.unicode < 255)
|
||||
{
|
||||
event_keyuni = tolower(event->keysym.unicode);
|
||||
// Now add the UNICODE char to our map (see comment on sym2unimap declaration)
|
||||
// fill the unicode frame-related unicode buffer
|
||||
if (key_state && event->keysym.unicode > 31 && event->keysym.unicode < 255)
|
||||
for (i = 0; i < KEY_BUFFER_SIZE; i++)
|
||||
{
|
||||
if (sym2unimap[i][0] == -1)
|
||||
if (unicode_frame_buffer[i] == '\0')
|
||||
{
|
||||
sym2unimap[i][0] = event_keyuni;
|
||||
sym2unimap[i][1] = event_keysym;
|
||||
unicode_frame_buffer[i] = event->keysym.unicode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else // no valid UNICODE - possibly 0 - see if we remove it from the list
|
||||
{
|
||||
for (i = 0; i < KEY_BUFFER_SIZE; i++)
|
||||
{
|
||||
if (event_keysym == sym2unimap[i][1])
|
||||
{
|
||||
event_keyuni = sym2unimap[i][0];
|
||||
sym2unimap[i][0] = sym2unimap[i][1] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
key_state = (event->state == SDL_PRESSED);
|
||||
|
||||
//=====================================================
|
||||
|
||||
|
@ -392,9 +374,7 @@ void key_handler(SDL_KeyboardEvent *event)
|
|||
keycode = i;
|
||||
key = &(key_data.keys[keycode]);
|
||||
|
||||
if (key_properties[i].ascii_value == event_keyuni && key_properties[i].ascii_value != 255)
|
||||
state = key_state;
|
||||
else if ((event_keyuni == -1 || event_keyuni == event_keysym) && key_properties[i].sym == event_keysym)
|
||||
if (key_properties[i].sym == event_keysym)
|
||||
state = key_state;
|
||||
else
|
||||
state = key->last_state;
|
||||
|
@ -482,12 +462,7 @@ void key_flush()
|
|||
for (i=0; i<KEY_BUFFER_SIZE; i++ ) {
|
||||
key_data.keybuffer[i] = 0;
|
||||
key_data.time_pressed[i] = 0;
|
||||
}
|
||||
|
||||
//Clear the unicode map
|
||||
for (i=0; i<KEY_BUFFER_SIZE; i++ ) {
|
||||
sym2unimap[i][0] = -1;
|
||||
sym2unimap[i][1] = -1;
|
||||
unicode_frame_buffer[i] = '\0';
|
||||
}
|
||||
|
||||
//use gettimeofday here:
|
||||
|
|
|
@ -1354,8 +1354,8 @@ void MarkerInputMessage(int key)
|
|||
DefiningMarkerMessage = 0;
|
||||
break;
|
||||
default:
|
||||
if (key > 0) {
|
||||
int ascii = key_to_ascii(key);
|
||||
{
|
||||
int ascii = key_ascii();
|
||||
if ((ascii < 255 ))
|
||||
if (Marker_index < 38 )
|
||||
{
|
||||
|
|
|
@ -1822,7 +1822,7 @@ void FinalCheats(int key)
|
|||
int i;
|
||||
char *cryptstring;
|
||||
|
||||
key=key_to_ascii(key);
|
||||
key=key_ascii();
|
||||
|
||||
for (i=0;i<15;i++)
|
||||
CheatBuffer[i]=CheatBuffer[i+1];
|
||||
|
@ -2228,58 +2228,55 @@ void ReadControls()
|
|||
if (Newdemo_state == ND_STATE_PLAYBACK )
|
||||
update_vcr_state();
|
||||
|
||||
while ((key=key_inkey_time(&key_time)) != 0) {
|
||||
if (con_events(key) && con_render)
|
||||
game_flush_inputs();
|
||||
key=key_inkey();
|
||||
|
||||
if (DefiningMarkerMessage)
|
||||
{
|
||||
MarkerInputMessage(key);
|
||||
continue;
|
||||
}
|
||||
if (con_events(key) && con_render)
|
||||
return;
|
||||
|
||||
if (DefiningMarkerMessage)
|
||||
{
|
||||
MarkerInputMessage(key);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef NETWORK
|
||||
if ( (Game_mode & GM_MULTI) && (multi_sending_message || multi_defining_message) )
|
||||
{
|
||||
multi_message_input_sub(key);
|
||||
continue;
|
||||
}
|
||||
if ( (Game_mode & GM_MULTI) && (multi_sending_message || multi_defining_message) )
|
||||
{
|
||||
multi_message_input_sub(key);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef RELEASE
|
||||
#ifdef NETWORK
|
||||
if ((key&KEY_DEBUGGED)&&(Game_mode&GM_MULTI)) {
|
||||
Network_message_reciever = 100; // Send to everyone...
|
||||
sprintf( Network_message, "%s %s", TXT_I_AM_A, TXT_CHEATER);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (Player_is_dead)
|
||||
HandleDeathKey(key);
|
||||
|
||||
if (Endlevel_sequence)
|
||||
HandleEndlevelKey(key);
|
||||
else if (Newdemo_state == ND_STATE_PLAYBACK ) {
|
||||
HandleDemoKey(key);
|
||||
|
||||
#ifndef RELEASE
|
||||
#ifdef NETWORK
|
||||
if ((key&KEY_DEBUGGED)&&(Game_mode&GM_MULTI)) {
|
||||
Network_message_reciever = 100; // Send to everyone...
|
||||
sprintf( Network_message, "%s %s", TXT_I_AM_A, TXT_CHEATER);
|
||||
}
|
||||
HandleTestKey(key);
|
||||
#endif
|
||||
} else {
|
||||
FinalCheats(key);
|
||||
|
||||
HandleSystemKey(key);
|
||||
HandleVRKey(key);
|
||||
HandleGameKey(key);
|
||||
|
||||
#ifndef RELEASE
|
||||
HandleTestKey(key);
|
||||
#endif
|
||||
|
||||
if (Player_is_dead)
|
||||
HandleDeathKey(key);
|
||||
|
||||
if (Endlevel_sequence)
|
||||
HandleEndlevelKey(key);
|
||||
else if (Newdemo_state == ND_STATE_PLAYBACK ) {
|
||||
HandleDemoKey(key);
|
||||
|
||||
#ifndef RELEASE
|
||||
HandleTestKey(key);
|
||||
#endif
|
||||
} else {
|
||||
FinalCheats(key);
|
||||
|
||||
HandleSystemKey(key);
|
||||
HandleVRKey(key);
|
||||
HandleGameKey(key);
|
||||
|
||||
#ifndef RELEASE
|
||||
HandleTestKey(key);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// if ((Players[Player_num].flags & PLAYER_FLAGS_CONVERTER) && keyd_pressed[KEY_F8] && (keyd_pressed[KEY_LALT] || keyd_pressed[KEY_RALT]))
|
||||
// transfer_energy_to_shield(key_down_time(KEY_F8));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1292,8 +1292,8 @@ void multi_message_input_sub(int key)
|
|||
game_flush_inputs();
|
||||
break;
|
||||
default:
|
||||
if (key > 0) {
|
||||
int ascii = key_to_ascii(key);
|
||||
{
|
||||
int ascii = key_ascii();
|
||||
if ((ascii < 255 ) && (ascii != 37)) {
|
||||
if (multi_message_index < MAX_MESSAGE_LEN-2 ) {
|
||||
Network_message[multi_message_index++] = ascii;
|
||||
|
|
|
@ -1264,7 +1264,7 @@ int newmenu_do4( char * title, char * subtitle, int nitems, newmenu_item * item,
|
|||
item[choice].value--;
|
||||
item[choice].text[item[choice].value] = 0;
|
||||
} else {
|
||||
ascii = key_to_ascii(k);
|
||||
ascii = key_ascii();
|
||||
if ((ascii < 255 ) && (item[choice].value < item[choice].text_len ))
|
||||
{
|
||||
int allowed;
|
||||
|
@ -1289,7 +1289,7 @@ int newmenu_do4( char * title, char * subtitle, int nitems, newmenu_item * item,
|
|||
}
|
||||
else if ((item[choice].type!=NM_TYPE_INPUT) && (item[choice].type!=NM_TYPE_INPUT_MENU) )
|
||||
{
|
||||
ascii = key_to_ascii(k);
|
||||
ascii = key_ascii();
|
||||
if (ascii < 255 ) {
|
||||
int choice1 = choice;
|
||||
ascii = toupper(ascii);
|
||||
|
@ -1804,8 +1804,8 @@ ReadFileNames:
|
|||
break;
|
||||
|
||||
default:
|
||||
if (key > 0) {
|
||||
int ascii = key_to_ascii(key);
|
||||
{
|
||||
int ascii = key_ascii();
|
||||
if ( ascii < 255 ) {
|
||||
int cc,cc1;
|
||||
cc=cc1=citem+1;
|
||||
|
@ -2105,8 +2105,8 @@ int newmenu_listbox1( char * title, int nitems, char * items[], int allow_abort_
|
|||
break;
|
||||
|
||||
default:
|
||||
if (key > 0) {
|
||||
int ascii = key_to_ascii(key);
|
||||
{
|
||||
int ascii = key_ascii();
|
||||
if ( ascii < 255 ) {
|
||||
int cc,cc1;
|
||||
cc=cc1=citem+1;
|
||||
|
|
|
@ -143,7 +143,7 @@ void ui_inputbox_do( UI_GADGET_INPUTBOX * inputbox, int keypress )
|
|||
if (inputbox->first_time) inputbox->first_time = 0;
|
||||
break;
|
||||
default:
|
||||
ascii = key_to_ascii(keypress);
|
||||
ascii = key_ascii();
|
||||
if ((ascii < 255 ) && (inputbox->position < inputbox->length-2))
|
||||
{
|
||||
if (inputbox->first_time) {
|
||||
|
|
|
@ -195,7 +195,7 @@ int menu_match_keypress( MENU * menu, int keypress )
|
|||
|
||||
keypress &= 0xFF;
|
||||
|
||||
c = key_to_ascii(keypress);
|
||||
c = key_ascii();
|
||||
|
||||
for (i=0; i< menu->NumItems; i++ )
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue