mirror of https://github.com/encounter/SDL.git
SDL_TEXTINPUT support for EVDEV
This commit is contained in:
parent
1f21484bdd
commit
b39a4daf04
|
@ -20,13 +20,21 @@ Raspbian (other Linux distros may work as well).
|
||||||
Raspbian Build Dependencies
|
Raspbian Build Dependencies
|
||||||
================================================================================
|
================================================================================
|
||||||
|
|
||||||
sudo apt-get install libudev-dev libasound2-dev
|
sudo apt-get install libudev-dev libasound2-dev libdbus-1-dev
|
||||||
|
|
||||||
You also need the VideoCore binary stuff that ships in /opt/vc for EGL and
|
You also need the VideoCore binary stuff that ships in /opt/vc for EGL and
|
||||||
OpenGL ES 2.x, it usually comes pre installed, but in any case:
|
OpenGL ES 2.x, it usually comes pre installed, but in any case:
|
||||||
|
|
||||||
sudo apt-get install libraspberrypi0 libraspberrypi-bin libraspberrypi-dev
|
sudo apt-get install libraspberrypi0 libraspberrypi-bin libraspberrypi-dev
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
No input
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
Make sure you belong to the "input" group.
|
||||||
|
|
||||||
|
sudo usermod -aG input `whoami`
|
||||||
|
|
||||||
================================================================================
|
================================================================================
|
||||||
No HDMI Audio
|
No HDMI Audio
|
||||||
================================================================================
|
================================================================================
|
||||||
|
@ -39,10 +47,41 @@ to your config.txt file and reboot.
|
||||||
|
|
||||||
Reference: http://www.raspberrypi.org/phpBB3/viewtopic.php?t=5062
|
Reference: http://www.raspberrypi.org/phpBB3/viewtopic.php?t=5062
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
Text Input API support
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
The Text Input API is supported, with translation of scan codes done via the
|
||||||
|
kernel symbol tables. For this to work, SDL needs access to a valid console.
|
||||||
|
If you notice there's no SDL_TEXTINPUT message being emmited, double check that
|
||||||
|
your app has read access to one of the following:
|
||||||
|
|
||||||
|
* /proc/self/fd/0
|
||||||
|
* /dev/tty
|
||||||
|
* /dev/tty[0...6]
|
||||||
|
* /dev/vc/0
|
||||||
|
* /dev/console
|
||||||
|
|
||||||
|
This is usually not a problem if you run from the physical terminal (as opposed
|
||||||
|
to running from a pseudo terminal, such as via SSH). If running from a PTS, a
|
||||||
|
quick workaround is to run your app as root or add yourself to the tty group,
|
||||||
|
then re login to the system.
|
||||||
|
|
||||||
|
sudo usermod -aG tty `whoami`
|
||||||
|
|
||||||
|
The keyboard layout used by SDL is the same as the one the kernel uses.
|
||||||
|
To configure the layout on Raspbian:
|
||||||
|
|
||||||
|
sudo dpkg-reconfigure keyboard-configuration
|
||||||
|
|
||||||
|
To configure the locale, which controls which keys are interpreted as letters,
|
||||||
|
this determining the CAPS LOCK behavior:
|
||||||
|
|
||||||
|
sudo dpkg-reconfigure locales
|
||||||
|
|
||||||
================================================================================
|
================================================================================
|
||||||
Notes
|
Notes
|
||||||
================================================================================
|
================================================================================
|
||||||
|
|
||||||
* Building has only been tested natively (i.e. not cross compiled). Cross
|
* Building has only been tested natively (i.e. not cross compiled). Cross
|
||||||
compilation might work though, feedback is welcome!
|
compilation might work though, feedback is welcome!
|
||||||
* No Text Input yet.
|
|
|
@ -20754,6 +20754,45 @@ $as_echo "#define SDL_INPUT_LINUXEV 1" >>confdefs.h
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CheckInputKD()
|
||||||
|
{
|
||||||
|
|
||||||
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for Linux kd.h" >&5
|
||||||
|
$as_echo_n "checking for Linux kd.h... " >&6; }
|
||||||
|
use_input_kd=no
|
||||||
|
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||||
|
/* end confdefs.h. */
|
||||||
|
|
||||||
|
#include <linux/kd.h>
|
||||||
|
#include <linux/keyboard.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
main ()
|
||||||
|
{
|
||||||
|
|
||||||
|
struct kbentry kbe;
|
||||||
|
kbe.kb_table = KG_CTRL;
|
||||||
|
ioctl(0, KDGKBENT, &kbe);
|
||||||
|
|
||||||
|
;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
_ACEOF
|
||||||
|
if ac_fn_c_try_compile "$LINENO"; then :
|
||||||
|
|
||||||
|
use_input_kd=yes
|
||||||
|
|
||||||
|
fi
|
||||||
|
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||||
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $use_input_kd" >&5
|
||||||
|
$as_echo "$use_input_kd" >&6; }
|
||||||
|
if test x$use_input_kd = xyes; then
|
||||||
|
|
||||||
|
$as_echo "#define SDL_INPUT_LINUXKD 1" >>confdefs.h
|
||||||
|
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
CheckLibUDev()
|
CheckLibUDev()
|
||||||
{
|
{
|
||||||
# Check whether --enable-libudev was given.
|
# Check whether --enable-libudev was given.
|
||||||
|
@ -22080,6 +22119,7 @@ case "$host" in
|
||||||
CheckLibUDev
|
CheckLibUDev
|
||||||
CheckDBus
|
CheckDBus
|
||||||
CheckInputEvents
|
CheckInputEvents
|
||||||
|
CheckInputKD
|
||||||
CheckTslib
|
CheckTslib
|
||||||
CheckUSBHID
|
CheckUSBHID
|
||||||
CheckPTHREAD
|
CheckPTHREAD
|
||||||
|
|
23
configure.in
23
configure.in
|
@ -1791,6 +1791,28 @@ CheckInputEvents()
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dnl See if we can use the kernel kd.h header
|
||||||
|
CheckInputKD()
|
||||||
|
{
|
||||||
|
|
||||||
|
AC_MSG_CHECKING(for Linux kd.h)
|
||||||
|
use_input_kd=no
|
||||||
|
AC_TRY_COMPILE([
|
||||||
|
#include <linux/kd.h>
|
||||||
|
#include <linux/keyboard.h>
|
||||||
|
],[
|
||||||
|
struct kbentry kbe;
|
||||||
|
kbe.kb_table = KG_CTRL;
|
||||||
|
ioctl(0, KDGKBENT, &kbe);
|
||||||
|
],[
|
||||||
|
use_input_kd=yes
|
||||||
|
])
|
||||||
|
AC_MSG_RESULT($use_input_kd)
|
||||||
|
if test x$use_input_kd = xyes; then
|
||||||
|
AC_DEFINE(SDL_INPUT_LINUXKD, 1, [ ])
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
dnl See if the platform offers libudev for device enumeration and hotplugging.
|
dnl See if the platform offers libudev for device enumeration and hotplugging.
|
||||||
CheckLibUDev()
|
CheckLibUDev()
|
||||||
{
|
{
|
||||||
|
@ -2395,6 +2417,7 @@ case "$host" in
|
||||||
CheckLibUDev
|
CheckLibUDev
|
||||||
CheckDBus
|
CheckDBus
|
||||||
CheckInputEvents
|
CheckInputEvents
|
||||||
|
CheckInputKD
|
||||||
CheckTslib
|
CheckTslib
|
||||||
CheckUSBHID
|
CheckUSBHID
|
||||||
CheckPTHREAD
|
CheckPTHREAD
|
||||||
|
|
|
@ -217,6 +217,7 @@
|
||||||
|
|
||||||
/* Enable various input drivers */
|
/* Enable various input drivers */
|
||||||
#undef SDL_INPUT_LINUXEV
|
#undef SDL_INPUT_LINUXEV
|
||||||
|
#undef SDL_INPUT_LINUXKD
|
||||||
#undef SDL_INPUT_TSLIB
|
#undef SDL_INPUT_TSLIB
|
||||||
#undef SDL_JOYSTICK_BEOS
|
#undef SDL_JOYSTICK_BEOS
|
||||||
#undef SDL_JOYSTICK_DINPUT
|
#undef SDL_JOYSTICK_DINPUT
|
||||||
|
|
|
@ -507,7 +507,7 @@ static const char *SDL_scancode_names[SDL_NUM_SCANCODES] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Taken from SDL_iconv() */
|
/* Taken from SDL_iconv() */
|
||||||
static char *
|
char *
|
||||||
SDL_UCS4ToUTF8(Uint32 ch, char *dst)
|
SDL_UCS4ToUTF8(Uint32 ch, char *dst)
|
||||||
{
|
{
|
||||||
Uint8 *p = (Uint8 *) dst;
|
Uint8 *p = (Uint8 *) dst;
|
||||||
|
|
|
@ -59,6 +59,9 @@ extern int SDL_SendEditingText(const char *text, int start, int end);
|
||||||
/* Shutdown the keyboard subsystem */
|
/* Shutdown the keyboard subsystem */
|
||||||
extern void SDL_KeyboardQuit(void);
|
extern void SDL_KeyboardQuit(void);
|
||||||
|
|
||||||
|
/* Convert to UTF-8 */
|
||||||
|
extern char *SDL_UCS4ToUTF8(Uint32 ch, char *dst);
|
||||||
|
|
||||||
#endif /* _SDL_keyboard_c_h */
|
#endif /* _SDL_keyboard_c_h */
|
||||||
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
/* vi: set ts=4 sw=4 expandtab: */
|
||||||
|
|
|
@ -39,7 +39,11 @@ static _THIS = NULL;
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <limits.h> /* For the definition of PATH_MAX */
|
#include <limits.h> /* For the definition of PATH_MAX */
|
||||||
|
#include <linux/input.h>
|
||||||
|
#ifdef SDL_INPUT_LINUXKD
|
||||||
|
#include <linux/kd.h>
|
||||||
|
#include <linux/keyboard.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "SDL.h"
|
#include "SDL.h"
|
||||||
#include "SDL_assert.h"
|
#include "SDL_assert.h"
|
||||||
|
@ -325,12 +329,54 @@ static Uint8 EVDEV_MouseButtons[] = {
|
||||||
SDL_BUTTON_X2 + 3 /* BTN_TASK 0x117 */
|
SDL_BUTTON_X2 + 3 /* BTN_TASK 0x117 */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static char* EVDEV_consoles[] = {
|
||||||
|
"/proc/self/fd/0",
|
||||||
|
"/dev/tty",
|
||||||
|
"/dev/tty0",
|
||||||
|
"/dev/tty1",
|
||||||
|
"/dev/tty2",
|
||||||
|
"/dev/tty3",
|
||||||
|
"/dev/tty4",
|
||||||
|
"/dev/tty5",
|
||||||
|
"/dev/tty6",
|
||||||
|
"/dev/vc/0",
|
||||||
|
"/dev/console"
|
||||||
|
};
|
||||||
|
|
||||||
|
#define IS_CONSOLE(fd) isatty (fd) && ioctl(fd, KDGKBTYPE, &arg) == 0 && ((arg == KB_101) || (arg == KB_84))
|
||||||
|
|
||||||
|
static int SDL_EVDEV_get_console_fd(void)
|
||||||
|
{
|
||||||
|
int fd, i;
|
||||||
|
char arg = 0;
|
||||||
|
|
||||||
|
/* Try a few consoles to see which one we have read access to */
|
||||||
|
|
||||||
|
for( i = 0; i < SDL_arraysize(EVDEV_consoles); i++) {
|
||||||
|
fd = open(EVDEV_consoles[i], O_RDONLY);
|
||||||
|
if (fd >= 0) {
|
||||||
|
if (IS_CONSOLE(fd)) return fd;
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try stdin, stdout, stderr */
|
||||||
|
|
||||||
|
for( fd = 0; fd < 3; fd++) {
|
||||||
|
if (IS_CONSOLE(fd)) return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We won't be able to send SDL_TEXTINPUT events */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
SDL_EVDEV_Init(void)
|
SDL_EVDEV_Init(void)
|
||||||
{
|
{
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
|
|
||||||
if (_this == NULL) {
|
if (_this == NULL) {
|
||||||
|
|
||||||
_this = (SDL_EVDEV_PrivateData *) SDL_calloc(1, sizeof(*_this));
|
_this = (SDL_EVDEV_PrivateData *) SDL_calloc(1, sizeof(*_this));
|
||||||
if(_this == NULL) {
|
if(_this == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
|
@ -354,6 +400,9 @@ SDL_EVDEV_Init(void)
|
||||||
#else
|
#else
|
||||||
/* TODO: Scan the devices manually, like a caveman */
|
/* TODO: Scan the devices manually, like a caveman */
|
||||||
#endif /* SDL_USE_LIBUDEV */
|
#endif /* SDL_USE_LIBUDEV */
|
||||||
|
|
||||||
|
/* We need a physical terminal (not PTS) to be able to translate key code to symbols via the kernel tables */
|
||||||
|
_this->console_fd = SDL_EVDEV_get_console_fd();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,6 +427,9 @@ SDL_EVDEV_Quit(void)
|
||||||
SDL_UDEV_Quit();
|
SDL_UDEV_Quit();
|
||||||
#endif /* SDL_USE_LIBUDEV */
|
#endif /* SDL_USE_LIBUDEV */
|
||||||
|
|
||||||
|
if (_this->console_fd >= 0) {
|
||||||
|
close(_this->console_fd);
|
||||||
|
}
|
||||||
/* Remove existing devices */
|
/* Remove existing devices */
|
||||||
while(_this->first != NULL) {
|
while(_this->first != NULL) {
|
||||||
SDL_EVDEV_device_removed(_this->first->path);
|
SDL_EVDEV_device_removed(_this->first->path);
|
||||||
|
@ -443,11 +495,18 @@ SDL_EVDEV_Poll(void)
|
||||||
SDL_Scancode scan_code;
|
SDL_Scancode scan_code;
|
||||||
int mouse_button;
|
int mouse_button;
|
||||||
SDL_Mouse *mouse;
|
SDL_Mouse *mouse;
|
||||||
|
#ifdef SDL_INPUT_LINUXKD
|
||||||
|
Uint16 modstate;
|
||||||
|
struct kbentry kbe;
|
||||||
|
static char keysym[8];
|
||||||
|
char *end;
|
||||||
|
Uint32 kval;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if SDL_USE_LIBUDEV
|
#if SDL_USE_LIBUDEV
|
||||||
SDL_UDEV_Poll();
|
SDL_UDEV_Poll();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (item = _this->first; item != NULL; item = item->next) {
|
for (item = _this->first; item != NULL; item = item->next) {
|
||||||
while ((len = read(item->fd, events, (sizeof events))) > 0) {
|
while ((len = read(item->fd, events, (sizeof events))) > 0) {
|
||||||
len /= sizeof(events[0]);
|
len /= sizeof(events[0]);
|
||||||
|
@ -455,20 +514,57 @@ SDL_EVDEV_Poll(void)
|
||||||
switch(item->devclass) {
|
switch(item->devclass) {
|
||||||
case SDL_EVDEV_DEVICE_KEYBOARD:
|
case SDL_EVDEV_DEVICE_KEYBOARD:
|
||||||
switch (events[i].type) {
|
switch (events[i].type) {
|
||||||
case EV_KEY:
|
case EV_KEY:
|
||||||
scan_code = SDL_EVDEV_translate_keycode(events[i].code);
|
scan_code = SDL_EVDEV_translate_keycode(events[i].code);
|
||||||
if (scan_code != SDL_SCANCODE_UNKNOWN) {
|
if (scan_code != SDL_SCANCODE_UNKNOWN) {
|
||||||
if (events[i].value == 0) {
|
if (events[i].value == 0) {
|
||||||
SDL_SendKeyboardKey(SDL_RELEASED, scan_code);
|
SDL_SendKeyboardKey(SDL_RELEASED, scan_code);
|
||||||
}
|
|
||||||
else if (events[i].value == 1) {
|
|
||||||
SDL_SendKeyboardKey(SDL_PRESSED, scan_code);
|
|
||||||
}
|
|
||||||
else if (events[i].value == 2) {
|
|
||||||
/* Key repeated */
|
|
||||||
SDL_SendKeyboardKey(SDL_PRESSED, scan_code);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else if (events[i].value == 1 || events[i].value == 2 /* Key repeated */ ) {
|
||||||
|
SDL_SendKeyboardKey(SDL_PRESSED, scan_code);
|
||||||
|
#ifdef SDL_INPUT_LINUXKD
|
||||||
|
if (_this->console_fd >= 0) {
|
||||||
|
kbe.kb_index = events[i].code;
|
||||||
|
/* Convert the key to an UTF-8 char */
|
||||||
|
/* Ref: http://www.linuxjournal.com/article/2783 */
|
||||||
|
modstate = SDL_GetModState();
|
||||||
|
kbe.kb_table = 0;
|
||||||
|
|
||||||
|
/* Ref: http://graphics.stanford.edu/~seander/bithacks.html#ConditionalSetOrClearBitsWithoutBranching */
|
||||||
|
kbe.kb_table |= -( (modstate & KMOD_LCTRL) != 0) & (1 << KG_CTRLL | 1 << KG_CTRL);
|
||||||
|
kbe.kb_table |= -( (modstate & KMOD_RCTRL) != 0) & (1 << KG_CTRLR | 1 << KG_CTRL);
|
||||||
|
kbe.kb_table |= -( (modstate & KMOD_LSHIFT) != 0) & (1 << KG_SHIFTL | 1 << KG_SHIFT);
|
||||||
|
kbe.kb_table |= -( (modstate & KMOD_RSHIFT) != 0) & (1 << KG_SHIFTR | 1 << KG_SHIFT);
|
||||||
|
kbe.kb_table |= -( (modstate & KMOD_LALT) != 0) & (1 << KG_ALT);
|
||||||
|
kbe.kb_table |= -( (modstate & KMOD_RALT) != 0) & (1 << KG_ALTGR);
|
||||||
|
|
||||||
|
if(ioctl(_this->console_fd, KDGKBENT, (unsigned long)&kbe) == 0 &&
|
||||||
|
( (KTYP(kbe.kb_value) == KT_LATIN) || (KTYP(kbe.kb_value) == KT_ASCII) || (KTYP(kbe.kb_value) == KT_LETTER) ))
|
||||||
|
{
|
||||||
|
kval = KVAL(kbe.kb_value);
|
||||||
|
|
||||||
|
/* While there's a KG_CAPSSHIFT symbol, it's not useful to build the table index with it
|
||||||
|
* because 1 << KG_CAPSSHIFT overflows the 8 bits of kb_table
|
||||||
|
* So, we do the CAPS LOCK logic here. Note that isalpha depends on the locale!
|
||||||
|
*/
|
||||||
|
if ( modstate & KMOD_CAPS && isalpha(kval) ) {
|
||||||
|
if ( isupper(kval) ) {
|
||||||
|
kval = tolower(kval);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
kval = toupper(kval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert to UTF-8 and send */
|
||||||
|
end = SDL_UCS4ToUTF8( kval, keysym);
|
||||||
|
*end = '\0';
|
||||||
|
SDL_SendKeyboardText(keysym);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -651,3 +747,4 @@ SDL_EVDEV_device_removed(const char *devpath)
|
||||||
#endif /* SDL_INPUT_LINUXEV */
|
#endif /* SDL_INPUT_LINUXEV */
|
||||||
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
/* vi: set ts=4 sw=4 expandtab: */
|
||||||
|
|
||||||
|
|
|
@ -19,8 +19,6 @@
|
||||||
3. This notice may not be removed or altered from any source distribution.
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/input.h>
|
|
||||||
|
|
||||||
#include "SDL_config.h"
|
#include "SDL_config.h"
|
||||||
|
|
||||||
#ifndef _SDL_evdev_h
|
#ifndef _SDL_evdev_h
|
||||||
|
@ -42,7 +40,7 @@ typedef struct SDL_evdevlist_item
|
||||||
char *path;
|
char *path;
|
||||||
int fd;
|
int fd;
|
||||||
SDL_EVDEV_deviceclass devclass;
|
SDL_EVDEV_deviceclass devclass;
|
||||||
struct SDL_evdevlist_item *next;
|
struct SDL_evdevlist_item *next;
|
||||||
} SDL_evdevlist_item;
|
} SDL_evdevlist_item;
|
||||||
|
|
||||||
typedef struct SDL_EVDEV_PrivateData
|
typedef struct SDL_EVDEV_PrivateData
|
||||||
|
@ -51,6 +49,7 @@ typedef struct SDL_EVDEV_PrivateData
|
||||||
SDL_evdevlist_item *last;
|
SDL_evdevlist_item *last;
|
||||||
int numdevices;
|
int numdevices;
|
||||||
int ref_count;
|
int ref_count;
|
||||||
|
int console_fd;
|
||||||
} SDL_EVDEV_PrivateData;
|
} SDL_EVDEV_PrivateData;
|
||||||
|
|
||||||
extern int SDL_EVDEV_Init(void);
|
extern int SDL_EVDEV_Init(void);
|
||||||
|
|
Loading…
Reference in New Issue