Fixes for #90, keyboard improvements and recognition of special keys for non-US keyboards

This commit is contained in:
Dimitris Panokostas 2018-02-18 01:22:37 +01:00
parent 427bae03cf
commit 99cbd583ed
2 changed files with 313 additions and 72 deletions

View file

@ -1,4 +1,4 @@
/*
/*
* UAE - The Un*x Amiga Emulator
*
* Keyboard buffer. Not really needed for X, but for SVGAlib and possibly
@ -27,42 +27,283 @@ static int kpb_first, kpb_last;
#define KEYBUF_SIZE 256
static int keybuf[KEYBUF_SIZE];
static uae_char* keyinject;
static int keyinject_offset;
static uae_u8 keyinject_previous;
static bool keyinject_state;
static bool keyinject_do;
int keys_available (void)
struct kbtab
{
int val;
val = kpb_first != kpb_last;
return val;
int ascii;
uae_u8 code;
uae_u8 qual;
};
static const struct kbtab kbtable[] =
{
{'~', 0x00, 0x60},
{'!', 0x01, 0x60},
{'@', 0x02, 0x60},
{'#', 0x03, 0x60},
{'$', 0x04, 0x60},
{'%', 0x05, 0x60},
{'^', 0x06, 0x60},
{'&', 0x07, 0x60},
{'*', 0x08, 0x60},
{'(', 0x09, 0x60},
{')', 0x0a, 0x60},
{'_', 0x0b, 0x60},
{'+', 0x0c, 0x60},
{'|', 0x0d, 0x60},
{'`', 0x00},
{'1', 0x01},
{'2', 0x02},
{'3', 0x03},
{'4', 0x04},
{'5', 0x05},
{'6', 0x06},
{'7', 0x07},
{'8', 0x08},
{'9', 0x09},
{'0', 0x0a},
{'-', 0x0b},
{'=', 0x0c},
{'\\', 0x0d},
{'\t', 0x42},
{'\n', 0x44},
{'{', 0x1a, 0x60},
{'}', 0x1b, 0x60},
{':', 0x29, 0x60},
{'"', 0x2b, 0x60},
{'[', 0x1a},
{']', 0x1b},
{';', 0x29},
{'\'', 0x2b},
{'<', 0x38, 0x60},
{'>', 0x39, 0x60},
{'?', 0x3a, 0x60},
{',', 0x38},
{'.', 0x39},
{'/', 0x3a},
{' ', 0x40},
{'q', 0x10},
{'w', 0x11},
{'e', 0x12},
{'r', 0x13},
{'t', 0x14},
{'y', 0x15},
{'u', 0x16},
{'i', 0x17},
{'o', 0x18},
{'p', 0x19},
{'a', 0x20},
{'s', 0x21},
{'d', 0x22},
{'f', 0x23},
{'g', 0x24},
{'h', 0x25},
{'j', 0x26},
{'k', 0x27},
{'l', 0x28},
{'z', 0x31},
{'x', 0x32},
{'c', 0x33},
{'v', 0x34},
{'b', 0x35},
{'n', 0x36},
{'m', 0x37},
{'Q', 0x10, 0x60},
{'W', 0x11, 0x60},
{'E', 0x12, 0x60},
{'R', 0x13, 0x60},
{'T', 0x14, 0x60},
{'Y', 0x15, 0x60},
{'U', 0x16, 0x60},
{'I', 0x17, 0x60},
{'O', 0x18, 0x60},
{'P', 0x19, 0x60},
{'A', 0x20, 0x60},
{'S', 0x21, 0x60},
{'D', 0x22, 0x60},
{'F', 0x23, 0x60},
{'G', 0x24, 0x60},
{'H', 0x25, 0x60},
{'J', 0x26, 0x60},
{'K', 0x27, 0x60},
{'L', 0x28, 0x60},
{'Z', 0x31, 0x60},
{'X', 0x32, 0x60},
{'C', 0x33, 0x60},
{'V', 0x34, 0x60},
{'B', 0x35, 0x60},
{'N', 0x36, 0x60},
{'M', 0x37, 0x60},
{0}
};
static void keytoscancode(int key, bool release)
{
int v = 0x40;
int q = 0x00;
int mask = release ? 0x80 : 0x00;
for (int i = 0; kbtable[i].ascii; i++)
{
if (kbtable[i].ascii == key)
{
v = kbtable[i].code;
q = kbtable[i].qual;
break;
}
}
v |= mask;
v = (v << 1) | (v >> 7);
q |= mask;
if (release)
{
record_key(v);
if (q & 0x7f)
{
q = (q << 1) | (q >> 7);
record_key(q);
}
}
else
{
if (q & 0x7f)
{
q = (q << 1) | (q >> 7);
record_key(q);
}
record_key(v);
}
}
int get_next_key (void)
// delay injection, some programs don't like too fast key events
static bool can_inject(void)
{
int key;
assert (kpb_first != kpb_last);
static int ovpos, cnt;
key = keybuf[kpb_last];
if (ovpos == vpos)
return false;
ovpos = vpos;
cnt++;
if (cnt < 4)
return false;
cnt = 0;
keyinject_do = true;
return true;
}
int keys_available(void)
{
int val;
val = kpb_first != kpb_last;
if (can_inject() && ((keyinject && keyinject[keyinject_offset]) || keyinject_state))
val = 1;
return val;
}
int get_next_key(void)
{
int key;
if (keyinject_do)
{
keyinject_do = false;
if (keyinject_state)
{
key = keyinject_previous;
keyinject_state = false;
keytoscancode(key, true);
}
else if (keyinject)
{
key = keyinject[keyinject_offset++];
keyinject_previous = key;
keyinject_state = true;
if (keyinject[keyinject_offset] == 0)
{
xfree(keyinject);
keyinject = nullptr;
keyinject_offset = 0;
}
keytoscancode(key, false);
}
}
assert(kpb_first != kpb_last);
key = keybuf[kpb_last];
if (++kpb_last == KEYBUF_SIZE)
kpb_last = 0;
return key;
kpb_last = 0;
//write_log (_T("%02x:%d\n"), key >> 1, key & 1);
return key;
}
int record_key (int kc)
int record_key(int kc)
{
int kpb_next = kpb_first + 1;
int kpb_next = kpb_first + 1;
if (kpb_next == KEYBUF_SIZE)
kpb_next = 0;
if (kpb_next == kpb_last) {
write_log (_T("Keyboard buffer overrun. Congratulations.\n"));
return 0;
}
keybuf[kpb_first] = kc;
kpb_first = kpb_next;
return 1;
//write_log (_T("got kc %02X\n"), ((kc << 7) | (kc >> 1)) & 0xff);
if (kpb_next == KEYBUF_SIZE)
kpb_next = 0;
if (kpb_next == kpb_last)
{
write_log(_T("Keyboard buffer overrun. Congratulations.\n"));
return 0;
}
keybuf[kpb_first] = kc;
kpb_first = kpb_next;
return 1;
}
void keybuf_init (void)
void keybuf_init(void)
{
kpb_first = kpb_last = 0;
inputdevice_updateconfig (&changed_prefs, &currprefs);
kpb_first = kpb_last = 0;
keyinject_offset = 0;
xfree(keyinject);
keyinject = nullptr;
inputdevice_updateconfig(&changed_prefs, &currprefs);
}
void keybuf_inject(const uae_char* txt)
{
uae_char* newbuf = xmalloc(uae_char, strlen(txt) + 1);
uae_char* p = newbuf;
for (int j = 0; j < strlen(txt); j++)
{
uae_char c = txt[j];
bool found = false;
for (int i = 0; kbtable[i].ascii; i++)
{
if (kbtable[i].ascii == c)
found = true;
}
if (found)
*p++ = c;
}
*p = 0;
if (p == newbuf)
{
xfree(newbuf);
return;
}
xfree(keyinject);
keyinject_offset = 0;
keyinject = newbuf;
}

View file

@ -393,12 +393,12 @@ static struct uae_input_device_kbr_default keytrans_amiga[] = {
{ SDL_SCANCODE_ESCAPE, INPUTEVENT_KEY_ESC },
{ SDL_SCANCODE_F1, INPUTEVENT_KEY_F1 },
{ SDL_SCANCODE_F2, INPUTEVENT_KEY_F2 },
{ SDL_SCANCODE_F3, INPUTEVENT_KEY_F3 },
{ SDL_SCANCODE_F4, INPUTEVENT_KEY_F4 },
{ SDL_SCANCODE_F1, INPUTEVENT_KEY_F1, 0, INPUTEVENT_SPC_FLOPPY0, ID_FLAG_QUALIFIER_SPECIAL, INPUTEVENT_SPC_EFLOPPY0, ID_FLAG_QUALIFIER_SPECIAL | ID_FLAG_QUALIFIER_SHIFT },
{ SDL_SCANCODE_F2, INPUTEVENT_KEY_F2, 0, INPUTEVENT_SPC_FLOPPY1, ID_FLAG_QUALIFIER_SPECIAL, INPUTEVENT_SPC_EFLOPPY1, ID_FLAG_QUALIFIER_SPECIAL | ID_FLAG_QUALIFIER_SHIFT },
{ SDL_SCANCODE_F3, INPUTEVENT_KEY_F3, 0, INPUTEVENT_SPC_FLOPPY2, ID_FLAG_QUALIFIER_SPECIAL, INPUTEVENT_SPC_EFLOPPY2, ID_FLAG_QUALIFIER_SPECIAL | ID_FLAG_QUALIFIER_SHIFT },
{ SDL_SCANCODE_F4, INPUTEVENT_KEY_F4, 0, INPUTEVENT_SPC_FLOPPY3, ID_FLAG_QUALIFIER_SPECIAL, INPUTEVENT_SPC_EFLOPPY3, ID_FLAG_QUALIFIER_SPECIAL | ID_FLAG_QUALIFIER_SHIFT },
{ SDL_SCANCODE_F5, INPUTEVENT_KEY_F5 },
{ SDL_SCANCODE_F5, INPUTEVENT_KEY_F5, 0, INPUTEVENT_SPC_STATERESTOREDIALOG, ID_FLAG_QUALIFIER_SPECIAL, INPUTEVENT_SPC_STATESAVEDIALOG, ID_FLAG_QUALIFIER_SPECIAL | ID_FLAG_QUALIFIER_SHIFT },
{ SDL_SCANCODE_F6, INPUTEVENT_KEY_F6 },
{ SDL_SCANCODE_F7, INPUTEVENT_KEY_F7 },
{ SDL_SCANCODE_F8, INPUTEVENT_KEY_F8 },
@ -427,7 +427,7 @@ static struct uae_input_device_kbr_default keytrans_amiga[] = {
{ SDL_SCANCODE_G, INPUTEVENT_KEY_G },
{ SDL_SCANCODE_H, INPUTEVENT_KEY_H },
{ SDL_SCANCODE_I, INPUTEVENT_KEY_I },
{ SDL_SCANCODE_J, INPUTEVENT_KEY_J },
{ SDL_SCANCODE_J, INPUTEVENT_KEY_J, 0, INPUTEVENT_SPC_SWAPJOYPORTS, ID_FLAG_QUALIFIER_SPECIAL },
{ SDL_SCANCODE_K, INPUTEVENT_KEY_K },
{ SDL_SCANCODE_L, INPUTEVENT_KEY_L },
{ SDL_SCANCODE_M, INPUTEVENT_KEY_M },
@ -457,13 +457,12 @@ static struct uae_input_device_kbr_default keytrans_amiga[] = {
{ SDL_SCANCODE_KP_8, INPUTEVENT_KEY_NP_8 },
{ SDL_SCANCODE_KP_9, INPUTEVENT_KEY_NP_9 },
{ SDL_SCANCODE_KP_0, INPUTEVENT_KEY_NP_0 },
{ SDL_SCANCODE_KP_PERIOD, INPUTEVENT_KEY_NP_PERIOD },
{ SDL_SCANCODE_KP_PLUS, INPUTEVENT_KEY_NP_ADD },
{ SDL_SCANCODE_KP_MINUS, INPUTEVENT_KEY_NP_SUB },
{ SDL_SCANCODE_KP_MULTIPLY, INPUTEVENT_KEY_NP_MUL },
{ SDL_SCANCODE_KP_PLUS, INPUTEVENT_KEY_NP_ADD, 0, INPUTEVENT_SPC_VOLUME_UP, ID_FLAG_QUALIFIER_SPECIAL, INPUTEVENT_SPC_MASTER_VOLUME_UP, ID_FLAG_QUALIFIER_SPECIAL | ID_FLAG_QUALIFIER_CONTROL, INPUTEVENT_SPC_INCREASE_REFRESHRATE, ID_FLAG_QUALIFIER_SPECIAL | ID_FLAG_QUALIFIER_SHIFT },
{ SDL_SCANCODE_KP_MINUS, INPUTEVENT_KEY_NP_SUB, 0, INPUTEVENT_SPC_VOLUME_DOWN, ID_FLAG_QUALIFIER_SPECIAL, INPUTEVENT_SPC_MASTER_VOLUME_DOWN, ID_FLAG_QUALIFIER_SPECIAL | ID_FLAG_QUALIFIER_CONTROL, INPUTEVENT_SPC_DECREASE_REFRESHRATE, ID_FLAG_QUALIFIER_SPECIAL | ID_FLAG_QUALIFIER_SHIFT },
{ SDL_SCANCODE_KP_MULTIPLY, INPUTEVENT_KEY_NP_MUL, 0, INPUTEVENT_SPC_VOLUME_MUTE, ID_FLAG_QUALIFIER_SPECIAL, INPUTEVENT_SPC_MASTER_VOLUME_MUTE, ID_FLAG_QUALIFIER_SPECIAL | ID_FLAG_QUALIFIER_CONTROL },
{ SDL_SCANCODE_KP_DIVIDE, INPUTEVENT_KEY_NP_DIV },
{ SDL_SCANCODE_KP_ENTER, INPUTEVENT_KEY_ENTER }, // The ENT from keypad..
{ SDL_SCANCODE_KP_ENTER, INPUTEVENT_KEY_ENTER },
{ SDL_SCANCODE_MINUS, INPUTEVENT_KEY_SUB },
{ SDL_SCANCODE_EQUALS, INPUTEVENT_KEY_EQUALS },
@ -473,16 +472,12 @@ static struct uae_input_device_kbr_default keytrans_amiga[] = {
{ SDL_SCANCODE_LSHIFT, INPUTEVENT_KEY_SHIFT_LEFT, 0, INPUTEVENT_SPC_QUALIFIER_SHIFT },
{ SDL_SCANCODE_LCTRL, INPUTEVENT_KEY_CTRL, 0, INPUTEVENT_SPC_QUALIFIER_CONTROL },
{ SDL_SCANCODE_LGUI, INPUTEVENT_KEY_AMIGA_LEFT, 0, INPUTEVENT_SPC_QUALIFIER_WIN },
{ SDL_SCANCODE_LALT, INPUTEVENT_KEY_ALT_LEFT, 0, INPUTEVENT_SPC_QUALIFIER_ALT },
{ SDL_SCANCODE_RALT, INPUTEVENT_KEY_ALT_RIGHT, 0, INPUTEVENT_SPC_QUALIFIER_ALT },
{ SDL_SCANCODE_RGUI, INPUTEVENT_KEY_AMIGA_RIGHT, 0, INPUTEVENT_SPC_QUALIFIER_WIN },
{ SDL_SCANCODE_MENU, INPUTEVENT_KEY_AMIGA_RIGHT, 0, INPUTEVENT_SPC_QUALIFIER_WIN },
{ SDL_SCANCODE_APPLICATION, INPUTEVENT_KEY_AMIGA_RIGHT, 0, INPUTEVENT_SPC_QUALIFIER_WIN },
{ SDL_SCANCODE_RCTRL, INPUTEVENT_KEY_CTRL, 0, INPUTEVENT_SPC_QUALIFIER_CONTROL },
{ SDL_SCANCODE_RSHIFT, INPUTEVENT_KEY_SHIFT_RIGHT, 0, INPUTEVENT_SPC_QUALIFIER_SHIFT },
@ -491,11 +486,11 @@ static struct uae_input_device_kbr_default keytrans_amiga[] = {
{ SDL_SCANCODE_LEFT, INPUTEVENT_KEY_CURSOR_LEFT },
{ SDL_SCANCODE_RIGHT, INPUTEVENT_KEY_CURSOR_RIGHT },
{ SDL_SCANCODE_INSERT, INPUTEVENT_KEY_AMIGA_LEFT },
{ SDL_SCANCODE_INSERT, INPUTEVENT_KEY_2B },
{ SDL_SCANCODE_DELETE, INPUTEVENT_KEY_DEL },
{ SDL_SCANCODE_HOME, INPUTEVENT_KEY_NP_LPAREN }, // Map home to left parent (as fsuae)
{ SDL_SCANCODE_END, INPUTEVENT_KEY_HELP }, // Help mapped to End key (as fsuae)}
{ SDL_SCANCODE_PAGEDOWN, INPUTEVENT_KEY_HELP },
{ SDL_SCANCODE_PAGEDOWN, INPUTEVENT_KEY_AMIGA_RIGHT },
{ SDL_SCANCODE_PAGEUP, INPUTEVENT_KEY_NP_RPAREN }, // Map pageup to right parent (as fsuae)
{ SDL_SCANCODE_LEFTBRACKET, INPUTEVENT_KEY_LEFTBRACKET },
@ -503,16 +498,21 @@ static struct uae_input_device_kbr_default keytrans_amiga[] = {
{ SDL_SCANCODE_SEMICOLON, INPUTEVENT_KEY_SEMICOLON },
{ SDL_SCANCODE_APOSTROPHE, INPUTEVENT_KEY_SINGLEQUOTE },
{ SDL_SCANCODE_GRAVE, INPUTEVENT_KEY_BACKQUOTE },
{ SDL_SCANCODE_BACKSLASH, INPUTEVENT_KEY_BACKSLASH },
{ SDL_SCANCODE_COMMA, INPUTEVENT_KEY_COMMA },
{ SDL_SCANCODE_PERIOD, INPUTEVENT_KEY_PERIOD },
{ SDL_SCANCODE_SLASH, INPUTEVENT_KEY_DIV },
{ SDL_SCANCODE_NONUSBACKSLASH, INPUTEVENT_KEY_30 },
//{ SDL_SCANCODE_PAUSE, INPUTEVENT_SPC_FREEZEBUTTON },
{ SDL_SCANCODE_SYSREQ, INPUTEVENT_SPC_SCREENSHOT_CLIPBOARD, 0, INPUTEVENT_SPC_SCREENSHOT, ID_FLAG_QUALIFIER_SPECIAL },
// This is configurable, so let's not hardcode it here
//{SDL_SCANCODE_F12, INPUTEVENT_SPC_ENTERGUI },
{ SDL_SCANCODE_PAUSE, INPUTEVENT_SPC_PAUSE, 0, INPUTEVENT_SPC_SINGLESTEP, ID_FLAG_QUALIFIER_SPECIAL | ID_FLAG_QUALIFIER_CONTROL, INPUTEVENT_SPC_IRQ7, ID_FLAG_QUALIFIER_SPECIAL | ID_FLAG_QUALIFIER_SHIFT, INPUTEVENT_SPC_WARP, ID_FLAG_QUALIFIER_SPECIAL },
//{ SDL_SCANCODE_F12, INPUTEVENT_SPC_ENTERGUI },
{ SDL_SCANCODE_AUDIOSTOP, INPUTEVENT_KEY_CDTV_STOP },
{ SDL_SCANCODE_AUDIOPLAY, INPUTEVENT_KEY_CDTV_PLAYPAUSE },
{ SDL_SCANCODE_AUDIOPREV, INPUTEVENT_KEY_CDTV_PREV },
{ SDL_SCANCODE_AUDIONEXT, INPUTEVENT_KEY_CDTV_NEXT },
{ -1, 0 }
};
@ -587,32 +587,6 @@ static int *kbmaps[] = {
kb_xa1, kb_xa2, kb_arcadia, kb_arcadiaxa, kb_cdtv
};
void keyboard_settrans(void)
{
#ifdef USE_SDL1
char vid_drv_name[32];
// get display type...
SDL_VideoDriverName(vid_drv_name, sizeof vid_drv_name);
if (strcmp(vid_drv_name, "x11") == 0)
{
keyboard_type = KEYCODE_X11;
inputdevice_setkeytranslation(keytrans_x11, kbmaps);
}
else if (strcmp(vid_drv_name, "fbcon") == 0)
{
keyboard_type = KEYCODE_FBCON;
inputdevice_setkeytranslation(keytrans_fbcon, kbmaps);
}
else
{
keyboard_type = KEYCODE_UNK;
inputdevice_setkeytranslation(keytrans, kbmaps);
}
#elif USE_SDL2
inputdevice_setkeytranslation(keytrans, kbmaps);
#endif
}
static bool specialpressed()
{
return (input_getqualifiers() & ID_FLAG_QUALIFIER_SPECIAL) != 0;
@ -659,6 +633,32 @@ static const int np[] = {
SDLK_KP_8, 8, SDLK_KP_9, 9, -1 };
#endif
void keyboard_settrans(void)
{
#ifdef USE_SDL1
char vid_drv_name[32];
// get display type...
SDL_VideoDriverName(vid_drv_name, sizeof vid_drv_name);
if (strcmp(vid_drv_name, "x11") == 0)
{
keyboard_type = KEYCODE_X11;
inputdevice_setkeytranslation(keytrans_x11, kbmaps);
}
else if (strcmp(vid_drv_name, "fbcon") == 0)
{
keyboard_type = KEYCODE_FBCON;
inputdevice_setkeytranslation(keytrans_fbcon, kbmaps);
}
else
{
keyboard_type = KEYCODE_UNK;
inputdevice_setkeytranslation(keytrans, kbmaps);
}
#elif USE_SDL2
inputdevice_setkeytranslation(keytrans, kbmaps);
#endif
}
int target_checkcapslock(const int scancode, int *state)
{
#ifdef USE_SDL1