Files
stk-code_catmod/android/src/main/java/STKEditText.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);
}
}