Getting proper text input from physical keyboard in Android - android

I have a View that overrides the OnKeyDown event. I can get the Key Code and the KeyEvent, but it seems that I'm missing something.
Let me explain. For non-US keyboard layouts, the Key Code I'm getting is wrong. For example, when I press the ñ key in my Spanish keyboard, I expect to receive a "ñ" letter, but instead I get a Keycode.AltLeft as Key Code.
How do I get the real letter?
Another problematic case is with accentuated characters: When I press the ´ key and the o key, I shouldn't receive two events, but only one with the letter ó.

What are you trying to do? It is probably too low level.
A key down might not necessarily have anything to do with the final input text produced. For instance to produce on Japanese character one has to press a sequence of several keys.

Related

Is there any ways to know which language user is typing in EditText ? or Restrict user to type in English only

Any one have idea of getting language of user, who is typing in the EditText.
What I Have Tried ?
Please do not suggest Google's com.google.mlkit , I have already tried but not working when user types fast.
I have also tried setting up android:digits="All Alfabets", It is not working when I long press and paste from the ClipBoard, It is allowing text from the other language.
This seems like a very complex problem! And one that limiting the allowed characters won't solve - many non-English languages use the same Latin character set as English, or use it for a romanised version of their written language. nihongo o kaite imasu is Japanese, but that would pass an alphabet check!
Even where other characters are used (e.g. accented versions) it's not unusual for people to just drop them and use the "standard English" characters when typing, especially if they're being informal - e.g. Spanish uses accents on question words like ¿qué?, but people might just not bother (and skip the ¿ too, or just say k if they're being really informal)
And then there's the fact that English does use accented characters - someone can be naïve or blasé, but you don't want your app to tell people they're "not typing in English" if they write those things.
I don't know anything about mlkit but if it's capable of detecting language to some decent degree, it really might be the way to go for such a complex human problem. I'd suggest that instead of trying to interfere with the user's typing, you just trigger a check when they're done which validates what they've entered. If it looks ok, you can enable a button or whatever - if not, show an error message and make them fix it themselves.
You could do that kind of thing with a TextWatcher (or the doAfterTextChanged extension function that comes with the ktx-core AndroidX library) - you'd probably want to start a delayed task so it happens a moment after they stop typing, and that you can interrupt if they start typing again
val languageCheck = Runnable {
// do your check here, enable buttons / show errors as a result
}
// set up the checker
textView.doAfterTextChanged {
// cancel an existing delayed task
textView.removeCallbacks(languageCheck)
// schedule a new one
textView.postDelayed(languageCheck, delayMillis)
}

Switch InputType from Text to Number on the fly

Canadian postal codes have the following format: A1A1A1, and match the following regex:
[ABCEGHJKLMNPRSTVXY][0-9][A-Z][0-9][A-Z][0-9]
I am setting up an EditText for the user to input their postal code. I would like to display alternatively the text and the number keyboard.
Naively, I use this code in either the TextWatcher or the InputFilter
if (Character.isDigit(s.charAt(s.length() - 1))) {
zipView.setInputType(InputType.TYPE_CLASS_TEXT
| InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS
| InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS);
} else {
zipView.setInputType(InputType.TYPE_CLASS_PHONE);
}
However, this result in an exception when the user inputs the first number.
java.lang.ArrayIndexOutOfBoundsException: length=1; index=1
at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:464)
at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:454)
at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:33)
at android.text.method.NumberKeyListener.onKeyDown(NumberKeyListener.java:121)
at android.widget.TextView.doKeyDown(TextView.java:5787)
at android.widget.TextView.onKeyDown(TextView.java:5600)
at android.view.KeyEvent.dispatch(KeyEvent.java:2609)
... (continues without ever mentionning my classes.)
My guess is that the input type does not like that there are unsupported characters already in the view.
Input type doesn't actually restrict the keys allowed, its a hint to the keyboard as to what will be entered, so the keyboard can decide to change its UI. Nothing prevents you from adding text to a number field. It looks like a problem calling replace in a filter you set (filters are different from input type).
In fact most keyboards wouldn't even trigger this- XXXKeyListener classes are generally only called by hardware keyboards that cause keydown and keyup events. Software keyboards generally don't do that. Did you give this field a NULL input type initially? That's the only thing that would make the average softkeyboard try to pretend to be a hardware one.
Oh one other thing- setting the input mode while the field is active generally doesn't work well. If you don't reset the input connection, most keyboards won't even detect it (there is no change input type API for the keyboard side). If you do reset the input connection, you're likely to hit all sorts of weird behavior with autocorrect and timing (I know Swype had a dozen different rules for debouncing of events that resetting the input connection interfered with). Its not recommended to change an input type, ever.

Unable to pass certain IR remote key codes to Android

I'm trying to use an IR remote to pass certain key codes to Android. So far, I'm able to pass numeric keys (0-9) and D-pad keys (up, down, left, right, enter). Now I'm trying to extend the keys to include other characters like a-z.
The code that I'm modifying is an IR driver in the Linux kernel part of Android. It's similar to this driver. However, when I pass a value like KEY_A (maps "a" to 30: defined in Linux's include/linux/input.h), Android doesn't see it.
The section of code that passes the command up is the following:
input_report_key(cir->input, cir->last_key, 1);
input_report_key(cir->input, cir->last_key, 0);
input_sync(cir->input);
When I print cir->last_key, I can see the value 30 when I press the "a" button. However, I'm not sure how to trace the code from here to Android to see where the button press is being dropped.
In Android, I have a file called /system/usr/keylayout/qwerty.kl that maps values, e.g. 30 maps to "a". The problem is Android never gets the value of 30 when I press "a".
The keybit field of this structure has to be set to include all the key codes being passed.
For example,
set_bit(KEY_A, input_dev->keybit);

Android: Calculator on showing 0 immediately after the dot

I am now working on a calculator, and everything works fine except for decimal places.
The calculator contains 2 displays actually, one is called fakedisplay for actual operations, and one is called Display, for presenting the desired format, ie adding commas.
When pressing 12345.678, Display will follow fakedisplay and present as 12,345.678, but if i press 12345.009, the fakedisplay will work normally as 12345.009, but the Display stuck as 12,345 until 9 is pressed, and at that time it will show 12,345.009 normally.
However, it is strange that when the user presses 0, there is no response, and until pressing 9, 009 will then immediately append.
I know this arise from the parsing code, but based on this, how could I amend the following code? I really cannot think of any solution... Many thanks for all your advice!
one.setOnClickListener(new View.OnClickListener() {
if (str.length()<15) {
Fakedisplay.append("1");
}
DecimalFormat myFormatter1 = new DecimalFormat("###,###,###,###.#################");
String str1=Fakedisplay.getText().toString();
String stripped1 = Double.valueOf(str1).toString();
stripped1 = myFormatter1.format(Double.valueOf(stripped1));
if (stripped1.endsWith(".0"))
stripped1 = stripped1.substring(0, stripped1.length() - 2);
Display.setText(stripped1);
}
Probably the easiest solution is to not strip off the .0 in the code for every keystroke..
Instead, only strip off trailing zeros (assuming there's a decimal point in there of course) when the user calls for a result. Entering keys such as the digit keys 0 through 9, the decimal point ., or the sign-change key +/- (what I'll call the entry keys) are not generating a result so should not strip trailing zeros.
However, non-entry keys, such as when you press + or - or = on your calculator can freely modify the number.
That will give you a display of the digits being entered as the user enters them but will still strip off trailing zeros when necessary.
You can do that with a modification to your statement (and, as mentioned, only doing this when the user presses a non-entry key):
stripped1 = stripped1.replaceAll("(\\.[0-9]*[1-9])0+$","$1");
stripped1 = stripped1.replaceAll("\\.0$","");
The first statement removes all trailing zeros at the end of a decimal number (other than on if it's really an integer). The second takes care of that case.
No doubt I could make a single substitution if I gave it some more thought but that should be enough to get it functional.

Android: How to record keystroke?

I want to make a smart keyboard that can learn and save new words from user. I already made note and keyboard separately, the problem is :
how to read all keystrokes and write it to my note in background?
how to save my note automatically?
thanks for your help
Keep a String or StringBuilder that stores all the text that the user types. All text sent through your soft keyboard will have to pass through the onKey method.
So, I'd do something like this:
1) In onKey, check to make sure primaryCode (the keycode that was pressed) is a letter/number/apostrophe using the corresponding functions. So, something like
Character.isDefined(primaryCode)
2) Concatenate primaryCode onto the end of your StringBuilder/String.
You'll also have to deal with the user moving the cursor/backspacing. In my keyboard, I only store the most recent two words (resetting this whenever the user moves the cursor). That way, the keyboard can learn what the most likely word is given the last word.
You can save your "note" using an ObjectOutputStream or (if it's fairly small) using sharedPreferences.
Send me an email if you run into an more issues: I've been writing a soft keyboard for a while so I'm pretty familiar with it.

Categories

Resources