New keyboard driver interface with international keyboard support.
parent
128a3b972c
commit
87cca4f7a5
|
@ -230,6 +230,10 @@
|
|||
// #define GINPUT_TOUCH_USER_CALIBRATION_SAVE FALSE
|
||||
// #define GMOUSE_DRIVER_LIST GMOUSEVMT_Win32, GMOUSEVMT_Win32
|
||||
//#define GINPUT_NEED_KEYBOARD FALSE
|
||||
// #define GINPUT_KEYBOARD_POLL_PERIOD 200
|
||||
// #define GKEYBOARD_DRIVER_LIST GKEYBOARDVMT_Win32, GKEYBOARDVMT_Win32
|
||||
// #define GKEYBOARD_LAYOUT_OFF FALSE
|
||||
// #define GKEYBOARD_LAYOUT_SCANCODE2_US FALSE
|
||||
//#define GINPUT_NEED_TOGGLE FALSE
|
||||
//#define GINPUT_NEED_DIAL FALSE
|
||||
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* 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:
|
||||
*
|
||||
* http://ugfx.org/license.html
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file src/ginput/driver_keyboard.h
|
||||
* @brief GINPUT LLD header file for keyboard drivers.
|
||||
*
|
||||
* @defgroup Keyboard Keyboard
|
||||
* @ingroup GINPUT
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _LLD_GINPUT_KEYBOARD_H
|
||||
#define _LLD_GINPUT_KEYBOARD_H
|
||||
|
||||
#if GINPUT_NEED_KEYBOARD //|| defined(__DOXYGEN__)
|
||||
|
||||
// Include the GDRIVER infrastructure
|
||||
#include "src/gdriver/sys_defs.h"
|
||||
|
||||
typedef struct GKeyboard {
|
||||
GDriver d; // The driver overheads and vmt
|
||||
uint16_t cntc; // The byte count in c
|
||||
uint16_t cntsc; // The byte count in sc
|
||||
char c[8]; // The utf8 code for the current key
|
||||
char sc[8]; // The scancode for the current key
|
||||
uint32_t keystate; // The keyboard state.
|
||||
uint16_t flags;
|
||||
#define GKEYBOARD_FLG_NEEDREAD 0x0001
|
||||
uint16_t laystate; // The layout state.
|
||||
const uint8_t * pLayout; // The current keyboard layout
|
||||
// Other driver specific fields may follow.
|
||||
} GKeyboard;
|
||||
|
||||
typedef struct GKeyboardVMT {
|
||||
GDriverVMT d; // Device flags are part of the general vmt
|
||||
#define GKEYBOARD_VFLG_NOPOLL 0x0001 // Do not poll this device - it is purely interrupt driven
|
||||
#define GKEYBOARD_VFLG_DYNAMICONLY 0x8000 // This keyboard driver should not be statically initialized eg Win32
|
||||
const uint8_t * defLayout; // The default keyboard layout
|
||||
bool_t (*init)(GKeyboard *m, unsigned driverinstance); // Required
|
||||
void (*deinit)(GKeyboard *m); // Optional
|
||||
int (*getdata)(GKeyboard *k, uint8_t *pch, int sz); // Required. Get zero or more scancode bytes. Returns the number of scancode bytes returns
|
||||
void (*putdata)(GKeyboard *k, char ch); // Optional. Send a single byte to the keyboard.
|
||||
} GKeyboardVMT;
|
||||
|
||||
#define gkvmt(m) ((const GKeyboardVMT const *)((m)->d.vmt))
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
// If we are not using multiple keyboards then hard-code the VMT name
|
||||
#if !defined(GINPUT_KEYBOARD_DRIVER_LIST)
|
||||
#undef GKEYBOARD_DRIVER_VMT
|
||||
#define GKEYBOARD_DRIVER_VMT GKEYBOARDVMT_OnlyOne
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/**
|
||||
* @brief Initialize a keyboard driver
|
||||
*
|
||||
* @param[in] g The keyboard driver
|
||||
* @param[in] param Unused by keyboard
|
||||
* @param[in] driverinstance The driver instance ToDo: Add some more details
|
||||
* @param[in] systeminstance The mouse instance ToDo: Add some more details
|
||||
*
|
||||
* @return TRUE on success, FALSE otherwise
|
||||
* @note This routine is provided by the high level code for
|
||||
* use in the driver VMT's GMouseVMT.d structure.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
bool_t _gkeyboardInitDriver(GDriver *g, void *param, unsigned driverinstance, unsigned systeminstance);
|
||||
|
||||
/**
|
||||
* @brief Routine that is called after initialization
|
||||
*
|
||||
* @param[in] g The keyboard driver
|
||||
* @note This routine is provided by the high level code for
|
||||
* use in the driver VMT's GKeyboardVMT.d structure.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void _gkeyboardPostInitDriver(GDriver *g);
|
||||
|
||||
/**
|
||||
* @brief Deinitialize a keyboard driver
|
||||
*
|
||||
* @param[in] g The kerboard driver
|
||||
* @note This routine is provided by the high level code for
|
||||
* use in the driver VMT's GKeyboardVMT.d structure.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void _gkeyboardDeInitDriver(GDriver *g);
|
||||
|
||||
/**
|
||||
* @brief Wakeup the high level code so that it attempts another read
|
||||
*
|
||||
* @note This routine is provided to low level drivers by the high level code
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void _gkeyboardWakeup(GKeyboard *k);
|
||||
|
||||
/**
|
||||
* @brief Wakeup the high level code so that it attempts another read
|
||||
*
|
||||
* @note This routine is provided to low level drivers by the high level code
|
||||
*
|
||||
* @iclass
|
||||
* @notapi
|
||||
*/
|
||||
void _gkeyboardWakeupI(GKeyboard *k);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINPUT_NEED_KEYBOARD */
|
||||
|
||||
#endif /* _LLD_GINPUT_KEYBOARD_H */
|
||||
/** @} */
|
|
@ -20,12 +20,19 @@
|
|||
extern void _gmouseInit(void);
|
||||
extern void _gmouseDeinit(void);
|
||||
#endif
|
||||
#if GINPUT_NEED_KEYBOARD
|
||||
extern void _gkeyboardInit(void);
|
||||
extern void _gkeyboardDeinit(void);
|
||||
#endif
|
||||
|
||||
void _ginputInit(void)
|
||||
{
|
||||
#if GINPUT_NEED_MOUSE
|
||||
_gmouseInit();
|
||||
#endif
|
||||
#if GINPUT_NEED_KEYBOARD
|
||||
_gkeyboardInit();
|
||||
#endif
|
||||
/**
|
||||
* This should really call an init routine for each ginput sub-system.
|
||||
* Maybe we'll do this later.
|
||||
|
@ -34,6 +41,9 @@ void _ginputInit(void)
|
|||
|
||||
void _ginputDeinit(void)
|
||||
{
|
||||
#if GINPUT_NEED_KEYBOARD
|
||||
_gkeyboardDeinit();
|
||||
#endif
|
||||
#if GINPUT_NEED_MOUSE
|
||||
_gmouseDeinit();
|
||||
#endif
|
||||
|
|
|
@ -8,16 +8,575 @@
|
|||
/**
|
||||
* @file src/ginput/ginput_keyboard.c
|
||||
* @brief GINPUT keyboard code.
|
||||
*
|
||||
* @defgroup Keyboard Keyboard
|
||||
* @ingroup GINPUT
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "gfx.h"
|
||||
|
||||
#if (GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD) || defined(__DOXYGEN__)
|
||||
#error "GINPUT: GINPUT_NEED_KEYBOARD - Not Implemented Yet"
|
||||
#if GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD
|
||||
|
||||
#define MICROCODE_DEBUG FALSE
|
||||
|
||||
#if MICROCODE_DEBUG
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#if GKEYBOARD_LAYOUT_OFF
|
||||
#error "Win32: The Win32 keyboard driver requires the layout engine. Please set GKEYBOARD_LAYOUT_OFF to FALSE."
|
||||
#endif
|
||||
|
||||
// Get the keyboard driver interface
|
||||
#include "driver_keyboard.h"
|
||||
#include "keyboard_microcode.h"
|
||||
|
||||
// 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
|
||||
static void microengine(GKeyboard *k, uint8_t code, uint8_t flags) {
|
||||
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
|
||||
static void microengine(GKeyboard *k, uint8_t code, uint8_t flags) {
|
||||
const uint8_t *pc;
|
||||
const uint8_t *nrec;
|
||||
uint8_t ver, diff, p1, p2;
|
||||
#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;
|
||||
uint8_t scancodes[8];
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef const GKeyboardVMT const GKEYBOARDVMTLIST[];
|
||||
|
||||
void _gkeyboardInit(void) {
|
||||
// GINPUT_KEYBOARD_DRIVER_LIST is defined - create each driver instance
|
||||
#if defined(GINPUT_KEYBOARD_DRIVER_LIST)
|
||||
{
|
||||
int i;
|
||||
|
||||
extern GKEYBOARDVMTLIST GINPUT_KEYBOARD_DRIVER_LIST;
|
||||
static GKEYBOARDVMTLIST dclist[] = {GINPUT_KEYBOARD_DRIVER_LIST};
|
||||
|
||||
for(i = 0; i < sizeof(dclist)/sizeof(dclist[0]); i++) {
|
||||
if (!(dclist[i]->d.flags & GKEYBOARD_VFLG_DYNAMICONLY))
|
||||
gdriverRegister(&dclist[i]->d, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// One and only one mouse
|
||||
#else
|
||||
{
|
||||
extern GKEYBOARDVMTLIST GKEYBOARDVMT_OnlyOne;
|
||||
|
||||
if (!(GKEYBOARDVMT_OnlyOne->d.flags & GKEYBOARD_VFLG_DYNAMICONLY))
|
||||
gdriverRegister(&GKEYBOARDVMT_OnlyOne->d, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void _gkeyboardDeinit(void) {
|
||||
gtimerDeinit(&KeyboardTimer);
|
||||
}
|
||||
|
||||
bool_t _gkeyboardInitDriver(GDriver *g, void *param, unsigned driverinstance, unsigned systeminstance) {
|
||||
#define k ((GKeyboard *)g)
|
||||
(void) param;
|
||||
(void) systeminstance;
|
||||
|
||||
// The initial keyboard layout comes from the VMT
|
||||
k->pLayout = gkvmt(k)->defLayout;
|
||||
|
||||
// Init the mouse
|
||||
if (!gkvmt(k)->init((GKeyboard *)g, driverinstance))
|
||||
return FALSE;
|
||||
|
||||
// Ensure the Poll timer is started
|
||||
if (!gtimerIsActive(&KeyboardTimer))
|
||||
gtimerStart(&KeyboardTimer, KeyboardPoll, 0, TRUE, GINPUT_KEYBOARD_POLL_PERIOD);
|
||||
|
||||
return TRUE;
|
||||
|
||||
#undef k
|
||||
}
|
||||
|
||||
void _gkeyboardPostInitDriver(GDriver *g) {
|
||||
#define k ((GKeyboard *)g)
|
||||
|
||||
// Run the init sequence from the layout microcode.
|
||||
microengine(k, 0, FLAG_INIT);
|
||||
|
||||
#undef k
|
||||
}
|
||||
|
||||
void _gkeyboardDeInitDriver(GDriver *g) {
|
||||
(void) g;
|
||||
}
|
||||
|
||||
GSourceHandle ginputGetKeyboard(unsigned instance) {
|
||||
if (instance == GKEYBOARD_ALL_INSTANCES)
|
||||
return (GSourceHandle)&KeyboardTimer;
|
||||
return (GSourceHandle)gdriverGetInstance(GDRIVER_TYPE_KEYBOARD, instance);
|
||||
}
|
||||
|
||||
bool_t ginputGetKeyboardStatus(unsigned instance, GEventKeyboard *pe) {
|
||||
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)))
|
||||
return FALSE;
|
||||
|
||||
pe->type = GEVENT_KEYBOARD;
|
||||
// TODO
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#if !GKEYBOARD_LAYOUT_OFF
|
||||
bool_t ginputSetKeyboardLayout(unsigned instance, const void *pLayout) {
|
||||
GKeyboard *k;
|
||||
|
||||
if (!(k = (GKeyboard *)gdriverGetInstance(GDRIVER_TYPE_KEYBOARD, instance)))
|
||||
return FALSE;
|
||||
|
||||
if (pLayout)
|
||||
k->pLayout = pLayout;
|
||||
else
|
||||
k->pLayout = gkvmt(k)->defLayout;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
#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);
|
||||
}
|
||||
|
||||
#endif /* GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD */
|
||||
/** @} */
|
||||
|
|
|
@ -23,72 +23,149 @@
|
|||
/* Type definitions */
|
||||
/*===========================================================================*/
|
||||
|
||||
#define GINPUT_KEYBOARD_NUM_PORTS 1 // The total number of keyboard inputs
|
||||
|
||||
// Event types for various ginput sources
|
||||
#define GEVENT_KEYBOARD (GEVENT_GINPUT_FIRST+2)
|
||||
|
||||
typedef struct GEventKeyboard_t {
|
||||
GEventType type; // The type of this event (GEVENT_KEYBOARD)
|
||||
uint16_t instance; // The keyboard instance
|
||||
char c; // The ASCII code for the current key press.
|
||||
// The only possible values are 0(NUL), 8(BS), 9(TAB), 13(CR), 27(ESC), 32(SPACE) to 126(~), 127(DEL)
|
||||
// 0 indicates an extended only key.
|
||||
uint16_t code; // An extended keyboard code. Codes less than 128 match their ASCII equivalent.
|
||||
#define GKEY_NULL 0
|
||||
#define GKEY_BACKSPACE 8
|
||||
#define GKEY_TAB 9
|
||||
#define GKEY_CR 13
|
||||
#define GKEY_ESC 27
|
||||
#define GKEY_SPACE 32
|
||||
#define GKEY_DEL 127
|
||||
#define GKEY_UP 0x0101
|
||||
#define GKEY_DOWN 0x0102
|
||||
#define GKEY_LEFT 0x0103
|
||||
#define GKEY_RIGHT 0x0104
|
||||
#define GKEY_HOME 0x0105
|
||||
#define GKEY_END 0x0106
|
||||
#define GKEY_PAGEUP 0x0107
|
||||
#define GKEY_PAGEDOWN 0x0108
|
||||
#define GKEY_INSERT 0x0109
|
||||
#define GKEY_DELETE 0x010A
|
||||
#define GKEY_SHIFT 0x0201
|
||||
#define GKEY_CNTRL 0x0202
|
||||
#define GKEY_ALT 0x0203
|
||||
#define GKEY_WINKEY 0x0204
|
||||
#define GKEY_RCLKEY 0x0205
|
||||
#define GKEY_FNKEY 0x0206
|
||||
#define GKEY_FN1 0x0301
|
||||
#define GKEY_FN2 0x0302
|
||||
#define GKEY_FN3 0x0303
|
||||
#define GKEY_FN4 0x0304
|
||||
#define GKEY_FN5 0x0305
|
||||
#define GKEY_FN6 0x0306
|
||||
#define GKEY_FN7 0x0307
|
||||
#define GKEY_FN8 0x0308
|
||||
#define GKEY_FN9 0x0309
|
||||
#define GKEY_FN10 0x030A
|
||||
#define GKEY_FN11 0x030B
|
||||
#define GKEY_FN12 0x030C
|
||||
uint16_t current_buttons; // A bit is set to indicate various meta status.
|
||||
#define GMETA_KEY_DOWN 0x0001
|
||||
#define GMETA_KEY_SHIFT 0x0002
|
||||
#define GMETA_KEY_CNTRL 0x0004
|
||||
#define GMETA_KEY_ALT 0x0008
|
||||
#define GMETA_KEY_WINKEY 0x0010
|
||||
#define GMETA_KEY_RCLKKEY 0x0020
|
||||
#define GMETA_KEY_FN 0x0040
|
||||
#define GMETA_KEY_MISSED_EVENT 0x8000
|
||||
uint16_t last_buttons; // The value of current_buttons on the last event
|
||||
uint16_t bytecount; // The number of bytes in c[]. Note this will only ever represent 0 or 1 characters. This is set to 0 for state transitions.
|
||||
char c[8]; // The utf8 code for the key or a special key code
|
||||
// Normal characters with special meaning. They are a maximum of 1 byte in length.
|
||||
#define GKEY_NULL 0
|
||||
#define GKEY_BACKSPACE 8
|
||||
#define GKEY_TAB 9
|
||||
#define GKEY_LF 10
|
||||
#define GKEY_CR 13
|
||||
#define GKEY_ENTER 13
|
||||
#define GKEY_ESC 27
|
||||
#define GKEY_SPACE 32
|
||||
#define GKEY_DEL 127
|
||||
|
||||
// These are special keys - GKEYSTATE_SPECIAL will be set. They are a maximum of 1 byte in length.
|
||||
#define GKEY_UP 0x81
|
||||
#define GKEY_DOWN 0x82
|
||||
#define GKEY_LEFT 0x83
|
||||
#define GKEY_RIGHT 0x84
|
||||
#define GKEY_HOME 0x85
|
||||
#define GKEY_END 0x86
|
||||
#define GKEY_PAGEUP 0x87
|
||||
#define GKEY_PAGEDOWN 0x88
|
||||
#define GKEY_INSERT 0x89
|
||||
#define GKEY_WINKEY 0x8A
|
||||
#define GKEY_RIGHTCLICKKEY 0x8B
|
||||
#define GKEY_FN1 0x91
|
||||
#define GKEY_FN2 0x92
|
||||
#define GKEY_FN3 0x93
|
||||
#define GKEY_FN4 0x94
|
||||
#define GKEY_FN5 0x95
|
||||
#define GKEY_FN6 0x96
|
||||
#define GKEY_FN7 0x97
|
||||
#define GKEY_FN8 0x98
|
||||
#define GKEY_FN9 0x99
|
||||
#define GKEY_FN10 0x9A
|
||||
#define GKEY_FN11 0x9B
|
||||
#define GKEY_FN12 0x9C
|
||||
#define GKEY_FN13 0x9D
|
||||
#define GKEY_FN14 0x9E
|
||||
#define GKEY_FN15 0x9F
|
||||
#define GKEY_CTRLBREAK 0xA0
|
||||
#define GKEY_CTRLPAUSE 0xA1
|
||||
#define GKEY_SYSREQ 0xA2
|
||||
#define GKEY_PRINTSCREEN 0xA3
|
||||
#define GKEY_POWER 0xA4
|
||||
#define GKEY_SLEEP 0xA5
|
||||
#define GKEY_SCREENSWITCH 0xA6
|
||||
#define GKEY_SCREENLOCK 0xA7
|
||||
#define GKEY_WIFIONOFF 0xA8
|
||||
#define GKEY_TRACKPADONOFF 0xA9
|
||||
#define GKEY_STARTMEDIA 0xAA
|
||||
#define GKEY_STARTHOME 0xAB
|
||||
#define GKEY_STARTEMAIL 0xAC
|
||||
#define GKEY_STARTCOMPUTER 0xAD
|
||||
#define GKEY_STARTAPP1 0xAE
|
||||
#define GKEY_STARTAPP2 0xAF
|
||||
#define GKEY_VOLUP 0xB0
|
||||
#define GKEY_VOLDOWN 0xB1
|
||||
#define GKEY_VOLMUTE 0xB2
|
||||
#define GKEY_EJECT 0xB3
|
||||
#define GKEY_MEDIAPLAY 0xB4
|
||||
#define GKEY_MEDIASTOP 0xB5
|
||||
#define GKEY_MEDIAPAUSE 0xB6
|
||||
#define GKEY_MEDIAFORWARD 0xB7
|
||||
#define GKEY_MEDIANEXT 0xB8
|
||||
#define GKEY_MEDIAREWIND 0xB9
|
||||
#define GKEY_MEDIAPREV 0xBA
|
||||
#define GKEY_MEDIASLOW 0xBB
|
||||
#define GKEY_LIGHTUP 0xBC
|
||||
#define GKEY_LIGHTDOWN 0xBD
|
||||
#define GKEY_LIGHTONOFF 0xBE
|
||||
#define GKEY_LAYOUT_FIRST 0xC0 // Special characters the layout can return start here.
|
||||
#define GKEY_DRIVER_FIRST 0xE0 // Special characters the driver can return start here.
|
||||
|
||||
uint32_t keystate; // The keyboard state.
|
||||
#define GKEYSTATE_KEYUP_BIT 0
|
||||
#define GKEYSTATE_REPEAT_BIT 1
|
||||
#define GKEYSTATE_SPECIAL_BIT 2
|
||||
#define GKEYSTATE_RAW_BIT 3
|
||||
#define GKEYSTATE_SHIFT_L_BIT 4
|
||||
#define GKEYSTATE_SHIFT_R_BIT 5
|
||||
#define GKEYSTATE_CTRL_L_BIT 6
|
||||
#define GKEYSTATE_CTRL_R_BIT 7
|
||||
#define GKEYSTATE_ALT_L_BIT 8
|
||||
#define GKEYSTATE_ALT_R_BIT 9
|
||||
#define GKEYSTATE_FN_BIT 10
|
||||
#define GKEYSTATE_COMPOSE_BIT 11
|
||||
#define GKEYSTATE_WINKEY_BIT 12
|
||||
#define GKEYSTATE_CAPSLOCK_BIT 13
|
||||
#define GKEYSTATE_NUMLOCK_BIT 14
|
||||
#define GKEYSTATE_SCROLLLOCK_BIT 15
|
||||
#define GKEYSTATE_LAYOUT_FIRST_BIT 16
|
||||
#define GKEYSTATE_SYSTEM_FIRST_BIT 20
|
||||
#define GKEYSTATE_DRIVER_FIRST_BIT 24
|
||||
#define GKEYSTATE_MISSED_EVENT_BIT 31
|
||||
|
||||
#define GKEYSTATE_KEYUP (1<<GKEYSTATE_KEYUP_BIT) // This is a keyup rather than a keydown event
|
||||
#define GKEYSTATE_REPEAT (1<<GKEYSTATE_REPEAT_BIT) // This is an automatic repeat character
|
||||
#define GKEYSTATE_SPECIAL (1<<GKEYSTATE_SPECIAL_BIT) // The character is a special character defined above and not a normal (utf8) character
|
||||
#define GKEYSTATE_RAW (1<<GKEYSTATE_RAW_BIT) // The character is a raw scancode and not a normal character
|
||||
#define GKEYSTATE_SHIFT_L (1<<GKEYSTATE_SHIFT_L_BIT) // Left Shift is down
|
||||
#define GKEYSTATE_SHIFT_R (1<<GKEYSTATE_SHIFT_R_BIT) // Right Shift is down
|
||||
#define GKEYSTATE_CTRL_L (1<<GKEYSTATE_CTRL_L_BIT) // Left Control is down
|
||||
#define GKEYSTATE_CTRL_R (1<<GKEYSTATE_CTRL_R_BIT) // Right Control is down
|
||||
#define GKEYSTATE_APPLE_CMD_L (1<<GKEYSTATE_CTRL_L_BIT) // Left Cmd (apple keyboard) is down
|
||||
#define GKEYSTATE_APPLE_CMD_R (1<<GKEYSTATE_CTRL_R_BIT) // Right Cmd (apple keyboard) is down
|
||||
#define GKEYSTATE_ALT_L (1<<GKEYSTATE_ALT_L_BIT) // Left Alt is down
|
||||
#define GKEYSTATE_ALT_R (1<<GKEYSTATE_ALT_R_BIT) // Right Alt is down
|
||||
#define GKEYSTATE_APPLE_OPTION_L (1<<GKEYSTATE_ALT_L_BIT) // Left Option (apple keyboard) is down
|
||||
#define GKEYSTATE_APPLE_OPTION_R (1<<GKEYSTATE_ALT_R_BIT) // Right Option (apple keyboard) is down
|
||||
#define GKEYSTATE_FN (1<<GKEYSTATE_FN_BIT) // Fn is down
|
||||
#define GKEYSTATE_COMPOSE (1<<GKEYSTATE_COMPOSE_BIT) // Compose is down
|
||||
#define GKEYSTATE_WINKEY (1<<GKEYSTATE_WINKEY_BIT) // WinKey is down
|
||||
#define GKEYSTATE_APPLE_CTRL (1<<GKEYSTATE_WINKEY_BIT) // Control key on apple keyboard is down
|
||||
#define GKEYSTATE_CAPSLOCK (1<<GKEYSTATE_CAPSLOCK_BIT) // CapsLock is on
|
||||
#define GKEYSTATE_NUMLOCK (1<<GKEYSTATE_NUMLOCK_BIT) // NumLock is on
|
||||
#define GKEYSTATE_SCROLLLOCK (1<<GKEYSTATE_SCROLLLOCK_BIT) // ScrollLock is on
|
||||
#define GKEYSTATE_LAYOUT_FIRST (1<<GKEYSTATE_LAYOUT_FIRST_BIT) // 4 bits for extra states for the key Layout
|
||||
#define GKEYSTATE_SYSTEM_FIRST (1<<GKEYSTATE_SYSTEM_FIRST_BIT) // 1st available flag for the system's use (maximum 4 bits)
|
||||
#define GKEYSTATE_DRIVER_FIRST (1<<GKEYSTATE_DRIVER_FIRST_BIT) // 1st available flag for the driver's use (maximum 7 bits)
|
||||
#define GKEYSTATE_MISSED_EVENT (1<<GKEYSTATE_MISSED_EVENT_BIT) // A keyboard event has been missed
|
||||
|
||||
#define GKEYSTATE_SHIFT (GKEYSTATE_SHIFT_L|GKEYSTATE_SHIFT_R) // A shift key is down (left or right)
|
||||
#define GKEYSTATE_CTRL (GKEYSTATE_CTRL_L|GKEYSTATE_CTRL_R) // A control key is down (left or right)
|
||||
#define GKEYSTATE_ALT (GKEYSTATE_ALT_L|GKEYSTATE_ALT_R) // A alt key is down (left or right)
|
||||
#define GKEYSTATE_APPLE_OPTION (GKEYSTATE_APPLE_OPTION_L|GKEYSTATE_APPLE_OPTION_R) // A apple option key is down (left or right)
|
||||
#define GKEYSTATE_APPLE_CMD (GKEYSTATE_APPLE_CMD_L|GKEYSTATE_APPLE_CMD_R) // A apple cmd key is down (left or right)
|
||||
} GEventKeyboard;
|
||||
|
||||
// Keyboard Listen Flags - passed to geventAddSourceToListener()
|
||||
#define GLISTEN_KEYREPEATS 0x0001 // Return key repeats (where the key is held down to get a repeat character)
|
||||
#define GLISTEN_KEYCODES 0x0002 // Return all key presses including extended code key presses (not just ascii codes)
|
||||
#define GLISTEN_KEYALL 0x0004 // Return keyup's, keydown's and everything in between (but not repeats unless GLISTEN_KEYREPEATS is set).
|
||||
#define GLISTEN_KEYSINGLE 0x8000 // Return only when one particular extended code key is pressed or released. The particular extended code is OR'd into this value
|
||||
// eg. (GLISTEN_KEYSINGLE | GKEY_CR)
|
||||
// No other flags may be set with this flag.
|
||||
#define GLISTEN_KEYREPEATSOFF 0x0001 // Ignore key repeats (if possible)
|
||||
#define GLISTEN_KEYNOSPECIALS 0x0002 // Ignore special keys
|
||||
#define GLISTEN_KEYUP 0x0004 // Return keyup's as well as key down events
|
||||
#define GLISTEN_KEYTRANSITIONS 0x0008 // Return transitions to the key state
|
||||
#define GLISTEN_KEYRAW 0x0010 // Return raw scan-codes. This turns off normal character processing.
|
||||
|
||||
// All keyboards
|
||||
#define GKEYBOARD_ALL_INSTANCES ((unsigned)-1)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
|
@ -105,7 +182,7 @@ extern "C" {
|
|||
*
|
||||
* @return The source handle of the created input instance
|
||||
*/
|
||||
GSourceHandle ginputGetKeyboard(uint16_t instance);
|
||||
GSourceHandle ginputGetKeyboard(unsigned instance);
|
||||
|
||||
/**
|
||||
* @brief Get the current keyboard status
|
||||
|
@ -115,7 +192,19 @@ extern "C" {
|
|||
*
|
||||
* @return Returns FALSE on an error (eg invalid instance)
|
||||
*/
|
||||
bool_t ginputGetKeyboardStatus(uint16_t instance, GEventKeyboard *pkeyboard);
|
||||
bool_t ginputGetKeyboardStatus(unsigned instance, GEventKeyboard *pkeyboard);
|
||||
|
||||
#if !GKEYBOARD_LAYOUT_OFF || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Set the keyboard layout
|
||||
*
|
||||
* @param[in] instance The ID of the keyboard input instance
|
||||
* @param[in] pLayout The keyboard layout micro-code. Passing NULL defaults to the driver's default layout.
|
||||
*
|
||||
* @return Returns FALSE on an error (eg invalid instance)
|
||||
*/
|
||||
bool_t ginputSetKeyboardLayout(unsigned instance, const void *pLayout);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -125,4 +214,3 @@ extern "C" {
|
|||
|
||||
#endif /* _GINPUT_KEYBOARD_H */
|
||||
/** @} */
|
||||
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* 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:
|
||||
*
|
||||
* http://ugfx.org/license.html
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file src/ginput/keyboard_microcode.c
|
||||
* @brief GINPUT keyboard standard microcode definitions.
|
||||
*/
|
||||
|
||||
#include "gfx.h"
|
||||
|
||||
#if GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD && !GKEYBOARD_LAYOUT_OFF
|
||||
|
||||
#include "keyboard_microcode.h"
|
||||
|
||||
#if GKEYBOARD_LAYOUT_SCANCODE2_US
|
||||
|
||||
#error "Keyboard Layout SCANCODE2_US is not fully implemented yet"
|
||||
|
||||
uint8_t KeyboardLayout_ScancodeSet2_US[] = {
|
||||
KMC_HEADERSTART, KMC_HEADER_ID1, KMC_HEADER_ID2, KMC_HEADER_VER_1,
|
||||
|
||||
KMC_RECORDSTART, 0x03, // Handle E0 codes (ignore for now assuming a single character)
|
||||
KMC_TEST_LASTCODE, 0xE0,
|
||||
KMC_ACT_DONE,
|
||||
KMC_RECORDSTART, 0x03,
|
||||
KMC_TEST_CODE, 0xE0,
|
||||
KMC_ACT_STOP,
|
||||
|
||||
KMC_RECORDSTART, 0x03, // Handle E1 codes (ignore for now assuming a single character)
|
||||
KMC_TEST_LASTCODE, 0xE1,
|
||||
KMC_ACT_DONE,
|
||||
KMC_RECORDSTART, 0x03,
|
||||
KMC_TEST_CODE, 0xE1,
|
||||
KMC_ACT_STOP,
|
||||
|
||||
KMC_RECORDSTART, 0x03, // Handle E2 codes (ignore for now assuming a single character)
|
||||
KMC_TEST_LASTCODE, 0xE2,
|
||||
KMC_ACT_DONE,
|
||||
KMC_RECORDSTART, 0x03,
|
||||
KMC_TEST_CODE, 0xE2,
|
||||
KMC_ACT_STOP,
|
||||
|
||||
KMC_RECORDSTART, 0x06, // KeyUp
|
||||
KMC_TEST_CODEBIT, 0x80,
|
||||
KMC_ACT_STATEBIT, GKEYSTATE_KEYUP_BIT,
|
||||
KMC_ACT_CODEBIT, 0x80 | KMC_BIT_CLEAR,
|
||||
|
||||
KMC_RECORDSTART, 0x05, // CapsLock (on keyup to avoid repeats)
|
||||
KMC_TEST_CODE, 0x58,
|
||||
KMC_TEST_STATEBIT, GKEYSTATE_KEYUP_BIT | KMC_BIT_CLEAR,
|
||||
KMC_ACT_DONE,
|
||||
KMC_RECORDSTART, 0x05,
|
||||
KMC_TEST_CODE, 0x58,
|
||||
KMC_ACT_STATEBIT, GKEYSTATE_CAPSLOCK_BIT | KMC_BIT_INVERT,
|
||||
KMC_ACT_DONE,
|
||||
|
||||
KMC_RECORDSTART, 0x05, // Detect Shift Keys
|
||||
//KMC_ACT_LAYOUTBIT, SCANCODESET2_LAYOUT_E0_BIT | KMC_BIT_CLEAR,
|
||||
KMC_ACT_STOP,
|
||||
|
||||
KMC_RECORDSTART, 0x03,
|
||||
KMC_ACT_CHARRANGE, 0x00,
|
||||
KMC_ACT_DONE,
|
||||
|
||||
KMC_RECORDSTART, 0x00,
|
||||
};
|
||||
#endif // GKEYBOARD_LAYOUT_SCANCODE2_US
|
||||
|
||||
#endif // GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD && !GKEYBOARD_LAYOUT_OFF
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* 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:
|
||||
*
|
||||
* http://ugfx.org/license.html
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file src/ginput/keyboard_microcode.h
|
||||
* @brief GINPUT keyboard layout microcode definition.
|
||||
*/
|
||||
|
||||
#ifndef _KEYBOARD_MICROCODE_H
|
||||
#define _KEYBOARD_MICROCODE_H
|
||||
|
||||
/*
|
||||
* Keyboard Layout Microcode Definition
|
||||
*
|
||||
* Each time a byte is received from the keyboard it is processed through the layout microcode engine. This enables conversion from
|
||||
* scancodes to ascii, internationalization, and various other tricky keyboard behavior.
|
||||
* Note a "code" is defined as a single byte of data from the keyboard, a "scancode" is one or more "codes" that are sent in response to one keyboard press or release.
|
||||
*
|
||||
* The layout microcode can even be switched on the fly by the application to effect such changes as changing from US English to Russian layouts.
|
||||
* They could conceivably even be loaded from disk at run-time.
|
||||
*
|
||||
* In the interest of efficiency there is very little error checking. Make sure your layout microcode has been debugged properly before releasing
|
||||
* to production code.
|
||||
*
|
||||
* Layout microcode consists of a header followed by 1 or more records.
|
||||
*
|
||||
* The header consists of a KMC_HEADERSTART and associated bytes. The is used only to check it looks like it might be layout microcode and to specify the
|
||||
* version of microcode. Future versions of layout microcode will always have the same header at least to the version number.
|
||||
*
|
||||
* Each record is delimited by a KMC_RECORDSTART. Each record can contain a maximum of 255 bytes.
|
||||
* A record length of zero indicates the end of the layout microcode.
|
||||
*
|
||||
* A record consists a mixture of tests and actions (normally the tests are first). If a test fails the rest of this record is skipped and the next
|
||||
* record is processed. This has the effect of AND'ing multiple tests that occur together.
|
||||
* KMC_TEST_INIT and KMC_TEST_ERROR are special. These tests must be the first byte in their respective record as without this test being there, there
|
||||
* is an implicit test that a code has actually been received.
|
||||
* If no records have successful tests for this code then by extension no actions are executed. That is, the code is ignored.
|
||||
* After fully processing a record, the next record is processed. This can be prevented by using the KMC_ACT_STOP action. When encountered all processing
|
||||
* on this code stops.
|
||||
*
|
||||
* Some tests set a pseudo variable called "diff". This is then used by some actions. At the start of a new record "diff" is set to "code" (or 0 for the init and
|
||||
* error conditions).
|
||||
* Some tests and actions do bit operations on either the saved key-state or on the code itself. Bit numbers (which can range from 0 to 31) test or affect the
|
||||
* "set" state of the bit. OR'ing KMC_BIT_CLEAR with the bit number test or affect the "clear" state of the bit. For example, KMC_ACT_STATEBIT with a parameter
|
||||
* of 10 will set bit 10 of the key-state. KMC_ACT_STATEBIT with a parameter of (10 | KMC_BIT_CLEAR) will clear bit 10 of the key-state.
|
||||
*
|
||||
*/
|
||||
|
||||
#define KMC_HEADERSTART 0x00 // Followed by: ID1 ID2 VER - This is the start of layout microcode.
|
||||
#define KMC_HEADER_ID1 'L'
|
||||
#define KMC_HEADER_ID2 'M'
|
||||
#define KMC_HEADER_VER_1 0x01
|
||||
|
||||
#define KMC_HEADER_VER_CURRENT KMC_HEADER_VER_1 // The current version number
|
||||
#define KMC_HEADER_VER_MIN KMC_HEADER_VER_1 // The minimum version number accepted
|
||||
#define KMC_HEADER_VER_MAX KMC_HEADER_VER_1 // The maximum version number accepted
|
||||
|
||||
#define KMC_RECORDSTART 0x01 // Followed by: nn b0 b1 ... b(nn-1) - nn bytes of test and action follow, nn = 00 means end of all tests
|
||||
|
||||
#define KMC_TEST_INIT 0x10 // Followed by: nothing - The layout is initializing
|
||||
#define KMC_TEST_ERROR 0x11 // Followed by: nothing - The keyboard has signaled an error
|
||||
#define KMC_TEST_CODE 0x12 // Followed by: aa - Code must equal aa. Diff is set to 0
|
||||
#define KMC_TEST_CODERANGE 0x13 // Followed by: aa bb - Code must be between aa and bb (inclusive). Diff is set to (code - aa)
|
||||
#define KMC_TEST_CODETABLE 0x14 // Followed by: n m1 m2 ... - Code must equal an m value. There are n possible m values. Diff is set to 0 to n-1 (the match position)
|
||||
#define KMC_TEST_STATEBIT 0x15 // Followed by: b - Test if a key-state bit is set/clear. b = 0 to 31 or b = (0 | KMC_BIT_CLEAR) to (31 | KMC_BIT_CLEAR)
|
||||
#define KMC_TEST_STATEOR 0x16 // Followed by: b1 b2 - Test two key-state bits and OR the result
|
||||
#define KMC_TEST_STATEAND 0x17 // Followed by: b1 b2 - Test two key-state bits and AND the result
|
||||
#define KMC_TEST_LAYOUTBIT 0x18 // Followed by: b - Test if a layout bit is set/clear. b = 0 to 15 or b = (0 | KMC_BIT_CLEAR) to (15 | KMC_BIT_CLEAR)
|
||||
#define KMC_TEST_LAYOUTOR 0x19 // Followed by: b1 b2 - Test two layout bits and OR the result
|
||||
#define KMC_TEST_LAYOUTAND 0x1A // Followed by: b1 b2 - Test two layout bits and AND the result
|
||||
#define KMC_TEST_CODEBIT 0x1B // Followed by: b - Test if a code bit is set/clear. b = 0 to 7 or b = (0 | KMC_BIT_CLEAR) to (7 | KMC_BIT_CLEAR)
|
||||
#define KMC_TEST_CODEOR 0x1C // Followed by: b1 b2 - Test two code bits and OR the result
|
||||
#define KMC_TEST_CODEAND 0x1D // Followed by: b1 b2 - Test two code bits and AND the result
|
||||
#define KMC_TEST_LASTCODE 0x1E // Followed by: aa - Test if the last scancode was aa
|
||||
#define KMC_TEST_SHIFT 0x20 // Followed by: nothing - Test if a shift key is down
|
||||
#define KMC_TEST_NOSHIFT 0x21 // Followed by: nothing - Test if a shift key is not down
|
||||
#define KMC_TEST_CTRL 0x22 // Followed by: nothing - Test if a control key is down
|
||||
#define KMC_TEST_NOCTRL 0x23 // Followed by: nothing - Test if a control key is not down
|
||||
#define KMC_TEST_ALT 0x24 // Followed by: nothing - Test if an alt key is down
|
||||
#define KMC_TEST_NOALT 0x25 // Followed by: nothing - Test if an alt key is not down
|
||||
#define KMC_TEST_CAPS 0x26 // Followed by: nothing - Test if capslock as modified by shift is active
|
||||
#define KMC_TEST_NOCAPS 0x27 // Followed by: nothing - Test if capslock as modified by shift is not active
|
||||
#define KMC_TEST_NUMLOCK 0x28 // Followed by: nothing - Test if numlock is active
|
||||
#define KMC_TEST_NONUMLOCK 0x29 // Followed by: nothing - Test if numlock is not active
|
||||
|
||||
#define KMC_ACT_STOP 0xFF // Followed by: nothing - Stop processing this code
|
||||
#define KMC_ACT_DONE 0xFE // Followed by: nothing - Finished processing this scancode sequence. (also implies STOP)
|
||||
#define KMC_ACT_RESET 0xFD // Followed by: nothing - Empty all buffers
|
||||
#define KMC_ACT_STATEBIT 0x80 // Followed by: b - Set or clear bit b in key-state. b = 0 to 31 or b = (0 | KMC_BIT_CLEAR) to (31 | KMC_BIT_CLEAR)
|
||||
#define KMC_ACT_LAYOUTBIT 0x81 // Followed by: b - Set or clear bit b in layout bits. b = 0 to 15 or b = (0 | KMC_BIT_CLEAR) to (15 | KMC_BIT_CLEAR)
|
||||
#define KMC_ACT_CODEBIT 0x82 // Followed by: b - Set or clear bit b in code. b = 0 to 7 or b = (0 | KMC_BIT_CLEAR) to (7 | KMC_BIT_CLEAR)
|
||||
#define KMC_ACT_CHAR 0x83 // Followed by: nn - Append char nn to output buffer
|
||||
#define KMC_ACT_CHARCODE 0x84 // Followed by: nothing - Append the code to output buffer
|
||||
#define KMC_ACT_CHARRANGE 0x85 // Followed by: nn - Append char nn + Diff to output
|
||||
#define KMC_ACT_CHARTABLE 0x86 // Followed by: n c1 c2 ... - Append char to output based on c[Diff]. If Diff is greater than n then nothing is appended.
|
||||
#define KMC_ACT_CLEAR 0x87 // Followed by: nothing - Clear the output buffer
|
||||
#define KMC_ACT_CHARADD 0x88 // Followed by: nn - Multiple the last char in output buffer by nn (assume 0 if none) and add Diff
|
||||
#define KMC_ACT_DATA 0x89 // Followed by: nn - Send nn back to the keyboard
|
||||
|
||||
#define KMC_BIT_CLEAR 0x80 // The bit number is being used for a bit clear operation rather than a bit set operation.
|
||||
#define KMC_BIT_INVERT 0x40 // Invert the bit rather than setting or clearing it.
|
||||
|
||||
#endif /* _KEYBOARD_MICROCODE_H */
|
|
@ -1,5 +1,6 @@
|
|||
GFXSRC += $(GFXLIB)/src/ginput/ginput_ginput.c \
|
||||
$(GFXLIB)/src/ginput/ginput_mouse.c \
|
||||
$(GFXLIB)/src/ginput/ginput_keyboard.c \
|
||||
$(GFXLIB)/src/ginput/keyboard_microcode.c \
|
||||
$(GFXLIB)/src/ginput/ginput_toggle.c \
|
||||
$(GFXLIB)/src/ginput/ginput_dial.c
|
||||
|
|
|
@ -170,7 +170,51 @@
|
|||
#if defined(__DOXYGEN__)
|
||||
#define GMOUSE_DRIVER_LIST GMOUSEVMT_Win32, GMOUSEVMT_Win32
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Milliseconds between keyboard polls.
|
||||
* @details Defaults to 200 milliseconds
|
||||
* @note How often keyboards should be polled.
|
||||
*/
|
||||
#ifndef GINPUT_KEYBOARD_POLL_PERIOD
|
||||
#define GINPUT_KEYBOARD_POLL_PERIOD 200
|
||||
#endif
|
||||
/**
|
||||
* @brief Define multiple static keyboards
|
||||
* @details When not defined the system automatically detects a single linked keyboard driver
|
||||
* @note The references to GKEYBOARDVMT_Win32 in the definition would be replaced
|
||||
* by the names of the VMT for each of the static keyboards you want to
|
||||
* include.
|
||||
* @note Dynamic keyboards associated automatically with a display eg Win32, X or GFXnet
|
||||
* do not need to be specified in this list as the display driver will register
|
||||
* them automatically as the display is created.
|
||||
*/
|
||||
#if defined(__DOXYGEN__)
|
||||
#define GKEYBOARD_DRIVER_LIST GMOUSEVMT_Win32, GMOUSEVMT_Win32
|
||||
#endif
|
||||
/**
|
||||
* @brief Turn off the layout engine.
|
||||
* @details When defined the layout engine is removed from the code and characters
|
||||
* are passed directly from the keyboard driver to the application.
|
||||
* @note Turning off the layout engine just saves code if it is not needed.
|
||||
*/
|
||||
#ifndef GKEYBOARD_LAYOUT_OFF
|
||||
#define GKEYBOARD_LAYOUT_OFF FALSE
|
||||
#endif
|
||||
/**
|
||||
* @brief Various Keyboard Layouts that can be included.
|
||||
* @details A keyboard layout controls conversion of scancodes to characters
|
||||
* and enables one keyboard to have multiple language mappings.
|
||||
* @note Defining a layout does not make it active. The keyboard driver
|
||||
* must have it active as the default or the application must
|
||||
* use @p ginputSetKeyboardLayout() to set the active layout.
|
||||
* @note Multiple layouts can be included but only one will be active
|
||||
* at a time (per keyboard).
|
||||
* @{
|
||||
*/
|
||||
#ifndef GKEYBOARD_LAYOUT_SCANCODE2_US
|
||||
#define GKEYBOARD_LAYOUT_SCANCODE2_US FALSE // US Keyboard using the ScanCode 2 set.
|
||||
#endif
|
||||
/** @} */
|
||||
/** @} */
|
||||
|
||||
#endif /* _GINPUT_OPTIONS_H */
|
||||
|
|
Loading…
Reference in New Issue