mirror of
https://github.com/LIV2/WinUAE.git
synced 2025-12-06 00:12:52 +00:00
378 lines
6.9 KiB
C++
378 lines
6.9 KiB
C++
/*
|
|
* UAE - The Un*x Amiga Emulator
|
|
*
|
|
* Keyboard buffer. Not really needed for X, but for SVGAlib and possibly
|
|
* Mac and DOS ports.
|
|
*
|
|
* Note: it's possible to have two threads in UAE, one reading keystrokes
|
|
* and the other one writing them. Despite this, no synchronization effort
|
|
* is needed. This code should be perfectly thread safe. At least if you
|
|
* assume that integer store instructions are atomic.
|
|
*
|
|
* Copyright 1995, 1997 Bernd Schmidt
|
|
*/
|
|
|
|
#include "sysconfig.h"
|
|
#include "sysdeps.h"
|
|
#include <assert.h>
|
|
|
|
#include "options.h"
|
|
#include "keybuf.h"
|
|
#include "keyboard.h"
|
|
#include "inputdevice.h"
|
|
#include "custom.h"
|
|
#include "savestate.h"
|
|
|
|
int key_swap_hack2 = false;
|
|
|
|
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;
|
|
static bool ignore_next_release;
|
|
static int delayed_released_code;
|
|
static int delayed_released_time;
|
|
|
|
|
|
struct kbtab
|
|
{
|
|
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, false);
|
|
if (q & 0x7f) {
|
|
q = (q << 1) | (q >> 7);
|
|
record_key(q, false);
|
|
}
|
|
} else {
|
|
if (q & 0x7f) {
|
|
q = (q << 1) | (q >> 7);
|
|
record_key(q, false);
|
|
}
|
|
record_key(v, false);
|
|
}
|
|
}
|
|
|
|
// delay injection, some programs don't like too fast key events
|
|
static bool can_inject(void)
|
|
{
|
|
static int ovpos, cnt;
|
|
|
|
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 = NULL;
|
|
keyinject_offset =0;
|
|
}
|
|
keytoscancode(key, false);
|
|
}
|
|
}
|
|
|
|
assert (kpb_first != kpb_last);
|
|
|
|
key = keybuf[kpb_last];
|
|
if (++kpb_last == KEYBUF_SIZE)
|
|
kpb_last = 0;
|
|
|
|
// send release immediately in warp mode if not qualifier key
|
|
delayed_released_time = 0;
|
|
if (currprefs.turbo_emulation && !(key & 0x01) && (key >> 1) < 0x60) {
|
|
if (!keys_available()) {
|
|
delayed_released_code = key | 0x01;
|
|
delayed_released_time = 5;
|
|
}
|
|
}
|
|
|
|
//write_log (_T("%02x:%d\n"), key >> 1, key & 1);
|
|
return key;
|
|
}
|
|
|
|
void keybuf_vsync(void)
|
|
{
|
|
if (delayed_released_time > 0) {
|
|
delayed_released_time--;
|
|
if (delayed_released_time == 0) {
|
|
record_key(delayed_released_code, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
int record_key(int kc, bool direct)
|
|
{
|
|
if (pause_emulation)
|
|
return 0;
|
|
return record_key_direct(kc, direct);
|
|
}
|
|
|
|
static void keyswap(int *kcdp, int *kcp, uae_u8 k1, uae_u8 k2)
|
|
{
|
|
int kcd = *kcdp;
|
|
int kc = *kcp;
|
|
if ((kcd & 0x7f) == k1) {
|
|
kcd = k2 | (kcd & 0x80);
|
|
kc = (kcd << 1) | (kcd >> 7);
|
|
} else if ((kcd & 0x7f) == k2) {
|
|
kcd = k1 | (kcd & 0x80);
|
|
kc = (kcd << 1) | (kcd >> 7);
|
|
}
|
|
*kcdp = kcd;
|
|
*kcp = kc;
|
|
}
|
|
|
|
int record_key_direct(int kc, bool direct)
|
|
{
|
|
int kpb_next = kpb_first + 1;
|
|
int kcd = (kc << 7) | (kc >> 1);
|
|
|
|
if (currprefs.cs_compatible == CP_DRACO) {
|
|
if (currprefs.cpuboard_settings & 0x10) {
|
|
inputdevice_draco_key(kc);
|
|
}
|
|
if (!currprefs.keyboard_connected) {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if (!direct) {
|
|
if (key_swap_hack2) {
|
|
// $0D <> $0C
|
|
keyswap(&kcd, &kc, 0x0d, 0x0c);
|
|
}
|
|
if (key_swap_hack == 2) {
|
|
// $2B <> $0D
|
|
keyswap(&kcd, &kc, 0x2b, 0x0d);
|
|
}
|
|
|
|
if (ignore_next_release) {
|
|
ignore_next_release = false;
|
|
if (kcd & 0x80) {
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
//write_log (_T("got kc %02X\n"), kcd & 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)
|
|
{
|
|
kpb_first = kpb_last = 0;
|
|
keyinject_offset = 0;
|
|
xfree(keyinject);
|
|
keyinject = NULL;
|
|
delayed_released_code = -1;
|
|
delayed_released_time = 0;
|
|
inputdevice_updateconfig (&changed_prefs, &currprefs);
|
|
}
|
|
|
|
void keybuf_ignore_next_release(void)
|
|
{
|
|
ignore_next_release = true;
|
|
}
|
|
|
|
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;
|
|
}
|