Browse Source

Merge pull request #154 from dwimsey/feature/deprecatedfix-XKeycodeToKeysym

Removes usage of deprecated XKeycodeToKeysym function in X11 example.
David Wimsey 11 years ago
parent
commit
d3883c57e1

+ 6 - 0
Build/CMakeLists.txt

@@ -257,6 +257,12 @@ if(BUILD_SAMPLES)
     	find_package(X11 REQUIRED)
         if (X11_FOUND)
         	list(APPEND sample_LIBRARIES ${X11_LIBRARIES})
+		# shell/src/x11/InputX11.cpp:InitialiseX11Keymap uses Xkb if
+		# possible instead of XGetKeyboardMapping for performance
+		if(X11_Xkb_FOUND)
+			FIND_PACKAGE_MESSAGE(X11 "Found X11 KBlib: ${X11_X11_LIB}" "[${X11_X11_LIB}][${X11_XkbINCLUDE_DIR}]")
+			add_definitions(-DHAS_X11XKBLIB)
+		endif()
         endif()
     endif()
    

+ 5 - 0
Samples/shell/include/x11/InputX11.h

@@ -47,6 +47,11 @@ public:
 
 	/// Process the windows message
 	static void ProcessXEvent(Display* display, const XEvent& event);
+
+	// Initialises Xkb extension if available or reads keymap from X11
+	// server otherwise.  This is internal to the X11 subsystem and
+	// has nothing to do with libRocket's mapping.
+	static void InitialiseX11Keymap(Display *display);
 };
 
 #endif

+ 77 - 8
Samples/shell/src/x11/InputX11.cpp

@@ -31,6 +31,9 @@
 #include <Rocket/Debugger.h>
 #include <Shell.h>
 #include <X11/Xlib.h>
+#ifdef HAS_X11XKBLIB
+#include <X11/XKBlib.h>
+#endif // HAS_X11XKBLIB
 #include <X11/keysym.h>
 #include <X11/Xutil.h>
 
@@ -40,6 +43,13 @@ static int GetKeyModifierState(int x_state);
 static const int KEYMAP_SIZE = 256;
 static Rocket::Core::Input::KeyIdentifier key_identifier_map[KEYMAP_SIZE];
 
+#ifdef HAS_X11XKBLIB
+static bool has_xkblib = false;
+#endif // HAS_X11XKBLIB
+
+static int min_keycode, max_keycode, keysyms_per_keycode;
+static KeySym *x11_key_mapping = NULL;
+
 bool InputX11::Initialise()
 {
 	InitialiseKeymap();
@@ -50,6 +60,35 @@ void InputX11::Shutdown()
 {
 }
 
+void InputX11::InitialiseX11Keymap(Display *display)
+{
+	ROCKET_ASSERT(display != NULL);
+
+#ifdef HAS_X11XKBLIB
+	int opcode_rtrn = -1;
+	int event_rtrn = -1;
+	int error_rtrn = -1;
+	int major_in_out = -1;
+	int minor_in_out = -1;
+
+	// Xkb extension may not exist in the server.  This checks for its
+	// existence and initializes the extension if available.
+	has_xkblib = XkbQueryExtension(display, &opcode_rtrn, &event_rtrn, &error_rtrn, &major_in_out, &minor_in_out);
+
+	// if Xkb isn't available, fall back to using XGetKeyboardMapping, 
+	// which may occur if libRocket is compiled with Xkb support but the
+	// server doesn't support it.  This occurs with older X11 servers or
+	// virtual framebuffers such as x11vnc server.
+	if(!has_xkblib)
+#endif // HAS_X11XKBLIB
+	{
+		XDisplayKeycodes(display, &min_keycode, &max_keycode);
+
+		ROCKET_ASSERT(x11_key_mapping != NULL);
+		x11_key_mapping = XGetKeyboardMapping(display, min_keycode, max_keycode + 1 - min_keycode, &keysyms_per_keycode);
+	}
+}
+
 void InputX11::ProcessXEvent(Display* display, const XEvent& event)
 {
 	// Process all mouse and keyboard events
@@ -95,11 +134,26 @@ void InputX11::ProcessXEvent(Display* display, const XEvent& event)
 
 		case KeyPress: 
 		{
-			KeySym sym = XKeycodeToKeysym(display, event.xkey.keycode, 0);
-			KeySym lower_sym, upper_sym;
-			XConvertCase(sym, &lower_sym, &upper_sym);
+			int group_index = 0; // this is always 0 for our limited example
+			Rocket::Core::Input::KeyIdentifier key_identifier;
+#ifdef HAS_X11XKBLIB
+			if(has_xkblib)
+			{
+				KeySym sym = XkbKeycodeToKeysym(display, event.xkey.keycode, 0, group_index);
+
+				key_identifier = key_identifier_map[sym & 0xFF];
+			}
+			else
+#endif // HAS_X11XKBLIB
+			{
+				KeySym sym = x11_key_mapping[(event.xkey.keycode - min_keycode) * keysyms_per_keycode + group_index];
+
+				KeySym lower_sym, upper_sym;
+				XConvertCase(sym, &lower_sym, &upper_sym);
+
+				key_identifier = key_identifier_map[lower_sym & 0xFF];
+			}
 
-			Rocket::Core::Input::KeyIdentifier key_identifier = key_identifier_map[lower_sym & 0xFF];
 			int key_modifier_state = GetKeyModifierState(event.xkey.state);
 
 			// Check for a shift-~ to toggle the debugger.
@@ -121,11 +175,26 @@ void InputX11::ProcessXEvent(Display* display, const XEvent& event)
 
 		case KeyRelease:
 		{
-			KeySym sym = XKeycodeToKeysym(display, event.xkey.keycode, 0);
-			KeySym lower_sym, upper_sym;
-			XConvertCase(sym, &lower_sym, &upper_sym);
+			int group_index = 0; // this is always 0 for our limited example
+			Rocket::Core::Input::KeyIdentifier key_identifier;
+#ifdef HAS_X11XKBLIB
+			if(has_xkblib)
+			{
+				KeySym sym = XkbKeycodeToKeysym(display, event.xkey.keycode, 0, group_index);
+
+				key_identifier = key_identifier_map[sym & 0xFF];
+			}
+			else
+#endif // HAS_X11XKBLIB
+			{
+				KeySym sym = x11_key_mapping[(event.xkey.keycode - min_keycode) * keysyms_per_keycode + group_index];
+
+				KeySym lower_sym, upper_sym;
+				XConvertCase(sym, &lower_sym, &upper_sym);
+
+				key_identifier = key_identifier_map[lower_sym & 0xFF];
+			}
 
-			Rocket::Core::Input::KeyIdentifier key_identifier = key_identifier_map[lower_sym & 0xFF];
 			int key_modifier_state = GetKeyModifierState(event.xkey.state);
 			if (key_identifier != Rocket::Core::Input::KI_UNKNOWN)
 				context->ProcessKeyUp(key_identifier, key_modifier_state);

+ 5 - 0
Samples/shell/src/x11/ShellX11.cpp

@@ -74,6 +74,11 @@ bool Shell::OpenWindow(const char* name, bool attach_opengl)
 	if (display == NULL)
 		return false;
 
+	// This initialise they keyboard to keycode mapping system of X11
+	// itself.  It must be done here as it needs to query the connected
+	// X server display for information about its install keymap abilities.
+	InputX11::InitialiseX11Keymap(display);
+
 	screen = XDefaultScreen(display);
 
 	// Fetch an appropriate 32-bit visual interface.