abouttreesummaryrefslogcommitdiff
path: root/srcs/juloo.keyboard2/KeyEventHandler.java
blob: 70b54b9b618846b3c2db8e29aef2daeac81f4a97 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
package juloo.keyboard2;

import android.os.Looper;
import android.view.KeyEvent;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;

class KeyEventHandler implements Config.IKeyEventHandler
{
  IReceiver _recv;
  Autocapitalisation _autocap;

  public int actionId; // Action performed by the Action key.

  public KeyEventHandler(Looper looper, IReceiver recv)
  {
    _recv = recv;
    _autocap = new Autocapitalisation(looper,
        this.new Autocapitalisation_callback());
  }

  /** Editing just started. */
  public void started(EditorInfo info)
  {
    _autocap.started(info, _recv.getCurrentInputConnection());
  }

  /** Selection has been updated. */
  public void selection_updated(int oldSelStart, int newSelStart)
  {
    _autocap.selection_updated(oldSelStart, newSelStart);
  }

  /** A key has been released. */
  public void key_up(KeyValue key, Pointers.Modifiers mods)
  {
    if (key == null)
      return;
    switch (key.getKind())
    {
      case Char: send_text(String.valueOf(key.getChar())); break;
      case String: send_text(key.getString()); break;
      case Event:
        switch (key.getEvent())
        {
          case CONFIG: _recv.showKeyboardConfig(); break;
          case SWITCH_TEXT: _recv.set_layout(Layout.Current); break;
          case SWITCH_NUMERIC: _recv.set_layout(Layout.Numeric); break;
          case SWITCH_EMOJI: _recv.setPane_emoji(); break;
          case SWITCH_BACK_EMOJI: _recv.setPane_normal(); break;
          case CHANGE_METHOD: _recv.switchInputMethod(); break;
          case CHANGE_METHOD_PREV: _recv.switchToPrevInputMethod(); break;
          case ACTION:
            InputConnection conn = _recv.getCurrentInputConnection();
            if (conn != null)
              conn.performEditorAction(actionId);
            break;
          case SWITCH_SECOND: _recv.set_layout(Layout.Secondary); break;
          case SWITCH_SECOND_BACK: _recv.set_layout(Layout.Primary); break;
          case SWITCH_GREEKMATH: _recv.set_layout(Layout.Greekmath); break;
          case CAPS_LOCK: _recv.set_shift_state(true, true); break;
          case SWITCH_VOICE_TYPING: _recv.switch_voice_typing(); break;
        }
        break;
      case Keyevent:
        handleKeyUpWithModifier(key.getKeyevent(), mods);
        break;
      case Modifier:
        break;
      case Editing:
        send_context_menu_action(action_of_editing_key(key.getEditing()));
        break;
    }
  }

  static int action_of_editing_key(KeyValue.Editing e)
  {
    switch (e)
    {
      case COPY: return android.R.id.copy;
      case PASTE: return android.R.id.paste;
      case CUT: return android.R.id.cut;
      case SELECT_ALL: return android.R.id.selectAll;
      case SHARE: return android.R.id.shareText;
      case PASTE_PLAIN: return android.R.id.pasteAsPlainText;
      case UNDO: return android.R.id.undo;
      case REDO: return android.R.id.redo;
      case REPLACE: return android.R.id.replaceText;
      case ASSIST: return android.R.id.textAssist;
      case AUTOFILL: return android.R.id.autofill;
      default: return -1; // sad
    }
  }

  // private void handleDelKey(int before, int after)
  // {
  //  CharSequence selection = getCurrentInputConnection().getSelectedText(0);

  //  if (selection != null && selection.length() > 0)
  //  getCurrentInputConnection().commitText("", 1);
  //  else
  //  getCurrentInputConnection().deleteSurroundingText(before, after);
  // }

  int sendMetaKey(int eventCode, int metaFlags, int metaState, boolean down)
  {
    int action;
    int updatedMetaState;
    if (down) { action = KeyEvent.ACTION_DOWN; updatedMetaState = metaState | metaFlags; }
    else { action = KeyEvent.ACTION_UP; updatedMetaState = metaState & ~metaFlags; }
    send_keyevent(action, eventCode, metaState);
    return updatedMetaState;
  }

  int sendMetaKeyForModifier(KeyValue.Modifier mod, int metaState, boolean down)
  {
    switch (mod)
    {
      case CTRL:
        return sendMetaKey(KeyEvent.KEYCODE_CTRL_LEFT, KeyEvent.META_CTRL_LEFT_ON | KeyEvent.META_CTRL_ON, metaState, down);
      case ALT:
        return sendMetaKey(KeyEvent.KEYCODE_ALT_LEFT, KeyEvent.META_ALT_LEFT_ON | KeyEvent.META_ALT_ON, metaState, down);
      case SHIFT:
        return sendMetaKey(KeyEvent.KEYCODE_SHIFT_LEFT, KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_SHIFT_ON, metaState, down);
      case META:
        return sendMetaKey(KeyEvent.KEYCODE_META_LEFT, KeyEvent.META_META_LEFT_ON | KeyEvent.META_META_ON, metaState, down);
      default: return metaState;
    }
  }

  /*
   * Don't set KeyEvent.FLAG_SOFT_KEYBOARD.
   */
  void handleKeyUpWithModifier(int keyCode, Pointers.Modifiers mods)
  {
    int metaState = 0;
    for (int i = 0; i < mods.size(); i++)
      metaState = sendMetaKeyForModifier(mods.get(i), metaState, true);
    send_keyevent(KeyEvent.ACTION_DOWN, keyCode, metaState);
    send_keyevent(KeyEvent.ACTION_UP, keyCode, metaState);
    for (int i = mods.size() - 1; i >= 0; i--)
      metaState = sendMetaKeyForModifier(mods.get(i), metaState, false);
  }

  void send_keyevent(int eventAction, int eventCode, int meta)
  {
    InputConnection conn = _recv.getCurrentInputConnection();
    if (conn == null)
      return;
    conn.sendKeyEvent(new KeyEvent(1, 1, eventAction, eventCode, 0, meta));
    if (eventAction == KeyEvent.ACTION_UP)
      _autocap.event_sent(eventCode, meta);
  }

  void send_text(CharSequence text)
  {
    InputConnection conn = _recv.getCurrentInputConnection();
    if (conn == null)
      return;
    conn.commitText(text, 1);
    _autocap.typed(text);
  }

  /** See {!InputConnection.performContextMenuAction}. */
  void send_context_menu_action(int id)
  {
    InputConnection conn = _recv.getCurrentInputConnection();
    if (conn == null)
      return;
    conn.performContextMenuAction(id);
  }

  public enum Layout
  {
    Current, // The primary or secondary layout
    Primary,
    Secondary,
    Numeric,
    Greekmath
  }

  public static interface IReceiver
  {
    public void switchInputMethod();
    public void switchToPrevInputMethod();
    public void switch_voice_typing();
    public void setPane_emoji();
    public void setPane_normal();
    public void showKeyboardConfig();
    public void set_layout(Layout l);
    public void set_shift_state(boolean state, boolean lock);
    public InputConnection getCurrentInputConnection();
  }

  class Autocapitalisation_callback implements Autocapitalisation.Callback
  {
    @Override
    public void update_shift_state(boolean should_enable, boolean should_disable)
    {
      if (should_enable)
        _recv.set_shift_state(true, false);
      else if (should_disable)
        _recv.set_shift_state(false, false);
    }
  }
}