299 lines
11 KiB
Java
299 lines
11 KiB
Java
package org.supertuxkart.stk_dbg;
|
|
|
|
import org.libsdl.app.SDLActivity;
|
|
import org.supertuxkart.stk_dbg.STKInputConnection;
|
|
|
|
import android.content.Context;
|
|
import android.text.InputType;
|
|
import android.view.inputmethod.EditorInfo;
|
|
import android.view.inputmethod.InputConnection;
|
|
import android.view.inputmethod.InputMethodManager;
|
|
import android.view.KeyEvent;
|
|
import android.view.View;
|
|
import android.widget.EditText;
|
|
import android.widget.TextView;
|
|
|
|
// We need to extend EditText instead of view to allow copying to our STK
|
|
// editbox
|
|
public class STKEditText extends EditText
|
|
{
|
|
private int m_composing_start;
|
|
|
|
private int m_composing_end;
|
|
|
|
/* Used to prevent copying text to non focused widget in STK. */
|
|
private int m_stk_widget_id;
|
|
|
|
private STKInputConnection m_stk_input_connection;
|
|
|
|
/* Used to avoid infinite calling updateSTKEditBox if setText currently
|
|
* by jni or clearing text when out focus. */
|
|
private boolean m_from_stk_editbox;
|
|
// ------------------------------------------------------------------------
|
|
private native static void editText2STKEditbox(int widget_id,
|
|
String full_text, int start,
|
|
int end,
|
|
int composing_start,
|
|
int composing_end);
|
|
// ------------------------------------------------------------------------
|
|
private native static void handleActionNext(int widget_id);
|
|
// ------------------------------------------------------------------------
|
|
private native static void handleLeftRight(boolean left, int widget_id);
|
|
// ------------------------------------------------------------------------
|
|
public STKEditText(Context context)
|
|
{
|
|
super(context);
|
|
setInputType(InputType.TYPE_CLASS_TEXT);
|
|
setFocusableInTouchMode(true);
|
|
m_composing_start = 0;
|
|
m_composing_end = 0;
|
|
m_stk_widget_id = -1;
|
|
m_from_stk_editbox = false;
|
|
m_stk_input_connection = null;
|
|
setOnEditorActionListener(new EditText.OnEditorActionListener()
|
|
{
|
|
@Override
|
|
public boolean onEditorAction(TextView v, int action_id,
|
|
KeyEvent event)
|
|
{
|
|
if (action_id == EditorInfo.IME_ACTION_NEXT)
|
|
{
|
|
handleActionNext(m_stk_widget_id);
|
|
// STK will handle the closing of the screen keyboard
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
});
|
|
setOnKeyListener(new EditText.OnKeyListener()
|
|
{
|
|
@Override
|
|
public boolean onKey(View v, int keyCode, KeyEvent event)
|
|
{
|
|
// Up or down pressed, leave focus
|
|
if (keyCode == KeyEvent.KEYCODE_DPAD_UP ||
|
|
keyCode == KeyEvent.KEYCODE_DPAD_DOWN)
|
|
{
|
|
if (event.getAction() == KeyEvent.ACTION_DOWN)
|
|
{
|
|
beforeHideKeyboard(true/*clear_text*/);
|
|
SDLActivity.onNativeKeyDown(keyCode);
|
|
SDLActivity.onNativeKeyUp(keyCode);
|
|
}
|
|
return true;
|
|
}
|
|
// For left or right let STK decides
|
|
else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT &&
|
|
getSelectionStart() == 0)
|
|
{
|
|
if (event.getAction() == KeyEvent.ACTION_DOWN)
|
|
{
|
|
beforeHideKeyboard(true/*clear_text*/);
|
|
handleLeftRight(true, m_stk_widget_id);
|
|
}
|
|
else
|
|
updateSTKEditBox();
|
|
return true;
|
|
}
|
|
else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT &&
|
|
getSelectionEnd() == getText().length())
|
|
{
|
|
if (event.getAction() == KeyEvent.ACTION_DOWN)
|
|
{
|
|
beforeHideKeyboard(true/*clear_text*/);
|
|
handleLeftRight(false, m_stk_widget_id);
|
|
}
|
|
else
|
|
updateSTKEditBox();
|
|
return true;
|
|
}
|
|
else if (keyCode == KeyEvent.KEYCODE_ENTER)
|
|
{
|
|
if (event.getAction() == KeyEvent.ACTION_DOWN)
|
|
handleActionNext(m_stk_widget_id);
|
|
return true;
|
|
}
|
|
|
|
// Requires for hardware key like "Ctrl-a" so it will select
|
|
// all text in stk edit box
|
|
updateSTKEditBox();
|
|
return false;
|
|
}
|
|
});
|
|
}
|
|
// ------------------------------------------------------------------------
|
|
@Override
|
|
public InputConnection onCreateInputConnection(EditorInfo out_attrs)
|
|
{
|
|
if (m_stk_input_connection == null)
|
|
{
|
|
m_stk_input_connection = new STKInputConnection(
|
|
super.onCreateInputConnection(out_attrs), this);
|
|
}
|
|
out_attrs.actionLabel = null;
|
|
out_attrs.inputType = getInputType();
|
|
out_attrs.imeOptions = EditorInfo.IME_ACTION_NEXT |
|
|
EditorInfo.IME_FLAG_NO_FULLSCREEN |
|
|
EditorInfo.IME_FLAG_NO_EXTRACT_UI;
|
|
return m_stk_input_connection;
|
|
}
|
|
// ------------------------------------------------------------------------
|
|
@Override
|
|
public boolean onCheckIsTextEditor() { return true; }
|
|
// ------------------------------------------------------------------------
|
|
@Override
|
|
public boolean onKeyPreIme(int key_code, KeyEvent event)
|
|
{
|
|
// Always remove the focus on STKEdit when pressing back button in
|
|
// phone, which hideSoftInputFromWindow is called by java itself
|
|
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK &&
|
|
event.getAction() == KeyEvent.ACTION_UP)
|
|
beforeHideKeyboard(false/*clear_text*/);
|
|
return false;
|
|
}
|
|
// ------------------------------------------------------------------------
|
|
public void setComposingRegion(int start, int end)
|
|
{
|
|
// From doc of InputConnectionWrapper, it says:
|
|
// Editor authors, be ready to accept a start that is greater than end.
|
|
if (start != end && start > end)
|
|
{
|
|
m_composing_end = start;
|
|
m_composing_start = end;
|
|
}
|
|
else
|
|
{
|
|
m_composing_start = start;
|
|
m_composing_end = end;
|
|
}
|
|
}
|
|
// ------------------------------------------------------------------------
|
|
public void updateSTKEditBox()
|
|
{
|
|
if (!isFocused() || m_from_stk_editbox)
|
|
return;
|
|
editText2STKEditbox(m_stk_widget_id, getText().toString(),
|
|
getSelectionStart(), getSelectionEnd(), m_composing_start,
|
|
m_composing_end);
|
|
}
|
|
// ------------------------------------------------------------------------
|
|
public void beforeHideKeyboard(final boolean clear_text)
|
|
{
|
|
try
|
|
{
|
|
if (clear_text)
|
|
{
|
|
// No need updating stk editbox on clearing text when out focus
|
|
m_from_stk_editbox = true;
|
|
{
|
|
super.clearComposingText();
|
|
super.getText().clear();
|
|
}
|
|
m_from_stk_editbox = false;
|
|
}
|
|
clearFocus();
|
|
setVisibility(View.GONE);
|
|
SDLActivity.reFocusAfterSTKEditText();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
m_from_stk_editbox = false;
|
|
}
|
|
}
|
|
// ------------------------------------------------------------------------
|
|
/* Called by STK with JNI to set this view with new text (like user focus
|
|
* a new editbox in stk, or change cursor / selection). */
|
|
public void setTextFromSTK(int widget_id, final String text,
|
|
int selection_start, int selection_end)
|
|
{
|
|
m_stk_widget_id = widget_id;
|
|
// Avoid sending the newly set text back to STK at the same time
|
|
m_from_stk_editbox = true;
|
|
try
|
|
{
|
|
String old_text = getText().toString();
|
|
boolean text_changed = !text.equals(old_text);
|
|
if (text_changed)
|
|
{
|
|
super.clearComposingText();
|
|
super.setText(text);
|
|
m_stk_input_connection.setComposingRegion(0, 0);
|
|
}
|
|
|
|
if (selection_start != selection_end &&
|
|
selection_start > selection_end)
|
|
{
|
|
int temp = selection_end;
|
|
selection_end = selection_start;
|
|
selection_start = temp;
|
|
}
|
|
if (selection_start < 0)
|
|
selection_start = 0;
|
|
if (selection_end > length())
|
|
selection_end = length();
|
|
|
|
if (text_changed)
|
|
{
|
|
InputMethodManager imm = (InputMethodManager)getContext()
|
|
.getSystemService(Context.INPUT_METHOD_SERVICE);
|
|
if (imm != null)
|
|
{
|
|
// From google, You should call this when the text within
|
|
// your view changes outside of the normal input method or
|
|
// key input flow, such as when an application calls
|
|
// TextView.setText().
|
|
imm.restartInput(this);
|
|
}
|
|
}
|
|
setSelection(selection_start, selection_end);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
m_from_stk_editbox = false;
|
|
}
|
|
m_from_stk_editbox = false;
|
|
}
|
|
// ------------------------------------------------------------------------
|
|
public STKInputConnection getSTKInputConnection()
|
|
{ return m_stk_input_connection; }
|
|
// ------------------------------------------------------------------------
|
|
public void configType(final int type)
|
|
{
|
|
int it = InputType.TYPE_CLASS_TEXT;
|
|
// Check text_box_widget.hpp for definition
|
|
switch (type)
|
|
{
|
|
case 0:
|
|
{
|
|
it = InputType.TYPE_CLASS_TEXT;
|
|
break;
|
|
}
|
|
case 1:
|
|
{
|
|
it = InputType.TYPE_CLASS_TEXT |
|
|
InputType.TYPE_TEXT_FLAG_CAP_SENTENCES;
|
|
break;
|
|
}
|
|
case 2:
|
|
{
|
|
it = InputType.TYPE_TEXT_VARIATION_PASSWORD;
|
|
break;
|
|
}
|
|
case 3:
|
|
{
|
|
it = InputType.TYPE_CLASS_NUMBER;
|
|
break;
|
|
}
|
|
case 4:
|
|
{
|
|
it = InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
if (it != getInputType())
|
|
setInputType(it);
|
|
}
|
|
}
|