Can't get meta state from Android KeyEvent - android

Looks silly, but I can't get meta state out of KeyEvent, accessed from onKeyListener. Tried with all keyboards I have and with emulators.
Whether or not Shift, Ctrl, etc keys are pressed, keyEvent.getMetaState() returns 0. May it works for TextListener, but I don't need it for entering text, I just want to differentiate between Tab and Shift+Tab.
Thanks for anticipated help.
Update. What I just figured out is that meta state is reported for alphabetic keys, but not for other keys.
For example if I press left Shift+T the system generates KeyEvent for KEYCODE_SHIFT_LEFT and KEYCODE_T, and KeyEvent for KEYCODE_T has META_SHIFT_ON set. You can trick the system with Shift+TAB+T, in which case META_SHIFT_ON is set for both KEYCODE_T and KEYCODE_TAB. However with Shift+TAB the KeyEvent for KEYCODE_SHIFT_LEFT is not generated, and the meta state remains unaffected.
Maybe system keyboard configuration files need to be updated to allow combinations like Shift+TAB?

Yes, it's really about android configuration file.
You modify TAB entry in /system/usr/kychars/Generic.kcm (or the file for corresponding vendor) and add a line for shift, as the following:
key TAB {
label: '\t'
base: '\t'
shift: '\t'
ctrl, alt, meta: none
}
Some devices uses qwerty.kcm, which has the shift line alaready present. They should work OK without intrusion. BTW, unicode has provides a special code \u21B9 for Shift+TAB, but it might not be recognised by Android.

Related

Handling dead keys in Android KCM

I'm using library Extra Physical Keyboard Layouts which is able to add new keyboard layouts to the device. Don't confuse it with whole new keyboards like SwiftKey, Samsung Keyboard etc.
This library is using KCM files which is Android standard for keyboard layout files.
I have my custom layout (originally KLC file) which I converted to KCM.
But these two main things about dead key are missing:
\u030c (ˇ) + \u0075 (u) should produce \u016f (ů), but now it is producing \u01d4 (ǔ)
But for example:
\u030c (ˇ) + \u0074 (t) result \u0165 (ť) is fine
\u030c (ˇ) + \u030c (ˇ) should produce \u003d (=).
Basically double pressing key EQUALS should produce \u003d (=)
The problem is that afaik there is no way how to handle dead keys in KCM file and are handled automatically by the OS.
Is there a way how to solve mentioned problems in KCM file or any other way without creating custom keyboard like SwiftKey etc.?
Mentioned KLC and KCM files can be found here.
Thank you

Register hardware keyboard shortcuts in Android's help menu

Android supports external hardware keyboards as input, which may send keyboard shortcuts (e.g. Ctrl+A) in which there are some ways to program my app to accept shortcuts from external keyboards (e.g. like this: Custom keyboard shortcuts).
I came across this keyboard shortcut "help" screen in Android (activated by pressing OS + /) (see picture below)
and noticed some apps have some keyboard shortcuts directly registered within the system shortcuts help screen(these screens are not provided by the app, they can be found by pressing OS + /).
So far, the apps that I see that have this feature are:
Samsung Internet
Samsung One UI Home
Google Chrome
Chromium-based browsers (e.g. Brave)
Google Docs, Sheets, Slides
I cannot find any way to register my keyboard shortcuts in my app programmatically such that they will be recognised by the system. How can I possibly implement it in my app?
I do know iOS/iPadOS has such a feature.
Perhaps Android does have such a feature too? It seems like it would be quite useful to app developers and users, not sure why it's not documented at all in Android Developer documentation.
Thanks.
This feature is not documented in the Android Developer website, so I had to search around.
Since it is supported by AOSP, this is not a proprietary method/function by Google. No root is required on your users' devices.
Since this feature is available in Chromium-based browsers, I decided to check up the open-source Chromium Android source code (a mirror on GitHub is available here by someone: https://github.com/kuoruan/Chromium-Android) and I have discovered how this feature is implemented.
The relevant lines are here:
https://github.com/kuoruan/Chromium-Android/blob/29ba2966ff145c9cb2492a971f9c03f879c5b9c9/app/src/main/java/org/chromium/chrome/browser/KeyboardShortcuts.java#L117
https://github.com/kuoruan/Chromium-Android/blob/29ba2966ff145c9cb2492a971f9c03f879c5b9c9/app/src/main/java/org/chromium/chrome/browser/ChromeTabbedActivity.java#L2135
In any Activity, you can override the method onProvideKeyboardShortcuts.It provides 3 parameters: data, menu, and deviceId, in which we only need data here.
Here is the method signature:
fun onProvideKeyboardShortcuts(
data: MutableList<KeyboardShortcutGroup>?,
menu: Menu?,
deviceId: Int
)
This only works on API 24 (Android Nougat) and above.
data is a mutable list of KeyboardShortcutGroup, which is a group of keyboard shortcuts.
So, you can have multiple groups containing multiple shortcuts, useful for grouping the shortcuts for your users.
To register your shortcuts,
Create a KeyboardShortcutGroup. This is required to store and group your keyboard shortcuts together. The class accepts a CharSequence as a parameter for the name of the group, so you have to use getString(R.string.your_resource) for string resources.
val keyboardShortcutGroup = KeyboardShortcutGroup(/* the name of your group here: */ "Test Group")
Define your keyboard shortcuts. Keyboard shortcuts are defined using KeyboardShortcutInfo objects, which accepts 3 parameters in it's constructor - a label, the key(e.g. A/ Z/ 8/ 9), and the modifier key. A single keyboard shortcut is created this way:
KeyboardShortcutInfo("Shortcut One" /*label*/, KeyEvent.KEYCODE_Z/*key*/, KeyEvent.META_ALT_ON/*modifier*/)
You need to pass in key codes into the constructor for the key and the modifier key.
The key and modifier key must be passed in seperately.
Here are the list of available key codes:
https://developer.android.com/reference/android/view/KeyEvent#KEYCODE_0 (See those prefixed with KEYCODE)
Based on testing, the modifier keys which work are:
Ctrl META_CTRL_ON
Alt META_ALT_ON
Shift META_SHIFT_ON
Super/OS/Meta (see https://android.stackexchange.com/a/243218/307843) META_META_ON
Function META_FUNCTION_ON
Left/Right keys for all of these are also available(i.e. META_ALT_LEFT_ON)
META_SYM_ON may work(have not tested yet), but Caps Lock doesn't work.
To combine modifier keys,
in Java, use the bitwise operator:
KeyEvent.META_ALT_LEFT_ON | KeyEvent.META_CTRL_ON
in Kotlin, use the or operator:
KeyEvent.META_ALT_LEFT_ON or KeyEvent.META_CTRL_ON
To this KeyboardShortcutGroup, add shortcuts using addItem.
keyboardShortcutGroup.addItem(shortcut /* <-- the shortcut created earlier */)
Add your KeyboardShortcutGroup to data
data.add(keyboardShortcutGroup)
Your code should look like this:
override fun onProvideKeyboardShortcuts(
data: MutableList<KeyboardShortcutGroup>?,
menu: Menu?,
deviceId: Int
) {
super.onProvideKeyboardShortcuts(data, menu, deviceId)
// Requires API 24
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val keyboardShortcutGroup = KeyboardShortcutGroup("Test Group")
keyboardShortcutGroup.addItem(KeyboardShortcutInfo("Shortcut One", KeyEvent.KEYCODE_Z, KeyEvent.META_ALT_ON))
data?.add(keyboardShortcutGroup)
}
}
You should see the end result:
You can use this to inform users of available shortcuts. Note that this does not implement them, it merely adds a listing to the Android shortcut menu.

Qt Android: Virtual keyboard keeps switching to uppercase when I type in a QLineEdit

When I type in a QLineEdit, the virtual keyboard starts with uppercase. Even if I set it to lowercase, it returns to uppercase as soon as I've typed a single character. That is, every time I type a character, the keyboard is reset to uppercase again.
This happens even on a freshly created project (I just put a line edit and run it).
I found a forum thread about the same issue - https://groups.google.com/forum/#!topic/android-qt/QMFZmkACAIA.
I'm using Qt/C++ (not QML).
Edit: Just tested it on a new QML project, the bug is there too. I also found a thread posted about it for QML - https://groups.google.com/forum/#!msg/android-qt/BzGDGoLNtYc/TdtOX9MW3vIJ.
Edit 2: I tested with inputMethodHints(), and the only one that had effect was ImhNoAutoUppercase. But then it still started with an uppercase char, and when pressing the back button (to delete the last character), the keyboard will switch to uppercase again, even if you've typed several letters. After the first letter it switches to lowercase, and if you don't press the back button it works mostly OK.
Edit: A somewhat good workaround is setting ImhNoAutoUppercase, the first letter is still capitalized, but at least the next letters you type will be lowercase.
Original answer:
In Android, this would be set using inputType on the EditText in the xml of the layout file for the Activity/Fragment (screen/page you are looking at). Can you access and edit the layout file directly for Android?
Are you using setInputMask() to control the input type? It may be that forcing lowercase (or switching of case conversion) gives the option to use upper or lower case. I guess what is being set in the Android layout xml file is inputType="textCapSentences" or something similar ( https://developer.android.com/training/keyboard-input/style.html ).
UPDATE: You mention that the issue is fixed in 5.4. This looks like the commit that would fix it. I would suggest just implementing the fixes shown here. https://qt.gitorious.org/qt/qtbase/commit/2b3f293d892c5268bd2a07ed17fa9fc5adacbd76
You mention you are happy to edit the Qt source code. I think the error may be in this part of src/org/qtproject/qt5/android/QtActivityDelegate.java
if ((inputHints & ImhUppercaseOnly) != 0) {
initialCapsMode |= android.text.TextUtils.CAP_MODE_CHARACTERS;
inputType |= android.text.InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS;
} else if ((inputHints & ImhLowercaseOnly) == 0 && (inputHints & ImhNoAutoUppercase) == 0) {
initialCapsMode |= android.text.TextUtils.CAP_MODE_SENTENCES;
inputType |= android.text.InputType.TYPE_TEXT_FLAG_CAP_SENTENCES;
}
Should be changed to:
if ((inputHints & ImhUppercaseOnly) != 0) {
initialCapsMode |= android.text.TextUtils.CAP_MODE_CHARACTERS;
inputType |= android.text.InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS;
} else if ((inputHints & ImhLowercaseOnly) == 0 && (inputHints & ImhNoAutoUppercase) == 0) {
//initialCapsMode |= android.text.TextUtils.CAP_MODE_SENTENCES; // not sure what to set here - could try 0 or null if commenting out line doesn't work
inputType |= android.text.InputType.TYPE_CLASS_TEXT;
}
If this doesn't fix it, I'd suggest searching the source code for android.text.InputType.TYPE_TEXT_FLAG_CAP or android.text.TextUtils.CAP_MODE and replacing them by trial and error.

Android done/go/enter does not fire any DOM event in Cordova

The Issue:
Using
<input id="my_tel" type="tel" onkeypress="alert(event);"/>
<input id="my_num" type="number" onkeypress="alert(event);" />
The issue is that pressing done or enter or go key in android, nothing happens.For all other keys it works fine. When i tried to alert what event is being fired i found none.
The keypad does not hide (which is very sad) on pressing go/enter/done button.
However using
input type="text"
the issue does not exist.
Here is what i tried :
A. Used input type="text" and do not allow user to enter anything except
numbers.
Problem with this approach : The user is always presented with the default textual keyboard, and she/he has to switch, from default text to number pad,
which is not elegant and a turn off as i have many such pages in my project.
B. Used events like 'touchstart'and 'touchend' but no luck.
C. The input box is not even losing focus on key press so the solution
html phonegap android : numeric soft keyboard has next instead of go button is not useful.
Possible solution :
We can use the SoftKeyBoard plugin (https://github.com/phonegap/phonegap-plugins/tree/master/Android/SoftKeyboard). And hope that this problem is solved by this. But seriously can't there be a better solution??
Note : The problem is not observed in the iOS app,just android.
Another Note : No DOM event is fired even on pressing backspace key, but atleast the the backspace key is doing its job. In my case the done/go/enter key does not seem to execute its default behavior.
are you using iScroll?, if you are try removing it for a quick test and see what happens. I use it on a phonegap app and it's doing strange things with the inputs.

Detecting alt keypresses in Android app

I want to create keyboard shortcuts in my Android app such that, say, alt-t runs a certain command. I can't seem to figure out how to detect the presence of the alt modifier in the emulator, though.
I've overridden onKeyDown() in my app to look like the following (Scala):
override def onKeyDown(keycode:Int, event:KeyEvent) = keycode match {
case KeyEvent.KEYCODE_B =>
StatisticsService.map(_.sayBatteryLevel())
true
case KeyEvent.KEYCODE_D =>
StatisticsService.map(_.sayDate())
true
case KeyEvent.KEYCODE_S =>
StatisticsService.map(_.saySignalStrengths())
true
case KeyEvent.KEYCODE_T =>
StatisticsService.map(_.sayTime())
true
case _ => super.onKeyDown(keycode, event)
}
That of course matches the plain keys just fine, but not alt-b, alt-t, etc. How can I change the above to match the given alt-modified bindings?
I've searched Google and have tried using event.isAltPressed, but this doesn't work. I've also logged the results of the keypresses, and have noticed that the alt key isn't at all picked up. That is, simply pressing alt does nothing, and pressing alt-t produces identical logs to just t.
This is being tested in the emulator if that makes a difference.
Edit: Not sure how to respond to comments left on my question, but I'm aware that not all devices have alt keys, but that's not an issue here because I'm coding for a custom device that does. The question isn't "what's the most generic way to do this," but "how do I match alt keybindings when the documented methods don't work and no explanation seems to be given in Google's own docs?"
Thanks.

Categories

Resources