Android输入法

677 阅读2分钟

1. 相关资料

2. 相关开源项目

3. 简单验证

    private fun funcInput(vararg content:CharSequence){
        var content = "随机输入字符串"
        mInputConnection?.commitText(content, 1)
    }
    private fun funcSelectAll(){
        mInputConnection?.performContextMenuAction(android.R.id.selectAll)
    }
    private fun funcBackSpaceClick(){
        val selectedText =
            mInputConnection?.getSelectedText(InputConnection.GET_TEXT_WITH_STYLES)
        if (TextUtils.isEmpty(selectedText)) {
            mInputConnection?.deleteSurroundingText(1, 0)
        } else {
            mInputConnection?.commitText("", 1)
        }
    }
    private fun funDeleteClick(){
        val selectedText =
            mInputConnection?.getSelectedText(InputConnection.GET_TEXT_WITH_STYLES)
        if (TextUtils.isEmpty(selectedText)) {
            mInputConnection?.sendKeyEvent(KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_FORWARD_DEL))
        } else {
            mInputConnection?.commitText("", 1)
        }
    }
    private fun funcBackSpaceLongClick():Boolean{
        val selectedText = mInputConnection?.getTextBeforeCursor(
            Int.MAX_VALUE,
            InputConnection.CURSOR_UPDATE_IMMEDIATE
        )
        return mInputConnection?.deleteSurroundingText(selectedText?.length ?: 0, 0) ?: true
    }
    private fun funcClear(){
        mInputConnection?.performContextMenuAction(android.R.id.selectAll)
        mInputConnection?.commitText("", 1)
    }
    private fun stopSlectText(){
        mInputConnection?.sendKeyEvent(KeyEvent(KeyEvent.ACTION_UP,KeyEvent.KEYCODE_SHIFT_LEFT))
        mInputConnection?.sendKeyEvent(KeyEvent(KeyEvent.ACTION_UP,KeyEvent.KEYCODE_SHIFT_RIGHT))
    }
    private fun funcCursorMoveLeft(){
        stopSlectText()
        mInputConnection?.sendKeyEvent(KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_DPAD_LEFT))
    }
    private fun funcCursorMoveRight(){
        stopSlectText()
        mInputConnection?.sendKeyEvent(KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_DPAD_RIGHT))
    }
    private fun funcCursorMoveUp(){
        stopSlectText()
        mInputConnection?.sendKeyEvent(KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_DPAD_UP))
    }
    private fun funcCursorMoveDown(){
        stopSlectText()
        mInputConnection?.sendKeyEvent(KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_DPAD_DOWN))
    }
    private fun funcShiftLeft(){
        mInputConnection?.sendKeyEvent(KeyEvent(KeyEvent.ACTION_UP,KeyEvent.KEYCODE_SHIFT_RIGHT))

        mInputConnection?.sendKeyEvent(KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_SHIFT_LEFT))
        mInputConnection?.sendKeyEvent(KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_DPAD_LEFT))
    }
    private fun funcShiftRight(){
        mInputConnection?.sendKeyEvent(KeyEvent(KeyEvent.ACTION_UP,KeyEvent.KEYCODE_SHIFT_LEFT))

        mInputConnection?.sendKeyEvent(KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_SHIFT_RIGHT))
        mInputConnection?.sendKeyEvent(KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_DPAD_RIGHT))
    }
    private fun funcShiftUp(){
        mInputConnection?.sendKeyEvent(KeyEvent(KeyEvent.ACTION_UP,KeyEvent.KEYCODE_SHIFT_RIGHT))

        mInputConnection?.sendKeyEvent(KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_SHIFT_LEFT))
        mInputConnection?.sendKeyEvent(KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_DPAD_UP))
    }
    private fun funcShiftDown(){
        mInputConnection?.sendKeyEvent(KeyEvent(KeyEvent.ACTION_UP,KeyEvent.KEYCODE_SHIFT_RIGHT))

        mInputConnection?.sendKeyEvent(KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_SHIFT_LEFT))
        mInputConnection?.sendKeyEvent(KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_DPAD_DOWN))
    }
    private fun funcGetSelectedText(): CharSequence? {
        val selectedText =
            mInputConnection?.getSelectedText(InputConnection.GET_TEXT_WITH_STYLES)
        Log.d("TagInput","funcGetSelectedText. selectedText:\n"+selectedText)
        return selectedText
    }
    private fun funcMoveHome(){
        mInputConnection?.sendKeyEvent(KeyEvent(KeyEvent.ACTION_UP,KeyEvent.KEYCODE_SHIFT_RIGHT))
        mInputConnection?.sendKeyEvent(KeyEvent(KeyEvent.ACTION_UP,KeyEvent.KEYCODE_SHIFT_LEFT))

        mInputConnection?.sendKeyEvent(KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_MOVE_HOME))
    }
    private fun funcMoveEnd(){
        mInputConnection?.sendKeyEvent(KeyEvent(KeyEvent.ACTION_UP,KeyEvent.KEYCODE_SHIFT_RIGHT))
        mInputConnection?.sendKeyEvent(KeyEvent(KeyEvent.ACTION_UP,KeyEvent.KEYCODE_SHIFT_LEFT))

        mInputConnection?.sendKeyEvent(KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_MOVE_END))
    }
    private fun funcShiftHome(){
        mInputConnection?.sendKeyEvent(KeyEvent(KeyEvent.ACTION_UP,KeyEvent.KEYCODE_SHIFT_RIGHT))

        mInputConnection?.sendKeyEvent(KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_SHIFT_LEFT))
        mInputConnection?.sendKeyEvent(KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_MOVE_HOME))
    }
    private fun funcShiftEnd(){
        mInputConnection?.sendKeyEvent(KeyEvent(KeyEvent.ACTION_UP,KeyEvent.KEYCODE_SHIFT_LEFT))

        mInputConnection?.sendKeyEvent(KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_SHIFT_RIGHT))
        mInputConnection?.sendKeyEvent(KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_MOVE_END))
    }

4. 具体技术点

1. 使用 InputConnection 无法选中光标所在行最后一个字符. 试验MIUI+也无法选中当前行最后一个字符,IOS设备是可以的.
```kotlin
mInputConnection?.sendKeyEvent(KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_SHIFT_RIGHT))
mInputConnection?.sendKeyEvent(KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_MOVE_END))
```
2. 使用2个栈(Java中的Stack)实例,可以实现自定义输入法的 上一步/下一步 功能.
  1. 每次触发内容变更后,都将最新内容压入 pre栈
  2. 每次执行 上一步,将 pre栈栈顶的元素取出,移入 next栈. 然后显示pre栈当前栈顶元素
  3. 每次执行 下一步,将 next栈栈顶元素取出,移入 pre栈. 然后显示pre栈当前栈顶元素 //伪代码
//1:每次触发内容变更后,都将最新内容压入 pre栈
//2:每次执行 上一步,将 pre栈栈顶的元素取出,移入 next栈. 然后显示pre栈当前栈顶元素
//3:每次执行 下一步,将 next栈栈顶元素取出,移入 pre栈. 然后显示pre栈当前栈顶元素

private fun gainCurrentContent():String{
    String content = "";
    Charsequence before = inputConnection.textCursorBefore(**)
    Charsequence after = inputConnection.textCursorBefore(**)
    content = before.toString + after.toString();
    return content;
}
private fun changeContent(){
    //改变当前内容
    ****
    //保存最新内容T,将T压入pre
    String curr = gainCurrentContent();
    pre.push(curr);
}
private fun goPre(){
    String curr = pre.poll();
    next.push(curr);
    String show = pre.peek();
    replaceContent(show);
}
private fun goNext(){
    String curr = next.poll();
    pre.push(curr);
    String show = pre.peek();
    replaceContent(show);
}
private fun replaceContent(content:Charsequence){
    替换内容为 content
}