2014-08-20 07:42:53 +00:00
|
|
|
/*
|
|
|
|
* This file is subject to the terms of the GFX License. If a copy of
|
|
|
|
* the license was not distributed with this file, you can obtain one at:
|
|
|
|
*
|
2018-10-01 15:32:39 +00:00
|
|
|
* http://ugfx.io/license.html
|
2014-08-20 07:42:53 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @file src/ginput/ginput_keyboard.c
|
|
|
|
* @brief GINPUT keyboard code.
|
|
|
|
*/
|
|
|
|
|
2015-02-20 23:23:33 +00:00
|
|
|
// We need to include stdio.h below for MICROCODE_DEBUG. Turn off GFILE_NEED_STDIO just for this file to prevent conflicts
|
|
|
|
#define GFILE_NEED_STDIO_MUST_BE_OFF
|
|
|
|
|
2015-11-21 09:27:08 +00:00
|
|
|
#include "../../gfx.h"
|
2014-08-20 07:42:53 +00:00
|
|
|
|
2015-01-07 03:20:23 +00:00
|
|
|
#if GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD
|
|
|
|
|
2018-02-27 07:44:21 +00:00
|
|
|
#define MICROCODE_DEBUG GFXOFF
|
2015-01-07 03:20:23 +00:00
|
|
|
|
|
|
|
#if MICROCODE_DEBUG
|
|
|
|
#include <stdio.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Get the keyboard driver interface
|
2015-01-21 07:26:24 +00:00
|
|
|
#include "ginput_driver_keyboard.h"
|
|
|
|
#include "ginput_keyboard_microcode.h"
|
2015-01-07 03:20:23 +00:00
|
|
|
|
|
|
|
// The keyboard poll timer
|
|
|
|
static GTIMER_DECL(KeyboardTimer);
|
|
|
|
|
|
|
|
static void SendKeyboardEventToListener(GSourceListener *psl, GKeyboard *k) {
|
|
|
|
GEventKeyboard *pe;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
// If there is no event buffer just mark a missed event
|
|
|
|
if (!(pe = (GEventKeyboard *)geventGetEventBuffer(psl))) {
|
|
|
|
// This listener is missing - save the meta events that have happened
|
|
|
|
psl->srcflags |= GKEYSTATE_MISSED_EVENT;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((psl->listenflags & GLISTEN_KEYRAW)) {
|
|
|
|
pe->type = GEVENT_KEYBOARD;
|
|
|
|
pe->bytecount = k->cntsc;
|
|
|
|
for(i = 0; i < k->cntsc; i++) pe->c[i] = k->sc[i];
|
|
|
|
for(; i < 8; i++) pe->c[i] = 0;
|
|
|
|
pe->keystate = k->keystate | psl->srcflags | GKEYSTATE_RAW;
|
|
|
|
psl->srcflags = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((psl->listenflags & GLISTEN_KEYREPEATSOFF) && (k->keystate & GKEYSTATE_REPEAT))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ((psl->listenflags & GLISTEN_KEYNOSPECIALS) && (k->keystate & GKEYSTATE_SPECIAL))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!(psl->listenflags & GLISTEN_KEYUP) && (k->keystate & GKEYSTATE_KEYUP))
|
|
|
|
k->cntc = 0;
|
|
|
|
|
|
|
|
if (!(psl->listenflags & GLISTEN_KEYTRANSITIONS) && !k->cntc)
|
|
|
|
return;
|
|
|
|
|
|
|
|
pe->type = GEVENT_KEYBOARD;
|
|
|
|
pe->bytecount = k->cntc;
|
|
|
|
for(i = 0; i < k->cntc; i++) pe->c[i] = k->c[i];
|
|
|
|
for(; i < 8; i++) pe->c[i] = 0;
|
|
|
|
pe->keystate = k->keystate | psl->srcflags;
|
|
|
|
psl->srcflags = 0;
|
|
|
|
geventSendEvent(psl);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void SendKeyboardEvent(GKeyboard *k) {
|
|
|
|
GSourceListener *psl;
|
|
|
|
|
|
|
|
// Send to the "All Keyboards" source listeners
|
|
|
|
psl = 0;
|
|
|
|
while ((psl = geventGetSourceListener((GSourceHandle)&KeyboardTimer, psl)))
|
|
|
|
SendKeyboardEventToListener(psl, k);
|
|
|
|
|
|
|
|
// Send to the keyboard specific source listeners
|
|
|
|
psl = 0;
|
|
|
|
while ((psl = geventGetSourceListener((GSourceHandle)k, psl)))
|
|
|
|
SendKeyboardEventToListener(psl, k);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define FLAG_ERROR 0x01
|
|
|
|
#define FLAG_INIT 0x02
|
|
|
|
|
|
|
|
#if GKEYBOARD_LAYOUT_OFF
|
2018-11-03 00:51:23 +00:00
|
|
|
static void microengine(GKeyboard *k, gU8 code, gU8 flags) {
|
2015-01-07 03:20:23 +00:00
|
|
|
if (flags)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Just send an event using the char
|
|
|
|
k->c[0] = k->sc[0] = code;
|
|
|
|
k->cntc = k->cntsc = 1;
|
|
|
|
SendKeyboardEvent(k);
|
|
|
|
k->cntc = k->cntsc = 0;
|
|
|
|
}
|
|
|
|
#else
|
2018-11-03 00:51:23 +00:00
|
|
|
static void microengine(GKeyboard *k, gU8 code, gU8 flags) {
|
|
|
|
const gU8 *pc;
|
|
|
|
const gU8 *nrec;
|
|
|
|
gU8 ver, diff, p1, p2;
|
2015-01-07 03:20:23 +00:00
|
|
|
#if MICROCODE_DEBUG
|
|
|
|
unsigned cnt;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
pc = k->pLayout;
|
|
|
|
if (!pc) {
|
|
|
|
if (flags)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Default is to just send an event using the char
|
|
|
|
k->c[0] = k->sc[0] = code;
|
|
|
|
k->cntc = k->cntsc = 1;
|
|
|
|
SendKeyboardEvent(k);
|
|
|
|
k->cntc = k->cntsc = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check the layout header
|
|
|
|
if (*pc++ != KMC_HEADERSTART || *pc++ != KMC_HEADER_ID1 || *pc++ != KMC_HEADER_ID2)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// We only understand version 1 currently
|
|
|
|
ver = *pc++;
|
|
|
|
if (ver < KMC_HEADER_VER_MIN || ver > KMC_HEADER_VER_MAX)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Setup
|
|
|
|
diff = code;
|
|
|
|
if (k->cntsc >= sizeof(k->sc))
|
|
|
|
flags |= FLAG_ERROR;
|
|
|
|
else
|
|
|
|
k->sc[k->cntsc++] = code;
|
|
|
|
|
|
|
|
#if MICROCODE_DEBUG
|
|
|
|
cnt = 0;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
while(*pc++ == KMC_RECORDSTART) {
|
|
|
|
// Get the record length
|
|
|
|
p1 = *pc++;
|
|
|
|
if (!p1) break;
|
|
|
|
nrec = pc + p1;
|
|
|
|
|
|
|
|
#if MICROCODE_DEBUG
|
|
|
|
cnt++;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
while(pc < nrec) {
|
|
|
|
switch(*pc++) {
|
|
|
|
case KMC_TEST_INIT:
|
|
|
|
if (!(flags & FLAG_INIT)) goto nextrecord;
|
|
|
|
break;
|
|
|
|
case KMC_TEST_ERROR:
|
|
|
|
if (!(flags & FLAG_ERROR)) goto nextrecord;
|
|
|
|
break;
|
|
|
|
case KMC_TEST_CODE:
|
|
|
|
if (flags != 0) goto nextrecord;
|
|
|
|
p1 = *pc++;
|
|
|
|
if (p1 != code) goto nextrecord;
|
|
|
|
diff = 0;
|
|
|
|
break;
|
|
|
|
case KMC_TEST_CODERANGE:
|
|
|
|
if (flags != 0) goto nextrecord;
|
|
|
|
p1 = *pc++;
|
|
|
|
p2 = *pc++;
|
|
|
|
if (code < p1 || code > p2) goto nextrecord;
|
|
|
|
diff = code - p1;
|
|
|
|
break;
|
|
|
|
case KMC_TEST_CODETABLE:
|
|
|
|
if (flags != 0) goto nextrecord;
|
|
|
|
p1 = *pc++;
|
|
|
|
for(p2 = 0; ; p2++, p1--, pc++) {
|
|
|
|
if (!p1) goto nextrecord;
|
|
|
|
if (*pc == code) break;
|
|
|
|
}
|
|
|
|
pc += p1;
|
|
|
|
diff = p2;
|
|
|
|
break;
|
|
|
|
case KMC_TEST_STATEBIT:
|
|
|
|
p1 = *pc++;
|
|
|
|
if ((p1 & KMC_BIT_CLEAR)) {
|
|
|
|
if ((k->keystate & (1 << (p1 & 31)))) goto nextrecord;
|
|
|
|
} else {
|
|
|
|
if (!(k->keystate & (1 << (p1 & 31)))) goto nextrecord;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case KMC_TEST_STATEOR:
|
|
|
|
p1 = *pc++;
|
|
|
|
if ((p1 & KMC_BIT_CLEAR)) {
|
|
|
|
if (!(k->keystate & (1 << (p1 & 31)))) break;
|
|
|
|
} else {
|
|
|
|
if ((k->keystate & (1 << (p1 & 31)))) break;
|
|
|
|
}
|
|
|
|
p2 = *pc++;
|
|
|
|
if ((p2 & KMC_BIT_CLEAR)) {
|
|
|
|
if (!(k->keystate & (1 << (p2 & 31)))) break;
|
|
|
|
} else {
|
|
|
|
if ((k->keystate & (1 << (p2 & 31)))) break;
|
|
|
|
}
|
|
|
|
goto nextrecord;
|
|
|
|
case KMC_TEST_STATEAND:
|
|
|
|
p1 = *pc++;
|
|
|
|
if ((p1 & KMC_BIT_CLEAR)) {
|
|
|
|
if ((k->keystate & (1 << (p1 & 31)))) goto nextrecord;
|
|
|
|
} else {
|
|
|
|
if (!(k->keystate & (1 << (p1 & 31)))) goto nextrecord;
|
|
|
|
}
|
|
|
|
p2 = *pc++;
|
|
|
|
if ((p2 & KMC_BIT_CLEAR)) {
|
|
|
|
if ((k->keystate & (1 << (p2 & 31)))) goto nextrecord;
|
|
|
|
} else {
|
|
|
|
if (!(k->keystate & (1 << (p2 & 31)))) goto nextrecord;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case KMC_TEST_LAYOUTBIT:
|
|
|
|
p1 = *pc++;
|
|
|
|
if ((p1 & KMC_BIT_CLEAR)) {
|
|
|
|
if ((k->laystate & (1 << (p1 & 15)))) goto nextrecord;
|
|
|
|
} else {
|
|
|
|
if (!(k->laystate & (1 << (p1 & 15)))) goto nextrecord;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case KMC_TEST_LAYOUTOR:
|
|
|
|
p1 = *pc++;
|
|
|
|
if ((p1 & KMC_BIT_CLEAR)) {
|
|
|
|
if (!(k->laystate & (1 << (p1 & 15)))) break;
|
|
|
|
} else {
|
|
|
|
if ((k->laystate & (1 << (p1 & 15)))) break;
|
|
|
|
}
|
|
|
|
p2 = *pc++;
|
|
|
|
if ((p2 & KMC_BIT_CLEAR)) {
|
|
|
|
if (!(k->laystate & (1 << (p2 & 15)))) break;
|
|
|
|
} else {
|
|
|
|
if ((k->laystate & (1 << (p2 & 15)))) break;
|
|
|
|
}
|
|
|
|
goto nextrecord;
|
|
|
|
case KMC_TEST_LAYOUTAND:
|
|
|
|
p1 = *pc++;
|
|
|
|
if ((p1 & KMC_BIT_CLEAR)) {
|
|
|
|
if ((k->laystate & (1 << (p1 & 15)))) goto nextrecord;
|
|
|
|
} else {
|
|
|
|
if (!(k->laystate & (1 << (p1 & 15)))) goto nextrecord;
|
|
|
|
}
|
|
|
|
p2 = *pc++;
|
|
|
|
if ((p2 & KMC_BIT_CLEAR)) {
|
|
|
|
if ((k->laystate & (1 << (p2 & 15)))) goto nextrecord;
|
|
|
|
} else {
|
|
|
|
if (!(k->laystate & (1 << (p2 & 15)))) goto nextrecord;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case KMC_TEST_CODEBIT:
|
|
|
|
if (flags != 0) goto nextrecord;
|
|
|
|
p1 = *pc++;
|
|
|
|
if ((p1 & KMC_BIT_CLEAR)) {
|
|
|
|
if ((code & (1 << (p1 & 7)))) goto nextrecord;
|
|
|
|
} else {
|
|
|
|
if (!(code & (1 << (p1 & 7)))) goto nextrecord;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case KMC_TEST_CODEOR:
|
|
|
|
if (flags != 0) goto nextrecord;
|
|
|
|
p1 = *pc++;
|
|
|
|
if ((p1 & KMC_BIT_CLEAR)) {
|
|
|
|
if (!(code & (1 << (p1 & 7)))) break;
|
|
|
|
} else {
|
|
|
|
if ((code & (1 << (p1 & 7)))) break;
|
|
|
|
}
|
|
|
|
p2 = *pc++;
|
|
|
|
if ((p2 & KMC_BIT_CLEAR)) {
|
|
|
|
if (!(code & (1 << (p2 & 7)))) break;
|
|
|
|
} else {
|
|
|
|
if ((code & (1 << (p2 & 7)))) break;
|
|
|
|
}
|
|
|
|
goto nextrecord;
|
|
|
|
case KMC_TEST_CODEAND:
|
|
|
|
if (flags != 0) goto nextrecord;
|
|
|
|
p1 = *pc++;
|
|
|
|
if ((p1 & KMC_BIT_CLEAR)) {
|
|
|
|
if ((code & (1 << (p1 & 7)))) goto nextrecord;
|
|
|
|
} else {
|
|
|
|
if (!(code & (1 << (p1 & 7)))) goto nextrecord;
|
|
|
|
}
|
|
|
|
p2 = *pc++;
|
|
|
|
if ((p2 & KMC_BIT_CLEAR)) {
|
|
|
|
if ((code & (1 << (p2 & 7)))) goto nextrecord;
|
|
|
|
} else {
|
|
|
|
if (!(code & (1 << (p2 & 7)))) goto nextrecord;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case KMC_TEST_LASTCODE:
|
|
|
|
p1 = *pc++;
|
|
|
|
if (k->cntsc < 2) goto nextrecord;
|
|
|
|
if (p1 != k->sc[k->cntsc-2]) goto nextrecord;
|
|
|
|
break;
|
|
|
|
case KMC_TEST_SHIFT:
|
|
|
|
if ((k->keystate & (GKEYSTATE_SHIFT_L|GKEYSTATE_SHIFT_R))) break;
|
|
|
|
goto nextrecord;
|
|
|
|
case KMC_TEST_NOSHIFT:
|
|
|
|
if (!(k->keystate & (GKEYSTATE_SHIFT_L|GKEYSTATE_SHIFT_R))) break;
|
|
|
|
goto nextrecord;
|
|
|
|
case KMC_TEST_CTRL:
|
|
|
|
if ((k->keystate & (GKEYSTATE_CTRL_L|GKEYSTATE_CTRL_R))) break;
|
|
|
|
goto nextrecord;
|
|
|
|
case KMC_TEST_NOCTRL:
|
|
|
|
if (!(k->keystate & (GKEYSTATE_CTRL_L|GKEYSTATE_CTRL_R))) break;
|
|
|
|
goto nextrecord;
|
|
|
|
case KMC_TEST_ALT:
|
|
|
|
if ((k->keystate & (GKEYSTATE_ALT_L|GKEYSTATE_ALT_R))) break;
|
|
|
|
goto nextrecord;
|
|
|
|
case KMC_TEST_NOALT:
|
|
|
|
if (!(k->keystate & (GKEYSTATE_ALT_L|GKEYSTATE_ALT_R))) break;
|
|
|
|
goto nextrecord;
|
|
|
|
case KMC_TEST_CAPS:
|
|
|
|
if ((k->keystate & GKEYSTATE_CAPSLOCK)) {
|
|
|
|
if (!(k->keystate & (GKEYSTATE_SHIFT_L|GKEYSTATE_SHIFT_R))) break;
|
|
|
|
} else {
|
|
|
|
if ((k->keystate & (GKEYSTATE_SHIFT_L|GKEYSTATE_SHIFT_R))) break;
|
|
|
|
}
|
|
|
|
goto nextrecord;
|
|
|
|
case KMC_TEST_NOCAPS:
|
|
|
|
if ((k->keystate & GKEYSTATE_CAPSLOCK)) {
|
|
|
|
if ((k->keystate & (GKEYSTATE_SHIFT_L|GKEYSTATE_SHIFT_R))) break;
|
|
|
|
} else {
|
|
|
|
if (!(k->keystate & (GKEYSTATE_SHIFT_L|GKEYSTATE_SHIFT_R))) break;
|
|
|
|
}
|
|
|
|
goto nextrecord;
|
|
|
|
case KMC_TEST_NUMLOCK:
|
|
|
|
if ((k->keystate & GKEYSTATE_NUMLOCK)) break;
|
|
|
|
goto nextrecord;
|
|
|
|
case KMC_TEST_NONUMLOCK:
|
|
|
|
if (!(k->keystate & GKEYSTATE_NUMLOCK)) break;
|
|
|
|
goto nextrecord;
|
|
|
|
|
|
|
|
case KMC_ACT_STOP:
|
|
|
|
#if MICROCODE_DEBUG
|
|
|
|
fprintf(stderr, "Executed STOP: Records=%2u Flags=0x%02X Code=0x%02X\n", cnt, flags, code); fflush(stderr);
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
case KMC_ACT_DONE:
|
|
|
|
SendKeyboardEvent(k);
|
|
|
|
k->cntc = k->cntsc = 0;
|
|
|
|
k->keystate &= ~(GKEYSTATE_KEYUP|GKEYSTATE_SPECIAL);
|
|
|
|
#if MICROCODE_DEBUG
|
|
|
|
fprintf(stderr, "Executed DONE: Records=%2u Flags=0x%02X Code=0x%02X\n", cnt, flags, code); fflush(stderr);
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
case KMC_ACT_RESET:
|
|
|
|
k->cntc = k->cntsc = 0;
|
|
|
|
k->keystate &= ~(GKEYSTATE_KEYUP|GKEYSTATE_SPECIAL);
|
|
|
|
break;
|
|
|
|
case KMC_ACT_STATEBIT:
|
|
|
|
p1 = *pc++;
|
|
|
|
if ((p1 & KMC_BIT_INVERT))
|
|
|
|
k->keystate ^= (1 << (p1 & 31));
|
|
|
|
else if ((p1 & KMC_BIT_CLEAR))
|
|
|
|
k->keystate &= ~(1 << (p1 & 31));
|
|
|
|
else
|
|
|
|
k->keystate |= (1 << (p1 & 31));
|
|
|
|
break;
|
|
|
|
case KMC_ACT_LAYOUTBIT:
|
|
|
|
p1 = *pc++;
|
|
|
|
if ((p1 & KMC_BIT_INVERT))
|
|
|
|
k->laystate ^= (1 << (p1 & 15));
|
|
|
|
else if ((p1 & KMC_BIT_CLEAR))
|
|
|
|
k->laystate &= ~(1 << (p1 & 15));
|
|
|
|
else
|
|
|
|
k->laystate |= (1 << (p1 & 15));
|
|
|
|
break;
|
|
|
|
case KMC_ACT_CODEBIT:
|
|
|
|
p1 = *pc++;
|
|
|
|
if ((p1 & KMC_BIT_INVERT))
|
|
|
|
code ^= (1 << (p1 & 7));
|
|
|
|
else if ((p1 & KMC_BIT_CLEAR))
|
|
|
|
code &= ~(1 << (p1 & 7));
|
|
|
|
else
|
|
|
|
code |= (1 << (p1 & 7));
|
|
|
|
break;
|
|
|
|
case KMC_ACT_CHAR:
|
|
|
|
if (k->cntc >= sizeof(k->c)) goto codeerror;
|
|
|
|
k->c[k->cntc++] = *pc++;
|
|
|
|
break;
|
|
|
|
case KMC_ACT_CHARCODE:
|
|
|
|
if (k->cntc >= sizeof(k->c)) goto codeerror;
|
|
|
|
k->c[k->cntc++] = code;
|
|
|
|
break;
|
|
|
|
case KMC_ACT_CHARRANGE:
|
|
|
|
if (k->cntc >= sizeof(k->c)) goto codeerror;
|
|
|
|
k->c[k->cntc++] = diff + *pc++;
|
|
|
|
break;
|
|
|
|
case KMC_ACT_CHARTABLE:
|
|
|
|
p1 = *pc++;
|
|
|
|
if (diff < p1) {
|
|
|
|
if (k->cntc >= sizeof(k->c)) goto codeerror;
|
|
|
|
k->c[k->cntc++] = pc[diff];
|
|
|
|
}
|
|
|
|
pc += p1;
|
|
|
|
break;
|
|
|
|
case KMC_ACT_CLEAR:
|
|
|
|
k->cntc = 0;
|
|
|
|
break;
|
|
|
|
case KMC_ACT_CHARADD:
|
|
|
|
p1 = *pc++;
|
|
|
|
if (!k->cntc)
|
|
|
|
k->c[k->cntc++] = 0;
|
|
|
|
k->c[k->cntc-1] = k->c[k->cntc-1] * p1 + diff;
|
|
|
|
break;
|
|
|
|
case KMC_ACT_DATA:
|
|
|
|
p1 = *pc++;
|
|
|
|
if (gkvmt(k)->putdata)
|
|
|
|
gkvmt(k)->putdata(k, p1);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
codeerror:
|
|
|
|
#if MICROCODE_DEBUG
|
|
|
|
fprintf(stderr, "Executed ERROR: Records=%2u Flags=0x%02X Code=0x%02X\n", cnt, flags, code); cnt = 0; fflush(stderr);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Prevent recursion
|
|
|
|
if (flags & FLAG_ERROR)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Process as an error
|
|
|
|
flags |= FLAG_ERROR;
|
|
|
|
nrec = k->pLayout + 4; // Jump back to the end of the header to process the error
|
|
|
|
goto nextrecord; // Nothing left to do here.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nextrecord:
|
|
|
|
pc = nrec;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if MICROCODE_DEBUG
|
|
|
|
fprintf(stderr, "Executed END: Records=%2u Flags=0x%02X Code=0x%02X\n", cnt, flags, code); fflush(stderr);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static void KeyboardPoll(void *param) {
|
|
|
|
GKeyboard * k;
|
2018-11-03 00:51:23 +00:00
|
|
|
gU8 scancodes[8];
|
2015-01-07 03:20:23 +00:00
|
|
|
int sz, i;
|
|
|
|
(void) param;
|
|
|
|
|
|
|
|
for(k = (GKeyboard *)gdriverGetNext(GDRIVER_TYPE_KEYBOARD, 0); k; k = (GKeyboard *)gdriverGetNext(GDRIVER_TYPE_KEYBOARD, (GDriver *)k)) {
|
|
|
|
if (!(gkvmt(k)->d.flags & GKEYBOARD_VFLG_NOPOLL) || (k->flags & GKEYBOARD_FLG_NEEDREAD)) {
|
|
|
|
k->flags &= ~GKEYBOARD_FLG_NEEDREAD;
|
|
|
|
sz = gkvmt(k)->getdata(k, scancodes, sizeof(scancodes));
|
|
|
|
for(i = 0; i < sz; i++)
|
|
|
|
microengine(k, scancodes[i], 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void _gkeyboardInit(void) {
|
|
|
|
// GINPUT_KEYBOARD_DRIVER_LIST is defined - create each driver instance
|
|
|
|
#if defined(GINPUT_KEYBOARD_DRIVER_LIST)
|
|
|
|
{
|
|
|
|
int i;
|
2015-01-27 03:42:11 +00:00
|
|
|
typedef const GKeyboardVMT const GKEYBOARDVMTLIST[1];
|
2015-01-07 03:20:23 +00:00
|
|
|
|
2015-01-27 03:42:11 +00:00
|
|
|
extern GKEYBOARDVMTLIST GINPUT_KEYBOARD_DRIVER_LIST;
|
|
|
|
static const GKeyboardVMT * const dclist[] = {GINPUT_KEYBOARD_DRIVER_LIST};
|
2015-01-07 03:20:23 +00:00
|
|
|
|
|
|
|
for(i = 0; i < sizeof(dclist)/sizeof(dclist[0]); i++) {
|
2017-07-01 18:25:01 +00:00
|
|
|
if (!(dclist[i]->d.flags & GKEYBOARD_VFLG_DYNAMICONLY))
|
2015-01-07 03:20:23 +00:00
|
|
|
gdriverRegister(&dclist[i]->d, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// One and only one mouse
|
|
|
|
#else
|
|
|
|
{
|
2015-01-27 03:42:11 +00:00
|
|
|
extern const GKeyboardVMT const GKEYBOARDVMT_OnlyOne[1];
|
2015-01-07 03:20:23 +00:00
|
|
|
|
2017-07-01 18:25:01 +00:00
|
|
|
if (!(GKEYBOARDVMT_OnlyOne->d.flags & GKEYBOARD_VFLG_DYNAMICONLY))
|
|
|
|
gdriverRegister(&GKEYBOARDVMT_OnlyOne->d, 0);
|
2015-01-07 03:20:23 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void _gkeyboardDeinit(void) {
|
|
|
|
gtimerDeinit(&KeyboardTimer);
|
|
|
|
}
|
|
|
|
|
2018-06-23 03:02:07 +00:00
|
|
|
gBool _gkeyboardInitDriver(GDriver *g, void *param, unsigned driverinstance, unsigned systeminstance) {
|
2017-07-01 18:25:01 +00:00
|
|
|
#define k ((GKeyboard *)g)
|
2015-01-07 03:20:23 +00:00
|
|
|
(void) param;
|
2017-07-01 18:25:01 +00:00
|
|
|
(void) systeminstance;
|
2015-01-07 03:20:23 +00:00
|
|
|
|
|
|
|
// The initial keyboard layout comes from the VMT
|
|
|
|
k->pLayout = gkvmt(k)->defLayout;
|
|
|
|
|
|
|
|
// Init the mouse
|
2017-07-01 18:25:01 +00:00
|
|
|
if (!gkvmt(k)->init((GKeyboard *)g, driverinstance))
|
2018-06-23 03:02:07 +00:00
|
|
|
return gFalse;
|
2015-01-07 03:20:23 +00:00
|
|
|
|
|
|
|
// Ensure the Poll timer is started
|
|
|
|
if (!gtimerIsActive(&KeyboardTimer))
|
2018-06-23 03:02:07 +00:00
|
|
|
gtimerStart(&KeyboardTimer, KeyboardPoll, 0, gTrue, GINPUT_KEYBOARD_POLL_PERIOD);
|
2015-01-07 03:20:23 +00:00
|
|
|
|
2018-06-23 03:02:07 +00:00
|
|
|
return gTrue;
|
2015-01-07 03:20:23 +00:00
|
|
|
|
2017-07-01 18:25:01 +00:00
|
|
|
#undef k
|
2015-01-07 03:20:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void _gkeyboardPostInitDriver(GDriver *g) {
|
2017-07-01 18:25:01 +00:00
|
|
|
#define k ((GKeyboard *)g)
|
2015-01-07 03:20:23 +00:00
|
|
|
|
|
|
|
// Run the init sequence from the layout microcode.
|
|
|
|
microengine(k, 0, FLAG_INIT);
|
|
|
|
|
2017-07-01 18:25:01 +00:00
|
|
|
#undef k
|
2015-01-07 03:20:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void _gkeyboardDeInitDriver(GDriver *g) {
|
2017-07-01 18:25:01 +00:00
|
|
|
(void) g;
|
2015-01-07 03:20:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GSourceHandle ginputGetKeyboard(unsigned instance) {
|
|
|
|
if (instance == GKEYBOARD_ALL_INSTANCES)
|
|
|
|
return (GSourceHandle)&KeyboardTimer;
|
2017-07-01 18:25:01 +00:00
|
|
|
return (GSourceHandle)gdriverGetInstance(GDRIVER_TYPE_KEYBOARD, instance);
|
2015-01-07 03:20:23 +00:00
|
|
|
}
|
|
|
|
|
2018-06-23 03:02:07 +00:00
|
|
|
gBool ginputGetKeyboardStatus(unsigned instance, GEventKeyboard *pe) {
|
2015-01-07 03:20:23 +00:00
|
|
|
GKeyboard *k;
|
|
|
|
|
|
|
|
// Win32 threads don't seem to recognise priority and/or pre-emption
|
|
|
|
// so we add a sleep here to prevent 100% polled applications from locking up.
|
|
|
|
gfxSleepMilliseconds(1);
|
|
|
|
|
|
|
|
if (!(k = (GKeyboard *)gdriverGetInstance(GDRIVER_TYPE_KEYBOARD, instance)))
|
2018-06-23 03:02:07 +00:00
|
|
|
return gFalse;
|
2015-01-07 03:20:23 +00:00
|
|
|
|
|
|
|
pe->type = GEVENT_KEYBOARD;
|
|
|
|
// TODO
|
2018-06-23 03:02:07 +00:00
|
|
|
return gTrue;
|
2015-01-07 03:20:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#if !GKEYBOARD_LAYOUT_OFF
|
2018-06-23 03:02:07 +00:00
|
|
|
gBool ginputSetKeyboardLayout(unsigned instance, const void *pLayout) {
|
2015-01-07 03:20:23 +00:00
|
|
|
GKeyboard *k;
|
|
|
|
|
|
|
|
if (!(k = (GKeyboard *)gdriverGetInstance(GDRIVER_TYPE_KEYBOARD, instance)))
|
2018-06-23 03:02:07 +00:00
|
|
|
return gFalse;
|
2015-01-07 03:20:23 +00:00
|
|
|
|
|
|
|
if (pLayout)
|
|
|
|
k->pLayout = pLayout;
|
|
|
|
else
|
|
|
|
k->pLayout = gkvmt(k)->defLayout;
|
|
|
|
|
2018-06-23 03:02:07 +00:00
|
|
|
return gTrue;
|
2015-01-07 03:20:23 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Wake up the keyboard driver from an interrupt service routine (there may be new readings available) */
|
|
|
|
void _gkeyboardWakeup(GKeyboard *k) {
|
|
|
|
if (k)
|
|
|
|
k->flags |= GKEYBOARD_FLG_NEEDREAD;
|
|
|
|
gtimerJab(&KeyboardTimer);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Wake up the keyboard driver from an interrupt service routine (there may be new readings available) */
|
|
|
|
void _gkeyboardWakeupI(GKeyboard *k) {
|
|
|
|
if (k)
|
|
|
|
k->flags |= GKEYBOARD_FLG_NEEDREAD;
|
|
|
|
gtimerJabI(&KeyboardTimer);
|
|
|
|
}
|
|
|
|
|
2014-08-20 07:42:53 +00:00
|
|
|
#endif /* GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD */
|