From: Matteo Bruni <mbruni@codeweavers.com> For large parts lifted from Rémi's winewayland commit d64ea8e4a6c93ba77208cb680b91dc0c2830049d. --- configure | 202 ++++++++++++++++++--------------- configure.ac | 8 +- dlls/winex11.drv/Makefile.in | 4 +- dlls/winex11.drv/keyboard.c | 188 +++++++++++++++++++++++++++++- dlls/winex11.drv/x11drv.h | 1 + dlls/winex11.drv/x11drv_main.c | 2 +- include/config.h.in | 3 + 7 files changed, 306 insertions(+), 102 deletions(-) diff --git a/configure b/configure index d8690c5dd0c..13883909a18 100755 --- a/configure +++ b/configure @@ -700,13 +700,13 @@ PCSCLITE_LIBS PCAP_LIBS WAYLAND_EGL_LIBS WAYLAND_EGL_CFLAGS -XKBREGISTRY_LIBS -XKBREGISTRY_CFLAGS XKBCOMMON_LIBS XKBCOMMON_CFLAGS WAYLAND_SCANNER WAYLAND_CLIENT_LIBS WAYLAND_CLIENT_CFLAGS +XKBREGISTRY_LIBS +XKBREGISTRY_CFLAGS X_LIBS X_CFLAGS CPP @@ -1901,12 +1901,12 @@ EGL_CFLAGS EGL_LIBS XMKMF CPP +XKBREGISTRY_CFLAGS +XKBREGISTRY_LIBS WAYLAND_CLIENT_CFLAGS WAYLAND_CLIENT_LIBS XKBCOMMON_CFLAGS XKBCOMMON_LIBS -XKBREGISTRY_CFLAGS -XKBREGISTRY_LIBS WAYLAND_EGL_CFLAGS WAYLAND_EGL_LIBS INOTIFY_CFLAGS @@ -2761,6 +2761,10 @@ Some influential environment variables: EGL_LIBS Linker flags for egl, overriding pkg-config XMKMF Path to xmkmf, Makefile generator for X Window System CPP C preprocessor + XKBREGISTRY_CFLAGS + C compiler flags for xkbregistry, overriding pkg-config + XKBREGISTRY_LIBS + Linker flags for xkbregistry, overriding pkg-config WAYLAND_CLIENT_CFLAGS C compiler flags for wayland-client, overriding pkg-config WAYLAND_CLIENT_LIBS @@ -2769,10 +2773,6 @@ Some influential environment variables: C compiler flags for xkbcommon, overriding pkg-config XKBCOMMON_LIBS Linker flags for xkbcommon, overriding pkg-config - XKBREGISTRY_CFLAGS - C compiler flags for xkbregistry, overriding pkg-config - XKBREGISTRY_LIBS - Linker flags for xkbregistry, overriding pkg-config WAYLAND_EGL_CFLAGS C compiler flags for wayland-egl, overriding pkg-config WAYLAND_EGL_LIBS @@ -16874,6 +16874,105 @@ else X_LIBS="" fi +if test "x$have_x" != "xno" || "x$with_wayland" != "xno" + then + rm -f conftest.err +if ${XKBREGISTRY_CFLAGS:+false} : +then : + if test ${PKG_CONFIG+y} +then : + XKBREGISTRY_CFLAGS=`$PKG_CONFIG --cflags xkbregistry 2>conftest.err` +fi +fi + +if ${XKBREGISTRY_LIBS:+false} : +then : + if test ${PKG_CONFIG+y} +then : + XKBREGISTRY_LIBS=`$PKG_CONFIG --libs xkbregistry 2>/dev/null` +fi +fi + + +printf "%s\n" "$as_me:${as_lineno-$LINENO}: xkbregistry cflags: $XKBREGISTRY_CFLAGS" >&5 +printf "%s\n" "$as_me:${as_lineno-$LINENO}: xkbregistry libs: $XKBREGISTRY_LIBS" >&5 +if test -s conftest.err; then + printf %s "$as_me:${as_lineno-$LINENO}: xkbregistry errors: " >&5 + cat conftest.err >&5 +fi +rm -f conftest.err +if test -n "$XKBREGISTRY_CFLAGS$XKBREGISTRY_LIBS" +then : + ac_save_CPPFLAGS=$CPPFLAGS +CPPFLAGS="$CPPFLAGS $XKBREGISTRY_CFLAGS" +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lxkbregistry" >&5 +printf %s "checking for -lxkbregistry... " >&6; } +if test ${ac_cv_lib_soname_xkbregistry+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) ac_check_soname_save_LIBS=$LIBS +LIBS="-lxkbregistry $XKBREGISTRY_LIBS $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. + The 'extern "C"' is for builds by C++ compilers; + although this is not generally supported in C code supporting it here + has little cost and some practical benefit (sr 110532). */ +#ifdef __cplusplus +extern "C" +#endif +char rxkb_context_new (void); +int +main (void) +{ +return rxkb_context_new (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + case "$LIBEXT" in + dll) ac_cv_lib_soname_xkbregistry=`$ac_cv_path_LDD conftest.exe | grep "xkbregistry" | sed -e "s/dll.*/dll/"';2,$d'` ;; + dylib) ac_cv_lib_soname_xkbregistry=`$OTOOL -L conftest$ac_exeext | grep "libxkbregistry\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libxkbregistry\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; + *) ac_cv_lib_soname_xkbregistry=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libxkbregistry\\.$LIBEXT" | sed -e "s/^.*\\[\\(libxkbregistry\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` + if ${ac_cv_lib_soname_xkbregistry:+false} : +then : + ac_cv_lib_soname_xkbregistry=`$LDD conftest$ac_exeext | grep "libxkbregistry\\.$LIBEXT" | sed -e "s/^.*\(libxkbregistry\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` +fi ;; + esac +else case e in #( + e) ac_cv_lib_soname_xkbregistry= ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + LIBS=$ac_check_soname_save_LIBS ;; +esac +fi +if ${ac_cv_lib_soname_xkbregistry:+false} : +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 +printf "%s\n" "not found" >&6; } + XKBREGISTRY_LIBS="" +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_xkbregistry" >&5 +printf "%s\n" "$ac_cv_lib_soname_xkbregistry" >&6; } + +printf "%s\n" "#define SONAME_LIBXKBREGISTRY \"$ac_cv_lib_soname_xkbregistry\"" >>confdefs.h + + : ;; +esac +fi +CPPFLAGS=$ac_save_CPPFLAGS +fi + + fi + if test "x$with_wayland" != "xno" then rm -f conftest.err @@ -17090,89 +17189,6 @@ else case e in #( esac fi -CPPFLAGS=$ac_save_CPPFLAGS -fi - - rm -f conftest.err -if ${XKBREGISTRY_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - XKBREGISTRY_CFLAGS=`$PKG_CONFIG --cflags xkbregistry 2>conftest.err` -fi -fi - -if ${XKBREGISTRY_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - XKBREGISTRY_LIBS=`$PKG_CONFIG --libs xkbregistry 2>/dev/null` -fi -fi - - -printf "%s\n" "$as_me:${as_lineno-$LINENO}: xkbregistry cflags: $XKBREGISTRY_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: xkbregistry libs: $XKBREGISTRY_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: xkbregistry errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -if test -n "$XKBREGISTRY_CFLAGS$XKBREGISTRY_LIBS" -then : - ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $XKBREGISTRY_CFLAGS" -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for rxkb_context_new in -lxkbregistry" >&5 -printf %s "checking for rxkb_context_new in -lxkbregistry... " >&6; } -if test ${ac_cv_lib_xkbregistry_rxkb_context_new+y} -then : - printf %s "(cached) " >&6 -else case e in #( - e) ac_check_lib_save_LIBS=$LIBS -LIBS="-lxkbregistry $XKBREGISTRY_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. - The 'extern "C"' is for builds by C++ compilers; - although this is not generally supported in C code supporting it here - has little cost and some practical benefit (sr 110532). */ -#ifdef __cplusplus -extern "C" -#endif -char rxkb_context_new (void); -int -main (void) -{ -return rxkb_context_new (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_xkbregistry_rxkb_context_new=yes -else case e in #( - e) ac_cv_lib_xkbregistry_rxkb_context_new=no ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS ;; -esac -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_xkbregistry_rxkb_context_new" >&5 -printf "%s\n" "$ac_cv_lib_xkbregistry_rxkb_context_new" >&6; } -if test "x$ac_cv_lib_xkbregistry_rxkb_context_new" = xyes -then : - : -else case e in #( - e) XKBREGISTRY_LIBS="" ;; -esac -fi - CPPFLAGS=$ac_save_CPPFLAGS fi @@ -25174,13 +25190,13 @@ XMKMF = $XMKMF CPP = $CPP X_CFLAGS = $X_CFLAGS X_LIBS = $X_LIBS +XKBREGISTRY_CFLAGS = $XKBREGISTRY_CFLAGS +XKBREGISTRY_LIBS = $XKBREGISTRY_LIBS WAYLAND_CLIENT_CFLAGS = $WAYLAND_CLIENT_CFLAGS WAYLAND_CLIENT_LIBS = $WAYLAND_CLIENT_LIBS WAYLAND_SCANNER = $WAYLAND_SCANNER XKBCOMMON_CFLAGS = $XKBCOMMON_CFLAGS XKBCOMMON_LIBS = $XKBCOMMON_LIBS -XKBREGISTRY_CFLAGS = $XKBREGISTRY_CFLAGS -XKBREGISTRY_LIBS = $XKBREGISTRY_LIBS WAYLAND_EGL_CFLAGS = $WAYLAND_EGL_CFLAGS WAYLAND_EGL_LIBS = $WAYLAND_EGL_LIBS PCAP_LIBS = $PCAP_LIBS diff --git a/configure.ac b/configure.ac index f35ac4376d9..c90fe7d888c 100644 --- a/configure.ac +++ b/configure.ac @@ -1433,6 +1433,12 @@ else X_LIBS="" fi +if test "x$have_x" != "xno" || "x$with_wayland" != "xno" + then + WINE_PACKAGE_FLAGS(XKBREGISTRY,[xkbregistry],,,, + [WINE_CHECK_SONAME(xkbregistry,rxkb_context_new,[:],[XKBREGISTRY_LIBS=""],[$XKBREGISTRY_LIBS])]) + fi + if test "x$with_wayland" != "xno" then WINE_PACKAGE_FLAGS(WAYLAND_CLIENT,[wayland-client],,,, @@ -1443,8 +1449,6 @@ then [WAYLAND_CLIENT_LIBS=""],[$WAYLAND_CLIENT_LIBS])])]) WINE_PACKAGE_FLAGS(XKBCOMMON,[xkbcommon],,,, [AC_CHECK_LIB(xkbcommon,xkb_context_new,[:],[XKBCOMMON_LIBS=""],[$XKBCOMMON_LIBS])]) - WINE_PACKAGE_FLAGS(XKBREGISTRY,[xkbregistry],,,, - [AC_CHECK_LIB(xkbregistry,rxkb_context_new,[:],[XKBREGISTRY_LIBS=""],[$XKBREGISTRY_LIBS])]) if test "x$with_opengl" != "xno" then WINE_PACKAGE_FLAGS(WAYLAND_EGL,[wayland-egl],,,, diff --git a/dlls/winex11.drv/Makefile.in b/dlls/winex11.drv/Makefile.in index f9ddd05175b..31768e670da 100644 --- a/dlls/winex11.drv/Makefile.in +++ b/dlls/winex11.drv/Makefile.in @@ -1,7 +1,7 @@ MODULE = winex11.drv UNIXLIB = winex11.so -UNIX_CFLAGS = $(X_CFLAGS) -UNIX_LIBS = -lwin32u $(X_LIBS) $(PTHREAD_LIBS) -lm +UNIX_CFLAGS = $(X_CFLAGS) $(XKBREGISTRY_CFLAGS) +UNIX_LIBS = -lwin32u $(X_LIBS) $(XKBREGISTRY_LIBS) $(PTHREAD_LIBS) -lm VER_FILEDESCRIPTION_STR = "Wine X11 driver" diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index 898286a5e6e..73c605b71ba 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -36,6 +36,10 @@ #include <X11/Xutil.h> #include <X11/XKBlib.h> +#ifdef SONAME_LIBXKBREGISTRY +#include <xkbcommon/xkbregistry.h> +#endif + #include <ctype.h> #include <stdarg.h> #include <string.h> @@ -939,6 +943,9 @@ static const struct { {0, NULL, NULL, NULL, NULL} /* sentinel */ }; static unsigned kbd_layout=0; /* index into above table of layouts */ +#ifdef SONAME_LIBXKBREGISTRY +static struct rxkb_context *rxkb_context; +#endif /* maybe more of these scancodes should be extended? */ /* extended must be set for ALT_R, CTRL_R, @@ -1426,6 +1433,152 @@ BOOL X11DRV_KeyEvent( HWND hwnd, XEvent *xev ) return TRUE; } +#ifdef SONAME_LIBXKBREGISTRY +static BOOL find_xkb_layout_variant(const char *name, const char **layout, const char **variant) +{ + struct rxkb_layout *iter; + + for (iter = rxkb_layout_first(rxkb_context); iter; iter = rxkb_layout_next(iter)) + { + const char *desc = rxkb_layout_get_description(iter); + + if (desc && !strcmp(name, desc)) + { + *layout = rxkb_layout_get_name(iter); + *variant = rxkb_layout_get_variant(iter); + return TRUE; + } + } + + return FALSE; +} + +static const struct layout_id_map_entry +{ + const char *name; + LANGID langid; +} layout_ids[] = +{ + { "af", MAKELANGID(LANG_DARI, SUBLANG_DEFAULT) }, + { "al", MAKELANGID(LANG_ALBANIAN, SUBLANG_DEFAULT) }, + { "am", MAKELANGID(LANG_ARMENIAN, SUBLANG_DEFAULT) }, + { "ara", MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT) }, + { "at", MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN_AUSTRIAN) }, + { "az", MAKELANGID(LANG_AZERBAIJANI, SUBLANG_DEFAULT) }, + { "au", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_AUS) }, + { "ba", MAKELANGID(LANG_BOSNIAN, SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_CYRILLIC) }, + { "bd", MAKELANGID(LANG_BANGLA, SUBLANG_DEFAULT) }, + { "be", MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH_BELGIAN) }, + { "bg", MAKELANGID(LANG_BULGARIAN, SUBLANG_DEFAULT) }, + { "br", MAKELANGID(LANG_PORTUGUESE, 2) }, + { "brai", MAKELANGID(LANG_NEUTRAL, SUBLANG_CUSTOM_DEFAULT) }, + { "bt", MAKELANGID(LANG_TIBETAN, 3) }, + { "bw", MAKELANGID(LANG_TSWANA, SUBLANG_TSWANA_BOTSWANA) }, + { "by", MAKELANGID(LANG_BELARUSIAN, SUBLANG_DEFAULT) }, + { "ca", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_CAN) }, + { "cd", MAKELANGID(LANG_FRENCH, SUBLANG_CUSTOM_UNSPECIFIED) }, + { "ch", MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN_SWISS) }, + { "cm", MAKELANGID(LANG_FRENCH, 11) }, + { "cn", MAKELANGID(LANG_CHINESE, SUBLANG_DEFAULT) }, + { "cz", MAKELANGID(LANG_CZECH, SUBLANG_DEFAULT) }, + { "de", MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT) }, + { "dk", MAKELANGID(LANG_DANISH, SUBLANG_DEFAULT) }, + { "dz", MAKELANGID(LANG_TAMAZIGHT, SUBLANG_TAMAZIGHT_ALGERIA_LATIN) }, + { "ee", MAKELANGID(LANG_ESTONIAN, SUBLANG_DEFAULT) }, + { "epo", MAKELANGID(LANG_NEUTRAL, SUBLANG_CUSTOM_DEFAULT) }, + { "es", MAKELANGID(LANG_SPANISH, SUBLANG_DEFAULT) }, + { "et", MAKELANGID(LANG_AMHARIC, SUBLANG_DEFAULT) }, + { "fi", MAKELANGID(LANG_FINNISH, SUBLANG_DEFAULT) }, + { "fo", MAKELANGID(LANG_FAEROESE, SUBLANG_DEFAULT) }, + { "fr", MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT) }, + { "gb", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_UK) }, + { "ge", MAKELANGID(LANG_GEORGIAN, SUBLANG_DEFAULT) }, + { "gh", MAKELANGID(LANG_ENGLISH, SUBLANG_CUSTOM_UNSPECIFIED) }, + { "gn", MAKELANGID(LANG_NEUTRAL, SUBLANG_CUSTOM_DEFAULT) }, + { "gr", MAKELANGID(LANG_GREEK, SUBLANG_DEFAULT) }, + { "hr", MAKELANGID(LANG_CROATIAN, SUBLANG_DEFAULT) }, + { "hu", MAKELANGID(LANG_HUNGARIAN, SUBLANG_DEFAULT) }, + { "id", MAKELANGID(LANG_INDONESIAN, SUBLANG_DEFAULT) }, + { "ie", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_EIRE) }, + { "il", MAKELANGID(LANG_HEBREW, SUBLANG_DEFAULT) }, + { "in", MAKELANGID(LANG_HINDI, SUBLANG_DEFAULT) }, + { "iq", MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_IRAQ) }, + { "ir", MAKELANGID(LANG_PERSIAN, SUBLANG_DEFAULT) }, + { "is", MAKELANGID(LANG_ICELANDIC, SUBLANG_DEFAULT) }, + { "it", MAKELANGID(LANG_ITALIAN, SUBLANG_DEFAULT) }, + { "jp", MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT) }, + { "ke", MAKELANGID(LANG_NEUTRAL, SUBLANG_CUSTOM_DEFAULT) }, + { "kg", MAKELANGID(LANG_KYRGYZ, SUBLANG_DEFAULT) }, + { "kh", MAKELANGID(LANG_KHMER, SUBLANG_DEFAULT) }, + { "kr", MAKELANGID(LANG_KOREAN, SUBLANG_DEFAULT) }, + { "kz", MAKELANGID(LANG_KAZAK, SUBLANG_DEFAULT) }, + { "la", MAKELANGID(LANG_LAO, SUBLANG_DEFAULT) }, + { "latam", MAKELANGID(LANG_SPANISH, SUBLANG_CUSTOM_UNSPECIFIED) }, + { "lk", MAKELANGID(LANG_SINHALESE, SUBLANG_DEFAULT) }, + { "lt", MAKELANGID(LANG_LITHUANIAN, SUBLANG_DEFAULT) }, + { "lv", MAKELANGID(LANG_LATVIAN, SUBLANG_DEFAULT) }, + { "ma", MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_MOROCCO) }, + { "mao", MAKELANGID(LANG_MAORI, SUBLANG_DEFAULT) }, + { "md", MAKELANGID(LANG_ROMANIAN, SUBLANG_CUSTOM_UNSPECIFIED) }, + { "me", MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_MONTENEGRO_LATIN) }, + { "mk", MAKELANGID(LANG_MACEDONIAN, SUBLANG_DEFAULT) }, + { "ml", MAKELANGID(LANG_NEUTRAL, SUBLANG_CUSTOM_DEFAULT) }, + { "mm", MAKELANGID(0x55 /*LANG_BURMESE*/, SUBLANG_DEFAULT) }, + { "mn", MAKELANGID(LANG_MONGOLIAN, SUBLANG_DEFAULT) }, + { "mt", MAKELANGID(LANG_MALTESE, SUBLANG_DEFAULT) }, + { "mv", MAKELANGID(LANG_DIVEHI, SUBLANG_DEFAULT) }, + { "my", MAKELANGID(LANG_MALAY, SUBLANG_DEFAULT) }, + { "ng", MAKELANGID(LANG_ENGLISH, SUBLANG_CUSTOM_UNSPECIFIED) }, + { "nl", MAKELANGID(LANG_DUTCH, SUBLANG_DEFAULT) }, + { "no", MAKELANGID(LANG_NORWEGIAN, SUBLANG_DEFAULT) }, + { "np", MAKELANGID(LANG_NEPALI, SUBLANG_DEFAULT) }, + { "ph", MAKELANGID(LANG_FILIPINO, SUBLANG_DEFAULT) }, + { "pk", MAKELANGID(LANG_URDU, SUBLANG_DEFAULT) }, + { "pl", MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT) }, + { "pt", MAKELANGID(LANG_PORTUGUESE, SUBLANG_DEFAULT) }, + { "ro", MAKELANGID(LANG_ROMANIAN, SUBLANG_DEFAULT) }, + { "rs", MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_LATIN) }, + { "ru", MAKELANGID(LANG_RUSSIAN, SUBLANG_DEFAULT) }, + { "se", MAKELANGID(LANG_SWEDISH, SUBLANG_DEFAULT) }, + { "si", MAKELANGID(LANG_SLOVENIAN, SUBLANG_DEFAULT) }, + { "sk", MAKELANGID(LANG_SLOVAK, SUBLANG_DEFAULT) }, + { "sn", MAKELANGID(LANG_WOLOF, SUBLANG_DEFAULT) }, + { "sy", MAKELANGID(LANG_SYRIAC, SUBLANG_DEFAULT) }, + { "tg", MAKELANGID(LANG_FRENCH, SUBLANG_CUSTOM_UNSPECIFIED) }, + { "th", MAKELANGID(LANG_THAI, SUBLANG_DEFAULT) }, + { "tj", MAKELANGID(LANG_TAJIK, SUBLANG_DEFAULT) }, + { "tm", MAKELANGID(LANG_TURKMEN, SUBLANG_DEFAULT) }, + { "tr", MAKELANGID(LANG_TURKISH, SUBLANG_DEFAULT) }, + { "tw", MAKELANGID(LANG_CHINESE, SUBLANG_CUSTOM_UNSPECIFIED) }, + { "tz", MAKELANGID(LANG_SWAHILI, SUBLANG_CUSTOM_UNSPECIFIED) }, + { "ua", MAKELANGID(LANG_UKRAINIAN, SUBLANG_DEFAULT) }, + { "us", MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT) }, + { "uz", MAKELANGID(LANG_UZBEK, 2) }, + { "vn", MAKELANGID(LANG_VIETNAMESE, SUBLANG_DEFAULT) }, + { "za", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_SOUTH_AFRICA) }, +}; + +static int xkb_layout_cmp(const void *key, const void *element) +{ + const struct layout_id_map_entry *entry = element; + + return strcmp(key, entry->name); +} + +static LANGID x11drv_langid_from_xkb_layout(const char *layout) +{ + struct layout_id_map_entry *entry; + + entry = bsearch(layout, layout_ids, ARRAY_SIZE(layout_ids), sizeof(*layout_ids), xkb_layout_cmp); + if (entry) + return entry->langid; + + FIXME("Unknown layout language %s\n", debugstr_a(layout)); + return MAKELANGID(LANG_NEUTRAL, SUBLANG_CUSTOM_UNSPECIFIED); +}; + +#endif + /********************************************************************** * X11DRV_KEYBOARD_DetectLayout * @@ -1808,9 +1961,14 @@ void X11DRV_InitKeyboard( Display *display ) XModifierKeymap *mmp; KeyCode *kcp; XkbStateRec xkb_state; - char *xkb_group_names[4]; - unsigned int i, xkb_group, xkb_group_count; +#ifdef SONAME_LIBXKBREGISTRY + const char *layout, *variant = NULL; + char *xkb_group_names[4], *name; + unsigned int xkb_group_count; +#endif XkbDescRec *xkb_desc; + unsigned int i, xkb_group; + LANGID lang = 0; Status s; pthread_mutex_lock( &kbd_mutex ); @@ -1852,6 +2010,7 @@ void X11DRV_InitKeyboard( Display *display ) xkb_desc = XkbGetMap( display, XkbAllClientInfoMask, XkbUseCoreKbd ); if (xkb_desc) { +#ifdef SONAME_LIBXKBREGISTRY XkbGetNames( display, XkbGroupNamesMask, xkb_desc ); for (i = 0; i < ARRAY_SIZE(xkb_desc->names->groups); i++) { @@ -1862,16 +2021,24 @@ void X11DRV_InitKeyboard( Display *display ) if (!XGetAtomNames( display, xkb_desc->names->groups, xkb_group_count, xkb_group_names )) xkb_group_count = 0; for (i = 0; i < xkb_group_count; i++) - { TRACE("group %u name %s\n", i, debugstr_a(xkb_group_names[i])); + name = xkb_group_names[xkb_state.group]; + if (!name || !find_xkb_layout_variant(name, &layout, &variant)) layout = "us"; + TRACE("Found layout %u name %s -> %s:%s\n", xkb_group, name, layout, variant); + lang = x11drv_langid_from_xkb_layout(layout); + TRACE("lang %#x\n", lang); + for (i = 0; i < xkb_group_count; i++) XFree( xkb_group_names[i] ); - } +#endif XkbFreeKeyboard( xkb_desc, 0, True ); } X11DRV_KEYBOARD_DetectLayout( display, mmp, xkb_group ); XFreeModifiermap(mmp); + if (lang && lang != main_key_tab[kbd_layout].lcid) + WARN("LANGID from Xkb group name and LANGID detected by X11DRV_KEYBOARD_DetectLayout don't match!\n"); + x11drv_init_layout( display ); pthread_mutex_unlock( &kbd_mutex ); @@ -1913,6 +2080,19 @@ BOOL X11DRV_MappingNotify( HWND dummy, XEvent *event ) return TRUE; } +void x11drv_xkb_init( Display *display ) +{ + XkbUseExtension( display, NULL, NULL ); + +#ifdef SONAME_LIBXKBREGISTRY + if (!(rxkb_context = rxkb_context_new(RXKB_CONTEXT_NO_FLAGS)) + || !rxkb_context_parse_default_ruleset(rxkb_context)) + { + ERR("Failed to parse default Xkb ruleset\n"); + return; + } +#endif +} /*********************************************************************** * VkKeyScanEx (X11DRV.@) diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 8b0c0a62f91..98bc4fd8ecc 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -755,6 +755,7 @@ extern void ungrab_clipping_window(void); extern void move_resize_window( HWND hwnd, int dir, POINT pos ); extern void X11DRV_InitKeyboard( Display *display ); extern BOOL X11DRV_ProcessEvents( DWORD mask ); +extern void x11drv_xkb_init( Display *display ); typedef int (*x11drv_error_callback)( Display *display, XErrorEvent *event, void *arg ); diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index 1bdcd282f2e..556057295a8 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -672,7 +672,7 @@ NTSTATUS __wine_unix_lib_init(void) #endif x11drv_xinput2_load(); - XkbUseExtension( gdi_display, NULL, NULL ); + x11drv_xkb_init( gdi_display ); X11DRV_InitKeyboard( gdi_display ); if (use_xim) use_xim = xim_init( input_style ); diff --git a/include/config.h.in b/include/config.h.in index 0343acc8d36..551771eaa6a 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -810,6 +810,9 @@ /* Define to the soname of the libXinerama library. */ #undef SONAME_LIBXINERAMA +/* Define to the soname of the libxkbregistry library. */ +#undef SONAME_LIBXKBREGISTRY + /* Define to the soname of the libXrandr library. */ #undef SONAME_LIBXRANDR -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10550