mirror of https://github.com/neutrinolabs/xrdp
Update genkeymap executable to use new format
This commit is contained in:
parent
b0cfc1a12b
commit
fe410a595d
|
@ -290,6 +290,9 @@
|
|||
|
||||
#define XR_RDP_SCAN_LSHIFT 42
|
||||
#define XR_RDP_SCAN_ALT 56
|
||||
// scancodes affected by numlock
|
||||
#define XR_RDP_SCAN_MIN_NUMLOCK 71 // KP7
|
||||
#define XR_RDP_SCAN_MAX_NUMLOCK 83 // KPDL
|
||||
|
||||
// Since we're not guaranteed to have pixman, copy these directives.
|
||||
#define XRDP_PIXMAN_TYPE_ARGB 2
|
||||
|
|
|
@ -537,6 +537,13 @@ AC_CHECK_HEADER([X11/extensions/Xrandr.h], [],
|
|||
[AC_MSG_ERROR([please install libxrandr-dev or libXrandr-devel])],
|
||||
[#include <X11/Xlib.h>])
|
||||
|
||||
# checking for XKB
|
||||
AC_CHECK_HEADER([X11/extensions/XKBrules.h], [],
|
||||
[AC_MSG_ERROR([please install libxkbfile-dev or libxkbfile-devel])],
|
||||
[#include <X11/Xlib.h>
|
||||
#include <X11/XKBlib.h>
|
||||
#include <stdio.h>])
|
||||
|
||||
if test "x$enable_utmp" = "xyes"
|
||||
then
|
||||
AC_CHECK_HEADERS(utmp.h utmpx.h)
|
||||
|
|
|
@ -2,15 +2,19 @@ EXTRA_DIST = \
|
|||
dump-keymaps.sh \
|
||||
readme.txt
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir)/common
|
||||
|
||||
AM_CFLAGS = $(X_CFLAGS)
|
||||
|
||||
bin_PROGRAMS = \
|
||||
xrdp-genkeymap
|
||||
|
||||
xrdp_genkeymap_SOURCES = genkeymap.c evdev-map.c
|
||||
xrdp_genkeymap_SOURCES = genkeymap.c
|
||||
|
||||
xrdp_genkeymap_LDFLAGS = \
|
||||
$(X_LIBS)
|
||||
|
||||
xrdp_genkeymap_LDADD = \
|
||||
$(X_PRE_LIBS) -lX11 $(X_EXTRA_LIBS)
|
||||
$(top_builddir)/common/libcommon.la \
|
||||
$(X_PRE_LIBS) -lxkbfile -lX11 $(X_EXTRA_LIBS)
|
||||
|
|
|
@ -1,279 +0,0 @@
|
|||
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
|
||||
/*
|
||||
* evdev-map.c
|
||||
* Copyright (C) Michał Górny 2014 <mgorny@gentoo.org>
|
||||
*
|
||||
* You may redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License, as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* main.cc is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with main.cc. If not, write to:
|
||||
* The Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301, USA
|
||||
*
|
||||
* xfree86(base)->evdev keycode mapping
|
||||
*/
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config_ac.h>
|
||||
#endif
|
||||
|
||||
int xfree86_to_evdev[255 - 8 + 1] =
|
||||
{
|
||||
/* MDSW */ 203,
|
||||
/* ESC */ 9,
|
||||
/* AE01 */ 10,
|
||||
/* AE02 */ 11,
|
||||
/* AE03 */ 12,
|
||||
/* AE04 */ 13,
|
||||
/* AE05 */ 14,
|
||||
/* AE06 */ 15,
|
||||
/* AE07 */ 16,
|
||||
/* AE08 */ 17,
|
||||
/* AE09 */ 18,
|
||||
/* AE10 */ 19,
|
||||
/* AE11 */ 20,
|
||||
/* AE12 */ 21,
|
||||
/* BKSP */ 22,
|
||||
/* TAB */ 23,
|
||||
/* AD01 */ 24,
|
||||
/* AD02 */ 25,
|
||||
/* AD03 */ 26,
|
||||
/* AD04 */ 27,
|
||||
/* AD05 */ 28,
|
||||
/* AD06 */ 29,
|
||||
/* AD07 */ 30,
|
||||
/* AD08 */ 31,
|
||||
/* AD09 */ 32,
|
||||
/* AD10 */ 33,
|
||||
/* AD11 */ 34,
|
||||
/* AD12 */ 35,
|
||||
/* RTRN */ 36,
|
||||
/* LCTL */ 37,
|
||||
/* AC01 */ 38,
|
||||
/* AC02 */ 39,
|
||||
/* AC03 */ 40,
|
||||
/* AC04 */ 41,
|
||||
/* AC05 */ 42,
|
||||
/* AC06 */ 43,
|
||||
/* AC07 */ 44,
|
||||
/* AC08 */ 45,
|
||||
/* AC09 */ 46,
|
||||
/* AC10 */ 47,
|
||||
/* AC11 */ 48,
|
||||
/* TLDE */ 49,
|
||||
/* LFSH */ 50,
|
||||
/* BKSL */ 51,
|
||||
/* AB01 */ 52,
|
||||
/* AB02 */ 53,
|
||||
/* AB03 */ 54,
|
||||
/* AB04 */ 55,
|
||||
/* AB05 */ 56,
|
||||
/* AB06 */ 57,
|
||||
/* AB07 */ 58,
|
||||
/* AB08 */ 59,
|
||||
/* AB09 */ 60,
|
||||
/* AB10 */ 61,
|
||||
/* RTSH */ 62,
|
||||
/* KPMU */ 63,
|
||||
/* LALT */ 64,
|
||||
/* SPCE */ 65,
|
||||
/* CAPS */ 66,
|
||||
/* FK01 */ 67,
|
||||
/* FK02 */ 68,
|
||||
/* FK03 */ 69,
|
||||
/* FK04 */ 70,
|
||||
/* FK05 */ 71,
|
||||
/* FK06 */ 72,
|
||||
/* FK07 */ 73,
|
||||
/* FK08 */ 74,
|
||||
/* FK09 */ 75,
|
||||
/* FK10 */ 76,
|
||||
/* NMLK */ 77,
|
||||
/* SCLK */ 78,
|
||||
/* KP7 */ 79,
|
||||
/* KP8 */ 80,
|
||||
/* KP9 */ 81,
|
||||
/* KPSU */ 82,
|
||||
/* KP4 */ 83,
|
||||
/* KP5 */ 84,
|
||||
/* KP6 */ 85,
|
||||
/* KPAD */ 86,
|
||||
/* KP1 */ 87,
|
||||
/* KP2 */ 88,
|
||||
/* KP3 */ 89,
|
||||
/* KP0 */ 90,
|
||||
/* KPDL */ 91,
|
||||
/* SYRQ */ 107,
|
||||
/* II5D */ 0,
|
||||
/* LSGT */ 94,
|
||||
/* FK11 */ 95,
|
||||
/* FK12 */ 96,
|
||||
/* HOME */ 110,
|
||||
/* UP */ 111,
|
||||
/* PGUP */ 112,
|
||||
/* LEFT */ 113,
|
||||
/* II65 */ 0,
|
||||
/* RGHT */ 114,
|
||||
/* END */ 115,
|
||||
/* DOWN */ 116,
|
||||
/* PGDN */ 117,
|
||||
/* INS */ 118,
|
||||
/* DELE */ 119,
|
||||
/* KPEN */ 104,
|
||||
/* RCTL */ 105,
|
||||
/* PAUS */ 127,
|
||||
/* PRSC */ 107,
|
||||
/* KPDV */ 106,
|
||||
/* RALT */ 108,
|
||||
/* BRK */ 419,
|
||||
/* LWIN */ 133,
|
||||
/* RWIN */ 134,
|
||||
/* MENU */ 0,
|
||||
/* FK13 */ 191,
|
||||
/* FK14 */ 192,
|
||||
/* FK15 */ 193,
|
||||
/* XF86AudioMute */ 121,
|
||||
/* XF86AudioLowerVolume */ 122,
|
||||
/* XF86AudioRaiseVolume */ 123,
|
||||
/* LVL3 */ 92,
|
||||
/* ALT */ 204,
|
||||
/* KPEQ */ 125,
|
||||
/* SUPR */ 206,
|
||||
/* HYPR */ 207,
|
||||
/* XFER */ 0,
|
||||
/* I02 */ 0,
|
||||
/* NFER */ 0,
|
||||
/* I04 */ 0,
|
||||
/* AE13 */ 132,
|
||||
/* I06 */ 0,
|
||||
/* I07 */ 0,
|
||||
/* Cancel */ 136,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
/* XF86Launch1 */ 156,
|
||||
/* XF86Launch2 */ 157,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
/* XF86Mail */ 163,
|
||||
/* XF86Favorites */ 164,
|
||||
0,
|
||||
/* XF86Back */ 166,
|
||||
/* XF86Forward */ 167,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
/* XF86AudioNext */ 171,
|
||||
/* XF86AudioPlay */ 172,
|
||||
/* XF86AudioPrev */ 173,
|
||||
/* XF86AudioStop */ 174,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
/* XF86HomePage */ 180,
|
||||
/* XF86Reload */ 181,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
/* XF86Search */ 225,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
/* XF86AudioMedia */ 234,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
};
|
|
@ -42,135 +42,407 @@
|
|||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/XKBlib.h>
|
||||
#include <X11/extensions/XKBrules.h>
|
||||
#include <locale.h>
|
||||
#include <unistd.h>
|
||||
|
||||
extern int xfree86_to_evdev[137 - 8 + 1];
|
||||
#include "scancode.h"
|
||||
#include "xrdp_constants.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
// cppcheck doesn't always set this macro to something in double-quotes
|
||||
#if defined(__cppcheck__)
|
||||
#undef PACKAGE_VERSION
|
||||
#endif
|
||||
|
||||
#if !defined(PACKAGE_VERSION)
|
||||
#define PACKAGE_VERSION "???"
|
||||
#endif
|
||||
|
||||
#define NUM_STATES 9
|
||||
|
||||
#define KEYMAP_FILE_FORMAT_VERSION "2"
|
||||
|
||||
// Scancodes affected by numlock
|
||||
#define IS_KEYPAD_SCANCODE(s) \
|
||||
((s) >= XR_RDP_SCAN_MIN_NUMLOCK && (s) <= XR_RDP_SCAN_MAX_NUMLOCK)
|
||||
|
||||
#define MAX_COMMENTS 10
|
||||
|
||||
/**
|
||||
* Contains info about the current keyboard setting
|
||||
*/
|
||||
struct kbd_info
|
||||
{
|
||||
const char *programname;
|
||||
char text[256];
|
||||
char *displayname = NULL;
|
||||
char *outfname;
|
||||
const char *sections[8] =
|
||||
char *keycode_set; ///< See 'setxkbmap -v'
|
||||
char *rules; ///< See 'setxkbmap -query'
|
||||
char *model; ///< See 'setxkbmap -query'
|
||||
char *layout; ///< See 'setxkbmap -query'
|
||||
char *variant; ///< See 'setxkbmap -query'
|
||||
char *options; ///< See 'setxkbmap -query' (comma separated)
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* Print brief info about program usage and exit
|
||||
* @param programname Unqualified name of program
|
||||
* @param status Exit status
|
||||
*/
|
||||
static void
|
||||
usage(const char *programname, int status)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [ -k keycode_set] [-c comment] [-c comment...]"
|
||||
" out_filename\n", programname);
|
||||
fprintf(stderr, "Example: %s -r evdev -c \"en-US pc104 keyboard\""
|
||||
" /etc/xrdp/km-00000409.toml\n", programname);
|
||||
exit(status);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* Free a kbd_info struct
|
||||
* @param kbd_info struct to free. May be incomplete or NULL
|
||||
*/
|
||||
static void
|
||||
free_kbd_info(struct kbd_info *kbd_info)
|
||||
{
|
||||
if (kbd_info != NULL)
|
||||
{
|
||||
"noshift", "shift", "altgr", "shiftaltgr",
|
||||
"capslock", "capslockaltgr", "shiftcapslock", "shiftcapslockaltgr"
|
||||
free(kbd_info->keycode_set);
|
||||
free(kbd_info->rules);
|
||||
free(kbd_info->model);
|
||||
free(kbd_info->layout);
|
||||
free(kbd_info->variant);
|
||||
free(kbd_info->options);
|
||||
free(kbd_info);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* Queries the X server to get information about the current keyboard
|
||||
* @param dpy X11 Display
|
||||
* @param programname Unqualified name of program
|
||||
* @return kbd_info struct, or NULL
|
||||
*
|
||||
* The structure may be incomplete if some data could not be obtained
|
||||
*/
|
||||
static struct kbd_info *
|
||||
get_kbd_info(Display *dpy, const char *programname)
|
||||
{
|
||||
struct kbd_info *kbd_info;
|
||||
char *rules;
|
||||
XkbRF_VarDefsRec vd;
|
||||
XkbDescPtr kbdesc = NULL;
|
||||
|
||||
if ((kbd_info = (struct kbd_info *)malloc( sizeof(*kbd_info))) == NULL)
|
||||
{
|
||||
fprintf(stderr, "%s: Out of memory\n", programname);
|
||||
}
|
||||
else if ((kbdesc = XkbAllocKeyboard()) == NULL)
|
||||
{
|
||||
fprintf(stderr, "%s: unable to allocate keyboard desc\n",
|
||||
programname);
|
||||
free_kbd_info(kbd_info);
|
||||
kbd_info = NULL;
|
||||
}
|
||||
else if (XkbGetNames(dpy, XkbKeycodesNameMask, kbdesc) != Success)
|
||||
{
|
||||
fprintf(stderr, "%s: unable to obtain keycode name for keyboard\n",
|
||||
programname);
|
||||
free_kbd_info(kbd_info);
|
||||
kbd_info = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
char *symatom = XGetAtomName(dpy, kbdesc->names->keycodes);
|
||||
kbd_info->keycode_set = strdup(symatom);
|
||||
XFree(symatom);
|
||||
|
||||
if (XkbRF_GetNamesProp(dpy, &rules, &vd) == 0 || rules == NULL)
|
||||
{
|
||||
fprintf(stderr, "%s: Couldn't interpret %s property\n",
|
||||
programname, _XKB_RF_NAMES_PROP_ATOM);
|
||||
kbd_info->rules = NULL;
|
||||
kbd_info->model = NULL;
|
||||
kbd_info->layout = NULL;
|
||||
kbd_info->variant = NULL;
|
||||
kbd_info->options = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
kbd_info->rules = rules;
|
||||
kbd_info->model = vd.model;
|
||||
kbd_info->layout = vd.layout;
|
||||
kbd_info->variant = vd.variant;
|
||||
kbd_info->options = vd.options;
|
||||
}
|
||||
}
|
||||
|
||||
if (kbdesc != NULL)
|
||||
{
|
||||
XkbFreeKeyboard(kbdesc, 0, True);
|
||||
}
|
||||
|
||||
return kbd_info;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* Outputs a comment containing the last setxkbmap command
|
||||
*
|
||||
* @param outf Output file
|
||||
* @param kbd_info Keyboard info struct
|
||||
*
|
||||
*/
|
||||
static void
|
||||
output_setxkbmap_comment(FILE *outf, const struct kbd_info *kbd_info)
|
||||
{
|
||||
if (kbd_info->model != NULL || kbd_info->layout != NULL ||
|
||||
kbd_info->variant != NULL || kbd_info->options != NULL)
|
||||
{
|
||||
fprintf(outf, "# setxkbmap -rules %s", kbd_info->rules);
|
||||
if (kbd_info->model != NULL)
|
||||
{
|
||||
fprintf(outf, " -model %s", kbd_info->model);
|
||||
}
|
||||
if (kbd_info->layout != NULL)
|
||||
{
|
||||
fprintf(outf, " -layout %s", kbd_info->layout);
|
||||
}
|
||||
if (kbd_info->variant != NULL)
|
||||
{
|
||||
fprintf(outf, " -variant %s", kbd_info->variant);
|
||||
}
|
||||
if (kbd_info->options != NULL)
|
||||
{
|
||||
// Options is comma-separated, but to achieve the same effect
|
||||
// with the command we need to use multiple '-option' args
|
||||
char *optionstr = strdup(kbd_info->options);
|
||||
if (optionstr != NULL)
|
||||
{
|
||||
char *p = strtok(optionstr, ",");
|
||||
fprintf(outf, " -option \"\"");
|
||||
while (p != NULL)
|
||||
{
|
||||
fprintf(outf, " -option %s", p);
|
||||
p = strtok(NULL, ",");
|
||||
}
|
||||
free(optionstr);
|
||||
}
|
||||
}
|
||||
putc('\n', outf);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* Output a section of the keymap file
|
||||
* @param outf Output file
|
||||
* @param dpy X display
|
||||
* @param section name Section name (e.g. 'shift')
|
||||
* @param event_state Modifier state needed for XKeyPressedEvent
|
||||
*/
|
||||
static void
|
||||
output_file_section(FILE *outf,
|
||||
Display *dpy,
|
||||
const char *section_name,
|
||||
unsigned int event_state)
|
||||
{
|
||||
XKeyPressedEvent e =
|
||||
{
|
||||
.type = KeyPress,
|
||||
.serial = 16,
|
||||
.send_event = True,
|
||||
.display = dpy,
|
||||
.state = event_state,
|
||||
.same_screen = True
|
||||
};
|
||||
int states[8] = {0, 1, 0x80, 0x81, 2, 0x82, 3, 0x83};
|
||||
int i;
|
||||
int idx;
|
||||
int char_count;
|
||||
int nbytes = 0;
|
||||
int unicode;
|
||||
Display *dpy;
|
||||
KeySym ks;
|
||||
FILE *outf;
|
||||
XKeyPressedEvent e;
|
||||
const char *ksstr;
|
||||
unsigned short scancode;
|
||||
unsigned int iter = 0;
|
||||
char text[256];
|
||||
wchar_t wtext[256];
|
||||
XkbDescPtr kbdesc;
|
||||
char *symatom;
|
||||
int is_evdev;
|
||||
|
||||
int is_numlock_section = (strcmp(section_name, "numlock") == 0);
|
||||
|
||||
fprintf(outf, "\n[%s]\n", section_name);
|
||||
|
||||
while ((scancode = scancode_get_next(&iter)) != 0)
|
||||
{
|
||||
// Numlock state table can be very small
|
||||
if (is_numlock_section && !IS_KEYPAD_SCANCODE(scancode))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
e.keycode = scancode_to_keycode(scancode);
|
||||
nbytes = XLookupString(&e, text, 255, &ks, NULL);
|
||||
if (ks == NoSymbol)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
ksstr = XKeysymToString(ks);
|
||||
if (ksstr == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
text[nbytes] = 0;
|
||||
char_count = mbstowcs(wtext, text, 255);
|
||||
unicode = 0;
|
||||
|
||||
if (char_count == 1)
|
||||
{
|
||||
unicode = wtext[0];
|
||||
}
|
||||
|
||||
if (scancode > 0xff)
|
||||
{
|
||||
fputs("E0_", outf);
|
||||
}
|
||||
fprintf(outf, "%02X=\"%d", (scancode & 0xff), (int)ks);
|
||||
if (unicode != 0)
|
||||
{
|
||||
fprintf(outf, ":U+%04X", unicode);
|
||||
}
|
||||
fprintf(outf, "\" # %s\n", ksstr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* Main
|
||||
* @param argc Argument count
|
||||
* @param argv Pointers to arguments
|
||||
* @return 0 for success
|
||||
*/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *programname;
|
||||
int opt;
|
||||
char *displayname = NULL;
|
||||
char *outfname;
|
||||
const char *sections[NUM_STATES] =
|
||||
{
|
||||
"noshift", "shift", "altgr", "shiftaltgr",
|
||||
"capslock", "capslockaltgr", "shiftcapslock", "shiftcapslockaltgr",
|
||||
"numlock"
|
||||
};
|
||||
int states[NUM_STATES] = {0, 1, 0x80, 0x81, 2, 0x82, 3, 0x83, 0x10};
|
||||
int idx;
|
||||
Display *dpy = NULL;
|
||||
FILE *outf = NULL;
|
||||
const char *comment[MAX_COMMENTS] = {0};
|
||||
int comment_count = 0;
|
||||
const char *keycode_set = NULL;
|
||||
struct kbd_info *kbd_info = NULL;
|
||||
int status = 1;
|
||||
|
||||
setlocale(LC_CTYPE, "");
|
||||
programname = argv[0];
|
||||
|
||||
if (argc != 2)
|
||||
if (strrchr(argv[0], '/') != NULL)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s out_filename\n", programname);
|
||||
fprintf(stderr, "Example: %s /etc/xrdp/km-00000409.ini\n", programname);
|
||||
return 1;
|
||||
programname = strrchr(argv[0], '/') + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
programname = argv[0];
|
||||
}
|
||||
|
||||
outfname = argv[1];
|
||||
dpy = XOpenDisplay(displayname);
|
||||
while ((opt = getopt(argc, argv, "c:k:")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'c':
|
||||
if (comment_count < MAX_COMMENTS)
|
||||
{
|
||||
comment[comment_count++] = optarg;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'k':
|
||||
keycode_set = optarg;
|
||||
break;
|
||||
|
||||
default: /* '?' */
|
||||
usage(programname, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if ((optind + 1) != argc)
|
||||
{
|
||||
usage(programname, 1);
|
||||
}
|
||||
|
||||
outfname = argv[optind];
|
||||
|
||||
dpy = XOpenDisplay(displayname);
|
||||
if (!dpy)
|
||||
{
|
||||
fprintf(stderr, "%s: unable to open display '%s'\n",
|
||||
programname, XDisplayName(displayname));
|
||||
return 1;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
/* check whether evdev is used */
|
||||
kbdesc = XkbAllocKeyboard();
|
||||
if (!kbdesc)
|
||||
if ((kbd_info = get_kbd_info(dpy, programname)) == 0)
|
||||
{
|
||||
// An error has already been logged
|
||||
goto finish;
|
||||
}
|
||||
|
||||
// If the keycode set isn't specified, use the one returned
|
||||
// by the XKB extension
|
||||
if (keycode_set == NULL)
|
||||
{
|
||||
keycode_set = kbd_info->keycode_set;
|
||||
}
|
||||
|
||||
if (scancode_set_keycode_set(keycode_set) != 0)
|
||||
{
|
||||
fprintf(stderr, "%s: keycode set '%s' is not recognised\n",
|
||||
programname, keycode_set);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if ((outf = fopen(outfname, "w")) == NULL)
|
||||
{
|
||||
fprintf(stderr, "%s: unable to create file '%s'\n",
|
||||
programname, outfname);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
fprintf(outf, "# Created by %s V" PACKAGE_VERSION
|
||||
"\n# Key code set: %s\n",
|
||||
programname, keycode_set);
|
||||
|
||||
output_setxkbmap_comment(outf, kbd_info);
|
||||
|
||||
for (idx = 0; idx < comment_count; ++idx)
|
||||
{
|
||||
fprintf(outf, "# %s\n", comment[idx]);
|
||||
}
|
||||
|
||||
fprintf(outf, "\n[General]\nversion=" KEYMAP_FILE_FORMAT_VERSION "\n");
|
||||
|
||||
for (idx = 0; idx < NUM_STATES; idx++) /* Sections and states */
|
||||
{
|
||||
output_file_section(outf, dpy, sections[idx], states[idx]);
|
||||
}
|
||||
|
||||
status = 0; // Successful run
|
||||
|
||||
finish:
|
||||
free_kbd_info(kbd_info);
|
||||
if (dpy != NULL)
|
||||
{
|
||||
fprintf(stderr, "%s: unable to allocate keyboard desc\n",
|
||||
programname);
|
||||
XCloseDisplay(dpy);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (XkbGetNames(dpy, XkbKeycodesNameMask, kbdesc) != Success)
|
||||
if (outf != NULL)
|
||||
{
|
||||
fprintf(stderr, "%s: unable to obtain keycode name for keyboard\n",
|
||||
programname);
|
||||
XkbFreeKeyboard(kbdesc, 0, True);
|
||||
XCloseDisplay(dpy);
|
||||
return 1;
|
||||
fclose(outf);
|
||||
}
|
||||
|
||||
symatom = XGetAtomName(dpy, kbdesc->names->keycodes);
|
||||
is_evdev = !strncmp(symatom, "evdev", 5);
|
||||
XFree(symatom);
|
||||
XkbFreeKeyboard(kbdesc, 0, True);
|
||||
|
||||
outf = fopen(outfname, "w");
|
||||
|
||||
if (outf == NULL)
|
||||
{
|
||||
fprintf(stderr, "%s: unable to create file '%s'\n", programname, outfname);
|
||||
XCloseDisplay(dpy);
|
||||
return 1;
|
||||
}
|
||||
|
||||
memset(&e, 0, sizeof(e));
|
||||
e.type = KeyPress;
|
||||
e.serial = 16;
|
||||
e.send_event = True;
|
||||
e.display = dpy;
|
||||
e.same_screen = True;
|
||||
|
||||
for (idx = 0; idx < 8; idx++) /* Sections and states */
|
||||
{
|
||||
fprintf(outf, "[%s]\n", sections[idx]);
|
||||
e.state = states[idx];
|
||||
|
||||
for (i = 8; i < 256; i++) /* Keycodes */
|
||||
{
|
||||
if (is_evdev)
|
||||
{
|
||||
e.keycode = xfree86_to_evdev[i - 8];
|
||||
}
|
||||
else
|
||||
{
|
||||
e.keycode = i;
|
||||
}
|
||||
nbytes = XLookupString(&e, text, 255, &ks, NULL);
|
||||
if (ks == NoSymbol)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
text[nbytes] = 0;
|
||||
char_count = mbstowcs(wtext, text, 255);
|
||||
unicode = 0;
|
||||
|
||||
if (char_count == 1)
|
||||
{
|
||||
unicode = wtext[0];
|
||||
}
|
||||
|
||||
fprintf(outf, "Key%d=%d:%d\n", i, (int) ks, unicode);
|
||||
}
|
||||
|
||||
if (idx != 7)
|
||||
{
|
||||
fprintf(outf, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
XCloseDisplay(dpy);
|
||||
fclose(outf);
|
||||
return 0;
|
||||
return status;
|
||||
}
|
||||
|
|
|
@ -1,39 +1,70 @@
|
|||
Creating a new keymap file.
|
||||
---------------------------
|
||||
Keymap file description
|
||||
-----------------------
|
||||
|
||||
The keymap files are used by the xrdp login screen, and also when
|
||||
sending keyboard input to a VNC server.
|
||||
|
||||
The names of the files are of the format;
|
||||
|
||||
km-xxxxxxxx.ini
|
||||
km-xxxxxxxx.toml
|
||||
|
||||
where the xxxxxxxx is replaced by the hex number of the layout of interest.
|
||||
|
||||
The files have 8 sections;
|
||||
The files are TOML compatible, with 10 sections;
|
||||
|
||||
[noshift], [shift], [altgr], [shiftaltgr], [capslock], [capslockaltgr],
|
||||
[shiftcapslock], [shiftcapslockaltgr]
|
||||
[General], [noshift], [shift], [altgr], [shiftaltgr], [capslock],
|
||||
[capslockaltgr], [shiftcapslock], [shiftcapslockaltgr], [numlock]
|
||||
|
||||
In each section there are multiple lines for each key.
|
||||
The [General] section contains information about the file. All other
|
||||
sections contain key mappings corresponding to the state of the modifier
|
||||
keys when the key is pressed.
|
||||
|
||||
An example line looks like;
|
||||
|
||||
Key10=49:49
|
||||
<RDP scancode>="<KeySym>[:<unicode>]" # comment
|
||||
|
||||
In this line, 10 is the X11 scancode, the first 49 is the keysym value,
|
||||
the second 49 if the unicode value of the key. This is the definition
|
||||
for the 'noshift' '1' key on a en-us keyboard. In this case, the keysym
|
||||
and the unicode value are the same.
|
||||
RDP scancode
|
||||
------------
|
||||
The RDP scancode is the code received from the RDP client for each
|
||||
key. RDP scancodes are more-or-less the same as Windows scancodes,
|
||||
or "Scan Code Set 1" key-down values.
|
||||
|
||||
Here is an example where they are not;
|
||||
Example scancodes might be '1C' for the enter key on most European
|
||||
keyboards, or 'E0 1C' for the number pad enter key.
|
||||
|
||||
This is the definition for the backspace key;
|
||||
Key22=65288:8
|
||||
A good website to consult for scancodes for a wide range of keyboards is
|
||||
https://kbdlayout.info/
|
||||
|
||||
And this is the star on the keypad;
|
||||
Key63=65450:42
|
||||
KeySym
|
||||
------
|
||||
The KeySym is a value used by the X server as an abstraction of the
|
||||
engraving on the key being pressed. It is needed to interact with the
|
||||
VNC server.
|
||||
|
||||
To create a new file run "xrdp-genkeymap <filename>"
|
||||
Unicode
|
||||
-------
|
||||
Keys which generate a character when pressed have this value added.
|
||||
This is used by the xrdp login screen.
|
||||
|
||||
Example: ./xrdp-genkeymap /etc/xrdp/km-00000409.ini
|
||||
Comment
|
||||
-------
|
||||
For generated keymap files, the comment is the name of the X11 KeySym
|
||||
for the key. This makes it a lot easier to see what is going on in
|
||||
the file.
|
||||
|
||||
Creating a new file
|
||||
-------------------
|
||||
|
||||
To create a new file:-
|
||||
1) Start an X server
|
||||
2) Use the 'setxkbmap' command to get the keyboard configured
|
||||
for the X server. Currently this has to use the 'evdev' rules so
|
||||
that xrdp and the X server agree on the low-level X11 keycodes to
|
||||
be used for the keys.
|
||||
3) Run the 'xrdp-genkeymap' command to extract the keyboard
|
||||
mappings
|
||||
|
||||
Example: ./xrdp-genkeymap /etc/xrdp/km-00000409.toml
|
||||
|
||||
Note: You need to have enough rights to be able to write to the
|
||||
/etc/xrdp directory.
|
||||
|
@ -41,3 +72,10 @@ Note: You need to have enough rights to be able to write to the
|
|||
Alternatively, create the keymap file in a directory of your choice, then
|
||||
copy or move it over to /etc/xrdp using sudo/su.
|
||||
|
||||
Using the X server of your current session may not be a good idea, as
|
||||
session and window managers can interfere with key bindings. A good option
|
||||
is to use an 'Xvfb' dummy X server to do this.
|
||||
|
||||
See also the dump_keymaps.sh script which auto-generates many keymap
|
||||
files for the xrdp distribution. Consider adding your keyboard into this
|
||||
list.
|
||||
|
|
Loading…
Reference in New Issue