I’ve been expanding Nifty’s role in my Android app. I’ve got a checkbox, button, and text to work, but I’m having an issue with TextField. I’d like to have the ability for the user to enter a number into a text box to change a game setting. The textfield display ok and when I touch the textfield and the blinking cursor shows up, but the Android keyboard does not appear so the user cannot enter any text.
Has anyone been able to display the Android keyboard when the user touches a TextField? I’d really not like to create my own keypad in Nifty to allow for data entry.
Well nifty textField is not really a text fields for android…
isn’t there a way to manually pop the keyboard? surely there is
I mean in the android API?
Maybe we should ad some API to do this from the harness or something…
For now what you could do is to create some kind of PopKeyBoardListener on the android side of the project, and make your nifty controller notify this listener when the field gets the focus…
That’s exactly what I’m working on now. I’ve got my nifty controller being notified when the text field gains and loses focus and a listener setup to notify MainActivity. Next I’ll display the soft keyboard and see if jme sees the keys and forwards them to nifty. I’ll keep you posted.
@iwgeric said:
and see if jme sees the keys and forwards them to nifty.
uh right I didn't think of this....it could be an issue...if it does not works you may have to add Action listeners to grab keyboard events...
There is a setSimulateKeyboard() on the jme's glSurfaceView, it sets a keyboardEventsEnabled boolean...but i'm afraid it's never used...so no magic :p
I'm looking forward your tests results.
also there is a ANDROID_TO_JME static array that looks like a map from JME’s keyInputs to android’s keyInputs but it’s also never used …I guess it’s still a work in progress…and since there no official android guy in the team anymore…I guess i’ll add it to my todo
@nehon said:
I'm looking forward your tests results.
I'm having some issues figuring out how to get the soft keyboard to display. I thought the following would work, but it isn't.
[java]
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED,0);
[/java]
I'll keeping looking into it, but if you know how to get the keyboard to display, let me know.
The more I look into this, the less sure I am that an Android soft keyboard is the right way to go.
Q1) Would it be better to have the keyboard created and displayed via Nifty?
This way, it would work on any of the platforms supported by the platform. However, I think it might be tricky creating a keyboard in Nifty. Mainly, to support various screen sizes, I think the letters would need to be scaled to fit the keyboard on smaller screens. I know that the layout, panels, and buttons can be scaled based on % instead of px, but I don’t know if the letters can be scaled.
Q2) Is there a way to scale the letters displayed on a Nifty button or do you have to have different Fonts at different sizes in order to change the text size of the labels?
1/ erf sounds hardcore
seen this post? http://stackoverflow.com/questions/2479504/forcing-the-soft-keyboard-open/6977565#6977565
I didn’t test it but the guy sounds pretty confident that it works
EDIT : nvm looks like it’s what you tested…
2/Afaik you can’t scale text, you have to create different size fonts.
Well, I got the keyboard to open and notify my MainActivity what the text is after each letter is pressed. The bad news is I could only figure out how to do it when a EditText has the focus. I put an EditText behind the GLSurfaceView so it isn’t visible and to a editText.requestFocus() and then do the code to open the keyboard. If I make the EditText invisible or try to use the GLSurfaceView, the keyboard doesn’t open.
OK, I think I have something that will work. I’m using the KeyboardView widget in Android. This allows you to define an XML file to layout the keys and an interface to receive the keycodes that correspond to the button/key pressed. I think with this users can use a default key layout that we provide as well as redefine their own XML file that includes the keys that want to display. It also scales itself based on the orientation and screensize of the device and allows for images or characters to be placed on the keys.
Currently, when I touch a textfield in Nifty, the EventBus subscription calls a routine on the android side which displays the keyboardview. When I touch the ENTER key on the keyboardview, the keyboardview dismisses and focus is returned to Nifty.
I’m going to move the android side of the code into AndroidHarness instead of MainActivity and then try to figure out how to map the keycodes from Android into ones that Nifty wants. Maybe I can use the Android_to_JME mappings to do this.
Still a ways to go to get something usable, but its a start. Let me know if you think this way would be acceptable.
i don’t get what’s the KeyboardView widget is, it’s a nifty control?
Will it support different keyboard layouts? (qwerty, azerty, and everything else)
Anyway thank you for your efforts it’s really appreciated.
A KeyboardView is an Android View that reads an XML file to determine what keys to show (images or characters) and what keycodes to return when the user clicks on a key.
http://developer.android.com/reference/android/inputmethodservice/KeyboardView.html
It would be a matter of changing the XML file to display different keyboards like a numeric keypad, querty keypad, etc… I haven’t decided yet whether to pass each key to Nifty individually or wait until the user dismisses the keypad and then pass the entire string to Nifty. It will depend, I think, on whether or not passing a keycode for “backspace” will work when passed to Nifty. I image that passing a backspace to nifty will delete the previous character in the Nifty control, so if that works, I’ll probably pass each character individually back to Nifty.
Another thing to figure out is how to tell the Android View which keyboard to use (which XML file to read) when the user activates various Nifty controls. I think it will require different NiftyEventSubscribers that pass an XML filename back to AndroidHarness or a predefined constant that reads a specific XML file. Not sure yet.
The nice thing about the KeyboardView is that it handles all the click events and passes back the key string and keycode so that we can convert the keycode for Nifty.
sounds good to me!
nice found.
Well, I found that implementing the KeyboardView was going to be much more work than I thought it was worth. After taking a step back, I decided to implement something else entirely. Maybe it’s just lazyness, but to do it right, I would have needed to implement a whole Input Manager for the keyboard which I didn’t think was worth it.
Instead, I implemented a way for the engine to fire off an event that would start up an alert box on the android side for the user to type in whatever they want with the default Android keyboard. Once the alert box text entry is complete, the entire string is then returned to the caller so that they can do whatever they want with the text.
I have this working with Nifty textfields. Basically, when the text is returned to my screen controller, I then take the text and set the textfield text. I think this is probably better for a couple of reasons:
- Users will use whatever keyboard they have defined
- Every individual key code does not need to be implemented in JME since it just uses the resulting string
- Future chat style implementations can also use this method to create strings to send over the network
Anyway, I’ll need another day or 2 to create the patch files, but the general changes are in:
- AndroidHarness - creates the dialog box and returns the resulting text
- SoftTextDialogInput - new interface for the engine to call to start the dialog box. This is currently located in package com.jme3.input so that it can be used for other platforms in the future (ie. iPhone, etc)
- SoftTextDialogInputListener - new interface to send back the completed text
- InputManager - added setters and getters for the SoftTextDialogInput class to use to create the dialog
- AndroidInput - sets the SoftTextDialogInput in InputManager to AndroidHarness. Other platforms would set variable in InputManager to thier own implementations in their own contexts
As I said, I have it all working in a modified version of the engine. The user implentation is the following:
In the Nifty XML file, I have an onClick interaction defined to call a routine in the Screen Controller. In the Screen Controller, I have the following:
[java]
public void changeGravity() {
logger.log(Level.INFO,"changeGravity");
TextField textField = screen.findNiftyControl("txtGravity", TextField.class);
String initialValue = "";
if (textField != null) {
initialValue = textField.getText();
} else {
logger.log(Level.INFO, "textField is null getting initial value");
}
SoftTextDialogInput softTextDialogInput = app.getInputManager().getSoftTextDialogInput();
if (softTextDialogInput != null) {
logger.log(Level.INFO, "Requesting soft dialog input");
softTextDialogInput.requestDialog(SoftTextDialogInput.NUMERIC_ENTRY_DIALOG, "Gravity", initialValue, new SoftTextDialogInputListener() {
public void onSoftText(int action, String text) {
logger.log(Level.INFO, "onTextDialogDismissed: action: {0}, text: {1}",
new Object[]{action, text});
if (action == SoftTextDialogInputListener.COMPLETE) {
TextField textField = screen.findNiftyControl("txtGravity", TextField.class);
if (textField != null) {
textField.setText(text);
} else {
logger.log(Level.INFO, "textField is null in Results Listener");
}
}
}
});
} else {
logger.log(Level.INFO, "softTextDialogInput is null");
}
}
[/java]
The above calls the Dialog creation interface and takes the returned text string and sets the TextField back in Nifty. No other user code is necessary.
@nehon I know it's a lot to take in without playing with it, but let me know what you think.
EDIT: In case you're wondering, this doesn't affect the PC version. If the PC version is being executed, SoftTextDialogInput in InputManager is null and the code is skipped and the PC keyboard still works to set the text in the textfield.
hehe sometimes you got to step back and do it allover again
That looks like a more robust solution as it’s the android soft keyboard that is triggered. Also the fact that you send the resulting string is clever, that avoid messing with the keyboard inputs.
Only thing i’m not fond of is the SoftTextDialogInput in the input manager, even if it’s null, it’s useless on the desktop side of the engine…
Can’t it be a AndroidInput attribute instead? Why do you need it to be in the InputManager?
Anyway I like this solution better, nice work
@nehon Thanks. I’m not sure where else to put it so that its available from the screen controller. I figured it needed to be set somewhere in the main engine so that the code could call it without using reflection to figure out if the interface is present. I was trying to make it so the same game code could be used on both platforms. Do you have any other ideas on how to call it?
I don’t know but maybe this should be somewhere in the nifty renderer since it’s triggered by Nifty textbox…
On the other hand, it’s very relative to inputs too so it’s consistent to put it in the inputManager.
Also it could be a general API for soft keyboards, not only Android has them, but there might be some desktop touch screens hardwares that use soft keyboards…
@Momoko_Fan what do you think?
To see what I was doing, below are the patch files based off the engine as of an hour ago:
SoftTextDialogInput
[java]
This patch file was generated by NetBeans IDE
Following Index: paths are relative to: D:UserspotterecDocumentsjMonkeyProjectsjME3srccorecomjme3input
This patch can be applied using context Tools: Patch action on respective folder.
It uses platform neutral UTF-8 encoding and n newlines.
Above lines and this line are ignored by the patching process.
Index: SoftTextDialogInput.java
— SoftTextDialogInput.java Locally New
+++ SoftTextDialogInput.java Locally New
@@ -0,0 +1,13 @@
+package com.jme3.input;
+
+import com.jme3.input.controls.SoftTextDialogInputListener;
+
+public interface SoftTextDialogInput {
+
- public static int TEXT_ENTRY_DIALOG = 0;
- public static int NUMERIC_ENTRY_DIALOG = 1;
- public static int NUMERIC_KEYPAD_DIALOG = 2;
+
- public void requestDialog(int id, String title, String initialValue, SoftTextDialogInputListener listener);
+
+}
[/java]
SoftTextDialogInputListener
[java]
This patch file was generated by NetBeans IDE
Following Index: paths are relative to: D:UserspotterecDocumentsjMonkeyProjectsjME3srccorecomjme3inputcontrols
This patch can be applied using context Tools: Patch action on respective folder.
It uses platform neutral UTF-8 encoding and n newlines.
Above lines and this line are ignored by the patching process.
Index: SoftTextDialogInputListener.java
— SoftTextDialogInputListener.java Locally New
+++ SoftTextDialogInputListener.java Locally New
@@ -0,0 +1,17 @@
+/*
-
- To change this template, choose Tools | Templates
- To change this template, choose Tools | Templates
-
- and open the template in the editor.
- and open the template in the editor.
- */
+package com.jme3.input.controls;
+
+/**
- *
-
-
@author potterec
-
@author potterec
- */
+public interface SoftTextDialogInputListener extends InputListener {
- public static int COMPLETE = 0;
- public static int CANCEL = 1;
+
- public void onSoftText(int action, String text);
+
+}
[/java]
InputManager
[java]
This patch file was generated by NetBeans IDE
Following Index: paths are relative to: D:UserspotterecDocumentsjMonkeyProjectsjME3srccorecomjme3input
This patch can be applied using context Tools: Patch action on respective folder.
It uses platform neutral UTF-8 encoding and n newlines.
Above lines and this line are ignored by the patching process.
Index: InputManager.java
— InputManager.java Base (BASE)
+++ InputManager.java Locally Modified (Based On LOCAL)
@@ -105,6 +105,7 @@
private ArrayList<RawInputListener> rawListeners = new ArrayList<RawInputListener>();
private RawInputListener[] rawListenerArray = null;
private ArrayList<InputEvent> inputQueue = new ArrayList<InputEvent>();
- private SoftTextDialogInput softTextDialogInput = null;
private static class Mapping {
@@ -730,6 +731,13 @@
}
}
- public void setSoftTextDialogInput(SoftTextDialogInput input) {
-
softTextDialogInput = input;<br />
- }
- public SoftTextDialogInput getSoftTextDialogInput() {
-
return softTextDialogInput;<br />
- }
+
private void processQueue() {
int queueSize = inputQueue.size();
RawInputListener[] array = getRawListenerArray();
[/java]
OGLESContext
[java]
This patch file was generated by NetBeans IDE
Following Index: paths are relative to: D:UserspotterecDocumentsjMonkeyProjectsjME3srcandroidcomjme3systemandroid
This patch can be applied using context Tools: Patch action on respective folder.
It uses platform neutral UTF-8 encoding and n newlines.
Above lines and this line are ignored by the patching process.
Index: OGLESContext.java
— OGLESContext.java Base (BASE)
+++ OGLESContext.java Locally Modified (Based On LOCAL)
@@ -241,6 +241,8 @@
if (app.getInputManager() != null) {
app.getInputManager().addMapping(ESCAPE_EVENT, new TouchTrigger(TouchInput.KEYCODE_BACK));
app.getInputManager().addListener((AndroidHarness) ctx, new String[]{ESCAPE_EVENT});
+
-
app.getInputManager().setSoftTextDialogInput((AndroidHarness)ctx);<br />
}
}
[/java]
AndroidHarness
[java]
This patch file was generated by NetBeans IDE
Following Index: paths are relative to: D:UserspotterecDocumentsjMonkeyProjectsjME3srcandroidcomjme3app
This patch can be applied using context Tools: Patch action on respective folder.
It uses platform neutral UTF-8 encoding and n newlines.
Above lines and this line are ignored by the patching process.
Index: AndroidHarness.java
— AndroidHarness.java Base (BASE)
+++ AndroidHarness.java Locally Modified (Based On LOCAL)
@@ -2,22 +2,27 @@
import android.app.Activity;
import android.app.AlertDialog;
+import android.app.Dialog;
import android.content.DialogInterface;
import android.content.pm.ActivityInfo;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.NinePatchDrawable;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
+import android.text.InputType;
import android.view.Display;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.view.Window;
import android.view.WindowManager;
+import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
+import com.jme3.input.SoftTextDialogInput;
import com.jme3.input.android.AndroidInput;
+import com.jme3.input.controls.SoftTextDialogInputListener;
import com.jme3.input.controls.TouchListener;
import com.jme3.input.event.TouchEvent;
import com.jme3.system.AppSettings;
@@ -40,7 +45,7 @@
-
@author Kirill
-
@author larynx
*/
-public class AndroidHarness extends Activity implements TouchListener, DialogInterface.OnClickListener {
+public class AndroidHarness extends Activity implements TouchListener, DialogInterface.OnClickListener, SoftTextDialogInput {
protected final static Logger logger = Logger.getLogger(AndroidHarness.class.getName());
@@ -131,6 +136,15 @@
private FrameLayout frameLayout = null;
final private String ESCAPE_EVENT = "TouchEscape";
- // variables for SoftTextDialogInput
- private FrameLayout layoutTextDialogInput;
- private EditText editTextDialogInput;
- private String dialogTitle = "";
- private String dialogInitialValue = "";
- private AlertDialog dialogTextInput;
- private int editTextDialogInputType = InputType.TYPE_CLASS_TEXT;
- private SoftTextDialogInputListener softTextDialogInputListener = null;
+
static {
try {
System.loadLibrary("bulletjme");
@@ -391,4 +405,90 @@
}
}
}
+
- public void requestDialog(final int id, final String title, final String initialValue, SoftTextDialogInputListener listener) {
-
softTextDialogInputListener = listener;<br />
-
dialogInitialValue = initialValue;<br />
-
dialogTitle = title;<br />
+
-
runOnUiThread(new Runnable() {<br />
-
@Override<br />
-
public void run() {<br />
-
switch (id) {<br />
-
case SoftTextDialogInput.TEXT_ENTRY_DIALOG:<br />
-
editTextDialogInputType = InputType.TYPE_CLASS_TEXT;<br />
-
showDialog(SoftTextDialogInput.TEXT_ENTRY_DIALOG);<br />
-
case SoftTextDialogInput.NUMERIC_ENTRY_DIALOG:<br />
-
editTextDialogInputType = InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL | InputType.TYPE_NUMBER_FLAG_SIGNED;<br />
-
showDialog(SoftTextDialogInput.TEXT_ENTRY_DIALOG);<br />
-
case SoftTextDialogInput.NUMERIC_KEYPAD_DIALOG:<br />
-
editTextDialogInputType = InputType.TYPE_CLASS_PHONE;<br />
-
showDialog(SoftTextDialogInput.TEXT_ENTRY_DIALOG);<br />
-
default:<br />
-
editTextDialogInputType = InputType.TYPE_CLASS_TEXT;<br />
-
showDialog(SoftTextDialogInput.TEXT_ENTRY_DIALOG);<br />
}
-
}<br />
-
});<br />
+
- }
+
+
-
@Override
- protected Dialog onCreateDialog(int id) {
-
switch (id) {<br />
-
case SoftTextDialogInput.TEXT_ENTRY_DIALOG:<br />
-
layoutTextDialogInput = new FrameLayout(this);<br />
-
editTextDialogInput = new EditText(this);<br />
-
editTextDialogInput.setWidth(LayoutParams.FILL_PARENT);<br />
-
editTextDialogInput.setHeight(LayoutParams.FILL_PARENT);<br />
-
editTextDialogInput.setPadding(20, 20, 20, 20);<br />
-
editTextDialogInput.setGravity(Gravity.FILL_HORIZONTAL);<br />
+
-
editTextDialogInput.setText(dialogInitialValue);<br />
-
editTextDialogInput.setInputType(editTextDialogInputType);<br />
-
layoutTextDialogInput.addView(editTextDialogInput);<br />
+
-
dialogTextInput = new AlertDialog.Builder(AndroidHarness.this)<br />
-
.setTitle(dialogTitle)<br />
-
.setView(layoutTextDialogInput)<br />
-
.setPositiveButton("OK",<br />
-
new DialogInterface.OnClickListener() {<br />
-
public void onClick(DialogInterface dialog, int whichButton) {<br />
-
/* User clicked OK, send COMPLETE action<br />
-
* and text */<br />
-
if (softTextDialogInputListener != null) {<br />
-
softTextDialogInputListener.onSoftText(SoftTextDialogInputListener.COMPLETE, editTextDialogInput.getText().toString());<br />
-
}<br />
-
}<br />
-
})<br />
-
.setNegativeButton("Cancel",<br />
-
new DialogInterface.OnClickListener() {<br />
-
public void onClick(DialogInterface dialog, int whichButton) {<br />
-
/* User clicked CANCEL, send CANCEL action<br />
-
* and text */<br />
-
if (softTextDialogInputListener != null) {<br />
-
softTextDialogInputListener.onSoftText(SoftTextDialogInputListener.CANCEL, editTextDialogInput.getText().toString());<br />
-
}<br />
-
}<br />
-
})<br />
-
.create();<br />
+
-
dialogTextInput.setOnDismissListener(new DialogInterface.OnDismissListener() {<br />
+
-
public void onDismiss(DialogInterface di) {<br />
-
logger.log(Level.INFO, "onDismiss");<br />
-
layoutTextDialogInput.removeView(editTextDialogInput);<br />
-
removeDialog(SoftTextDialogInput.TEXT_ENTRY_DIALOG);<br />
-
}<br />
-
});<br />
-
return dialogTextInput;<br />
+
-
default:<br />
+
-
}<br />
-
return null;<br />
+
- }
+
+}
[/java]
So this opens a dialog to enter the text to go into the field. I thought the idea was to open the software keyboard so that the text can be entered directly?
Also, where’s the integration with nifty? I think it should go into the InputSystem spi, which will then call on a method on the context or JmeSystem to open software keyboard on supported platforms.
Read the complete thread, @iwgeric said that poping the soft keyboard doesn’t work, that’s why he’s looking for an alternate solution.