Send non-ASCII soft keys as UTF-8

This commit is contained in:
Cameron Gutman 2023-02-25 12:49:55 -06:00
parent f77543cd9b
commit 370dbb1a10
2 changed files with 58 additions and 58 deletions

View File

@ -62,6 +62,7 @@ import android.os.IBinder;
import android.util.Rational;
import android.view.Display;
import android.view.InputDevice;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.Surface;
@ -1299,33 +1300,42 @@ public class Game extends Activity implements SurfaceHolder.Callback,
handled = controllerHandler.handleButtonDown(event);
}
// Try the keyboard handler if it wasn't handled as a game controller
if (!handled) {
// Try the keyboard handler
short translated = keyboardTranslator.translate(event.getKeyCode(), event.getDeviceId());
if (translated == 0) {
return false;
}
// Let this method take duplicate key down events
if (handleSpecialKeys(event.getKeyCode(), true)) {
return true;
}
// Eat repeat down events
if (event.getRepeatCount() > 0) {
return true;
}
// Pass through keyboard input if we're not grabbing
if (!grabbedInput) {
return false;
}
byte modifiers = getModifierState(event);
if (KeyboardTranslator.needsShift(event.getKeyCode())) {
modifiers |= KeyboardPacket.MODIFIER_SHIFT;
// We'll send it as a raw key event if we have a key mapping, otherwise we'll send it
// as UTF-8 text (if it's a printable character).
short translated = keyboardTranslator.translate(event.getKeyCode(), event.getDeviceId());
if (translated == 0) {
// Make sure it has a valid Unicode representation and it's not a dead character
// (which we don't support). If those are true, we can send it as UTF-8 text.
//
// NB: We need to be sure this happens before the getRepeatCount() check because
// UTF-8 events don't auto-repeat on the host side.
int unicodeChar = event.getUnicodeChar();
if ((unicodeChar & KeyCharacterMap.COMBINING_ACCENT) == 0 && (unicodeChar & KeyCharacterMap.COMBINING_ACCENT_MASK) != 0) {
conn.sendUtf8Text(""+(char)unicodeChar);
return true;
}
return false;
}
conn.sendKeyboardInput(translated, KeyboardPacket.KEY_DOWN, modifiers,
// Eat repeat down events
if (event.getRepeatCount() > 0) {
return true;
}
conn.sendKeyboardInput(translated, KeyboardPacket.KEY_DOWN, getModifierState(event),
keyboardTranslator.hasNormalizedMapping(event.getKeyCode(), event.getDeviceId()) ? 0 : MoonBridge.SS_KBE_FLAG_NON_NORMALIZED);
}
@ -1370,13 +1380,8 @@ public class Game extends Activity implements SurfaceHolder.Callback,
handled = controllerHandler.handleButtonUp(event);
}
// Try the keyboard handler if it wasn't handled as a game controller
if (!handled) {
// Try the keyboard handler
short translated = keyboardTranslator.translate(event.getKeyCode(), event.getDeviceId());
if (translated == 0) {
return false;
}
if (handleSpecialKeys(event.getKeyCode(), false)) {
return true;
}
@ -1386,17 +1391,43 @@ public class Game extends Activity implements SurfaceHolder.Callback,
return false;
}
byte modifiers = getModifierState(event);
if (KeyboardTranslator.needsShift(event.getKeyCode())) {
modifiers |= KeyboardPacket.MODIFIER_SHIFT;
short translated = keyboardTranslator.translate(event.getKeyCode(), event.getDeviceId());
if (translated == 0) {
// If we sent this event as UTF-8 on key down, also report that it was handled
// when we get the key up event for it.
int unicodeChar = event.getUnicodeChar();
return (unicodeChar & KeyCharacterMap.COMBINING_ACCENT) == 0 && (unicodeChar & KeyCharacterMap.COMBINING_ACCENT_MASK) != 0;
}
conn.sendKeyboardInput(translated, KeyboardPacket.KEY_UP, modifiers,
conn.sendKeyboardInput(translated, KeyboardPacket.KEY_UP, getModifierState(event),
keyboardTranslator.hasNormalizedMapping(event.getKeyCode(), event.getDeviceId()) ? 0 : MoonBridge.SS_KBE_FLAG_NON_NORMALIZED);
}
return true;
}
@Override
public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
return handleKeyMultiple(event) || super.onKeyMultiple(keyCode, repeatCount, event);
}
private boolean handleKeyMultiple(KeyEvent event) {
// We can receive keys from a software keyboard that don't correspond to any existing
// KEYCODE value. Android will give those to us as an ACTION_MULTIPLE KeyEvent.
//
// Despite the fact that the Android docs say this is unused since API level 29, these
// events are still sent as of Android 13 for the above case.
//
// For other cases of ACTION_MULTIPLE, we will not report those as handled so hopefully
// they will be passed to us again as regular singular key events.
if (event.getKeyCode() != KeyEvent.KEYCODE_UNKNOWN || event.getCharacters() == null) {
return false;
}
conn.sendUtf8Text(event.getCharacters());
return true;
}
private TouchContext getTouchContext(int actionIndex)
{
if (actionIndex < touchContextMap.length) {
@ -2270,14 +2301,10 @@ public class Game extends Activity implements SurfaceHolder.Callback,
return handleKeyDown(keyEvent);
case KeyEvent.ACTION_UP:
return handleKeyUp(keyEvent);
case KeyEvent.ACTION_MULTIPLE:
return handleKeyMultiple(keyEvent);
default:
return false;
}
}
@Override
public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
conn.sendUtf8Text(event.getCharacters());
return super.onKeyMultiple(keyCode, repeatCount, event);
}
}

View File

@ -104,20 +104,6 @@ public class KeyboardTranslator implements InputManager.InputDeviceListener {
}
}
public static boolean needsShift(int keycode) {
switch (keycode)
{
case KeyEvent.KEYCODE_AT:
case KeyEvent.KEYCODE_POUND:
case KeyEvent.KEYCODE_PLUS:
case KeyEvent.KEYCODE_STAR:
return true;
default:
return false;
}
}
public boolean hasNormalizedMapping(int keycode, int deviceId) {
if (deviceId >= 0) {
KeyboardMapping mapping = keyboardMappings.get(deviceId);
@ -359,20 +345,7 @@ public class KeyboardTranslator implements InputManager.InputDeviceListener {
translated = 0x6E;
break;
case KeyEvent.KEYCODE_AT:
translated = 2 + VK_0;
break;
case KeyEvent.KEYCODE_POUND:
translated = 3 + VK_0;
break;
case KeyEvent.KEYCODE_STAR:
translated = 8 + VK_0;
break;
default:
System.out.println("No key for "+keycode);
return 0;
}
}