Browse Source

WIP: Linux port
- Button code -> character mapping now functional
- Text input events are now properly reported
- Return key input command is now properly reported

Marko Pintera 8 years ago
parent
commit
ca06c8bfd0

+ 156 - 18
Source/BansheeCore/Linux/BsLinuxPlatform.cpp

@@ -491,17 +491,150 @@ namespace bs
 		return L"";
 	}
 
-	WString Platform::keyCodeToUnicode(UINT32 keyCode)
+	/** Maps Banshee button codes to X11 names for physical key locations. */
+	const char* keyCodeToKeyName(ButtonCode code)
+	{
+		switch(code)
+		{
+			// Row #1
+		case BC_F1:			return "FK01";
+		case BC_F2:			return "FK02";
+		case BC_F3:			return "FK03";
+		case BC_F4:			return "FK04";
+		case BC_F5:			return "FK05";
+		case BC_F6:			return "FK06";
+		case BC_F7:			return "FK07";
+		case BC_F8:			return "FK08";
+		case BC_F9:			return "FK09";
+		case BC_F10:		return "FK10";
+		case BC_F11:		return "FK11";
+		case BC_F12:		return "FK12";
+
+			// Row #2
+		case BC_GRAVE:		return "TLDE";
+		case BC_1: 			return "AE01";
+		case BC_2:			return "AE02";
+		case BC_3:			return "AE03";
+		case BC_4:			return "AE04";
+		case BC_5:			return "AE05";
+		case BC_6:			return "AE06";
+		case BC_7:			return "AE07";
+		case BC_8:			return "AE08";
+		case BC_9:			return "AE09";
+		case BC_0:			return "AE10";
+		case BC_MINUS:		return "AE11";
+		case BC_EQUALS:		return "AE12";
+		case BC_BACK:		return "BKSP";
+
+			// Row #3
+		case BC_TAB:		return "TAB";
+		case BC_Q:			return "AD01";
+		case BC_W:			return "AD02";
+		case BC_E:			return "AD03";
+		case BC_R:			return "AD04";
+		case BC_T:			return "AD05";
+		case BC_Y:			return "AD06";
+		case BC_U:			return "AD07";
+		case BC_I:			return "AD08";
+		case BC_O:			return "AD09";
+		case BC_P:			return "AD10";
+		case BC_LBRACKET:	return "AD11";
+		case BC_RBRACKET:	return "AD12";
+
+			// Row #4
+		case BC_A:			return "AC01";
+		case BC_S:			return "AC02";
+		case BC_D:			return "AC03";
+		case BC_F:			return "AC04";
+		case BC_G:			return "AC05";
+		case BC_H:			return "AC06";
+		case BC_J:			return "AC07";
+		case BC_K:			return "AC08";
+		case BC_L:			return "AC09";
+		case BC_SEMICOLON:	return "AC10";
+		case BC_APOSTROPHE:	return "AC11";
+		case BC_BACKSLASH:	return "BKSL";
+
+			// Row #5
+		case BC_Z:			return "AB01";
+		case BC_X:			return "AB02";
+		case BC_C:			return "AB03";
+		case BC_V:			return "AB04";
+		case BC_B:			return "AB05";
+		case BC_N:			return "AB06";
+		case BC_M:			return "AB07";
+		case BC_COMMA:		return "AB08";
+		case BC_PERIOD:		return "AB09";
+		case BC_SLASH:		return "AB10";
+
+			// Keypad
+		case BC_NUMPAD0:	return "KP0";
+		case BC_NUMPAD1:	return "KP1";
+		case BC_NUMPAD2:	return "KP2";
+		case BC_NUMPAD3:	return "KP3";
+		case BC_NUMPAD4:	return "KP4";
+		case BC_NUMPAD5:	return "KP5";
+		case BC_NUMPAD6:	return "KP6";
+		case BC_NUMPAD7:	return "KP7";
+		case BC_NUMPAD8:	return "KP8";
+		case BC_NUMPAD9:	return "KP9";
+
+		default:
+			break;
+		}
+
+		return nullptr;
+	}
+
+	WString Platform::keyCodeToUnicode(UINT32 buttonCode)
 	{
 		Lock lock(mData->lock);
 
-		// Note: Assuming the keyCode is equal to X11 KeySym. Which it is because that's how our input manager reports them.
-		KeySym keySym = (KeySym)keyCode;
+		static bool mapInitialized = false;
+		static UnorderedMap<String, KeyCode> keyMap;
+		if(!mapInitialized)
+		{
+			char name[XkbKeyNameLength + 1];
+
+			XkbDescPtr desc = XkbGetMap(mData->xDisplay, 0, XkbUseCoreKbd);
+			XkbGetNames(mData->xDisplay, XkbKeyNamesMask, desc);
+
+			for(UINT32 keyCode = desc->min_key_code; keyCode <= desc->max_key_code; keyCode++)
+			{
+				memcpy(name, desc->names->keys[keyCode].name, XkbKeyNameLength);
+				name[XkbKeyNameLength] = '\0';
+
+				keyMap[String(name)] = keyCode;
+			}
+
+			XkbFreeNames(desc, XkbKeyNamesMask, True);
+			XkbFreeKeyboard(desc, 0, True);
+
+			mapInitialized = true;
+		}
+
+		const char* keyName = keyCodeToKeyName((ButtonCode)buttonCode);
+		if(keyName == nullptr)
+		{
+			// Not a printable key
+			return L"";
+		}
+
+		auto iterFind = keyMap.find(String(keyName));
+		if(iterFind == keyMap.end())
+		{
+			// Cannot find mapping, although this shouldn't really happen
+			return L"";
+		}
 
 		XKeyPressedEvent event;
 		bs_zero_out(event);
-		event.keycode = XKeysymToKeycode(mData->xDisplay, keySym);
+		event.type = KeyPress;
+		event.keycode = iterFind->second;
 		event.display = mData->xDisplay;
+		event.time = CurrentTime;
+		event.window = mData->mainXWindow;
+		event.root = RootWindow(mData->xDisplay, XDefaultScreen(mData->xDisplay));
 
 		Status status;
 		char buffer[16];
@@ -557,7 +690,7 @@ namespace bs
 		case XK_Escape:
 			command = InputCommandType::Escape;
 			return true;
-		case XK_ISO_Enter:
+		case XK_Return:
 			command = shift ? InputCommandType::Return : InputCommandType::Confirm;
 			return true;
 		case XK_BackSpace:
@@ -648,29 +781,34 @@ namespace bs
 			case KeyPress:
 			{
 				// Process text input
+				KeySym keySym = XkbKeycodeToKeysym(mData->xDisplay, (KeyCode)event.xkey.keycode, 0, 0);
+
 				//// Check if input manager wants this event. If not, we process it.
-				if(!XFilterEvent(&event, None))
+				if(XFilterEvent(&event, None) == False)
 				{
-					Status status;
-					char buffer[16];
+					// Don't consider Return key a character
+					if(keySym != XK_Return)
+					{
+						Status status;
+						char buffer[16];
 
-					INT32 length = Xutf8LookupString(mData->IC, &event.xkey, buffer, sizeof(buffer), nullptr,
-							&status);
+						INT32 length = Xutf8LookupString(mData->IC, &event.xkey, buffer, sizeof(buffer), nullptr,
+								&status);
 
-					if(length > 0)
-					{
-						buffer[length] = '\0';
+						if (length > 0)
+						{
+							buffer[length] = '\0';
 
-						U32String utfStr = UTF8::toUTF32(String(buffer));
-						if(utfStr.length() > 0)
-							onCharInput((UINT32)utfStr[0]);
+							U32String utfStr = UTF8::toUTF32(String(buffer));
+							if (utfStr.length() > 0)
+								onCharInput((UINT32) utfStr[0]);
+						}
 					}
 				}
 
 				// Handle input commands
 				InputCommandType command = InputCommandType::Backspace;
 
-				KeySym keySym = XkbKeycodeToKeysym(mData->xDisplay, (KeyCode)event.xkey.keycode, 0, 0);
 				bool shift = (event.xkey.state & ShiftMask) != 0;
 
 				if(parseInputCommand(keySym, shift, command))
@@ -1000,7 +1138,7 @@ namespace bs
 
 		if(XSupportsLocale())
 		{
-			XSetLocaleModifiers("");
+			XSetLocaleModifiers("@im=none");
 			mData->IM = XOpenIM(mData->xDisplay, nullptr, nullptr, nullptr);
 
 			// Note: Currently our windows don't support pre-edit and status areas, which are used for more complex types

+ 4 - 0
Source/BansheeGLRenderAPI/Linux/BsLinuxRenderWindow.cpp

@@ -72,6 +72,10 @@ namespace bs
 
 	LinuxRenderWindow::~LinuxRenderWindow()
 	{
+		// Make sure to set the original desktop video mode before we exit
+		if(mProperties.isFullScreen)
+			setWindowed(50, 50);
+
 		if (mWindow != nullptr)
 		{
 			LinuxPlatform::lockX();