2022-07-24 20:02:48 +02:00
|
|
|
package juloo.keyboard2;
|
|
|
|
|
2022-09-19 22:06:22 +02:00
|
|
|
import android.os.Handler;
|
|
|
|
import android.os.Looper;
|
2022-07-24 20:02:48 +02:00
|
|
|
import android.text.InputType;
|
|
|
|
import android.text.TextUtils;
|
|
|
|
import android.view.inputmethod.EditorInfo;
|
|
|
|
import android.view.inputmethod.InputConnection;
|
|
|
|
import android.view.KeyEvent;
|
|
|
|
|
|
|
|
final class Autocapitalisation
|
|
|
|
{
|
2022-09-19 22:06:22 +02:00
|
|
|
boolean _enabled = false;
|
|
|
|
boolean _should_enable_shift = false;
|
|
|
|
boolean _should_disable_shift = false;
|
|
|
|
boolean _should_update_caps_mode = false;
|
2022-07-30 17:42:58 +02:00
|
|
|
|
2022-09-19 22:06:22 +02:00
|
|
|
Handler _handler;
|
|
|
|
InputConnection _ic;
|
|
|
|
Callback _callback;
|
|
|
|
int _caps_mode;
|
2022-07-30 17:42:58 +02:00
|
|
|
|
|
|
|
/** Keep track of the cursor to recognize cursor movements from typing. */
|
2022-09-19 22:06:22 +02:00
|
|
|
int _cursor;
|
2022-07-30 17:42:58 +02:00
|
|
|
|
2022-09-19 22:06:22 +02:00
|
|
|
static int SUPPORTED_CAPS_MODES =
|
2022-07-30 17:42:58 +02:00
|
|
|
InputType.TYPE_TEXT_FLAG_CAP_SENTENCES |
|
|
|
|
InputType.TYPE_TEXT_FLAG_CAP_WORDS;
|
2022-07-24 20:02:48 +02:00
|
|
|
|
2022-10-15 16:12:25 +02:00
|
|
|
public Autocapitalisation(Looper looper, Callback cb)
|
2022-09-19 22:06:22 +02:00
|
|
|
{
|
2022-10-15 16:12:25 +02:00
|
|
|
_handler = new Handler(looper);
|
|
|
|
_callback = cb;
|
2022-07-24 20:02:48 +02:00
|
|
|
}
|
|
|
|
|
2022-09-19 22:06:22 +02:00
|
|
|
/**
|
|
|
|
* The events are: started, typed, event sent, selection updated
|
|
|
|
* [started] does initialisation work and must be called before any other
|
|
|
|
* event.
|
|
|
|
*/
|
2022-10-15 16:12:25 +02:00
|
|
|
public void started(EditorInfo info, InputConnection ic)
|
2022-07-24 20:02:48 +02:00
|
|
|
{
|
2022-07-30 17:42:58 +02:00
|
|
|
_ic = ic;
|
|
|
|
_caps_mode = info.inputType & TextUtils.CAP_MODE_SENTENCES;
|
|
|
|
if (!Config.globalConfig().autocapitalisation || _caps_mode == 0)
|
2022-07-24 20:02:48 +02:00
|
|
|
{
|
|
|
|
_enabled = false;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
_enabled = true;
|
2022-07-30 17:42:58 +02:00
|
|
|
_should_enable_shift = (info.initialCapsMode != 0);
|
2022-09-19 22:06:22 +02:00
|
|
|
_callback.update_shift_state(_should_enable_shift, true);
|
2022-07-24 20:02:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public void typed(CharSequence c)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < c.length(); i++)
|
2022-09-19 22:06:22 +02:00
|
|
|
type_one_char(c.charAt(i));
|
|
|
|
callback(false);
|
2022-07-24 20:02:48 +02:00
|
|
|
}
|
|
|
|
|
2022-10-16 22:34:21 +02:00
|
|
|
public void event_sent(int code, int meta)
|
2022-07-24 20:02:48 +02:00
|
|
|
{
|
2022-10-16 22:34:21 +02:00
|
|
|
if (meta != 0)
|
|
|
|
{
|
|
|
|
_should_enable_shift = false;
|
|
|
|
_should_update_caps_mode = false;
|
|
|
|
return;
|
|
|
|
}
|
2022-07-24 23:32:14 +02:00
|
|
|
switch (code)
|
|
|
|
{
|
2022-07-30 17:42:58 +02:00
|
|
|
case KeyEvent.KEYCODE_DEL:
|
2022-09-19 22:06:22 +02:00
|
|
|
if (_cursor > 0) _cursor--;
|
|
|
|
_should_update_caps_mode = true;
|
2022-07-24 23:32:14 +02:00
|
|
|
break;
|
|
|
|
}
|
2022-09-19 22:06:22 +02:00
|
|
|
callback(true);
|
2022-07-24 23:32:14 +02:00
|
|
|
}
|
|
|
|
|
2023-08-26 23:37:22 +02:00
|
|
|
public void stop()
|
|
|
|
{
|
|
|
|
_should_enable_shift = false;
|
|
|
|
_should_update_caps_mode = false;
|
|
|
|
callback(true);
|
|
|
|
}
|
|
|
|
|
2022-10-15 16:12:25 +02:00
|
|
|
public static interface Callback
|
|
|
|
{
|
|
|
|
public void update_shift_state(boolean should_enable, boolean should_disable);
|
|
|
|
}
|
|
|
|
|
2022-07-24 23:32:14 +02:00
|
|
|
/** Returns [true] if shift might be disabled. */
|
2022-09-19 22:06:22 +02:00
|
|
|
public void selection_updated(int old_cursor, int new_cursor)
|
2022-07-24 23:32:14 +02:00
|
|
|
{
|
2022-07-30 17:42:58 +02:00
|
|
|
if (new_cursor == _cursor) // Just typing
|
2022-09-19 22:06:22 +02:00
|
|
|
return;
|
2022-10-15 16:12:25 +02:00
|
|
|
if (new_cursor == 0 && _ic != null)
|
2022-09-24 22:36:06 +02:00
|
|
|
{
|
|
|
|
// Detect whether the input box has been cleared
|
|
|
|
CharSequence t = _ic.getTextAfterCursor(1, 0);
|
|
|
|
if (t != null && t.equals(""))
|
|
|
|
_should_update_caps_mode = true;
|
|
|
|
}
|
2022-07-30 17:42:58 +02:00
|
|
|
_cursor = new_cursor;
|
|
|
|
_should_enable_shift = false;
|
2022-09-19 22:06:22 +02:00
|
|
|
callback(true);
|
2022-07-24 20:02:48 +02:00
|
|
|
}
|
|
|
|
|
2022-10-15 16:12:25 +02:00
|
|
|
Runnable delayed_callback = new Runnable()
|
|
|
|
{
|
|
|
|
public void run()
|
|
|
|
{
|
|
|
|
if (_should_update_caps_mode && _ic != null)
|
|
|
|
{
|
|
|
|
_should_enable_shift = _enabled && (_ic.getCursorCapsMode(_caps_mode) != 0);
|
|
|
|
_should_update_caps_mode = false;
|
|
|
|
}
|
|
|
|
_callback.update_shift_state(_should_enable_shift, _should_disable_shift);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
void callback(final boolean might_disable)
|
|
|
|
{
|
|
|
|
_should_disable_shift = might_disable;
|
|
|
|
// The callback must be delayed because [getCursorCapsMode] would sometimes
|
|
|
|
// be called before the editor finished handling the previous event.
|
|
|
|
_handler.postDelayed(delayed_callback, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void type_one_char(char c)
|
|
|
|
{
|
|
|
|
_cursor++;
|
|
|
|
if (is_trigger_character(c))
|
|
|
|
_should_update_caps_mode = true;
|
|
|
|
else
|
|
|
|
_should_enable_shift = false;
|
|
|
|
}
|
|
|
|
|
2022-09-19 22:06:22 +02:00
|
|
|
boolean is_trigger_character(char c)
|
2022-07-24 20:02:48 +02:00
|
|
|
{
|
|
|
|
switch (c)
|
|
|
|
{
|
|
|
|
case ' ':
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|