LoginSignup
1
1

More than 3 years have passed since last update.

Androidアプリでソフトウェアキーボードの入力を1文字ずつ検出する

Last updated at Posted at 2020-01-24

概要

Androidで1文字ずつ文字の検出をしようと思ってonKey~をつかってもできませんでした.
ちょっと調べたところ,ソフトウェアキーボードのキーボードイベントを拾ってくれないらしいです.
https://developer.android.com/training/keyboard-input/commands

ので,1文字ずつ文字の検出する機能を実装しました.

EditTextの場合,TextChangedListenerを使えば一応できますが,入力ではなくてEditTextのテキストが変わったら反応するため処理がめんどくさいので使いません.

ソースコード

実装

今回はEditTextの場合で実装していきます.
この実装方法だと(たぶん)ほかのViewでもつかえます.WebViewでは使えました.

やることは簡単で,もとになるViewを継承してonCreateInputConnectiondispatchKeyEventをオーバーライトするだけです.

dispatchKeyEventKeyEventを拾えるので,そこで入力時にしたいことを記述します.

MyEditText.kt
package com.usr.myedittexttest

import android.content.Context
import android.util.AttributeSet
import android.util.Log
import android.view.KeyEvent
import android.view.inputmethod.BaseInputConnection
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputConnection
import android.widget.EditText

class MyEditText : EditText {

    constructor(context: Context?) : super(context)
    constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)

    override fun onCreateInputConnection(outAttrs: EditorInfo): InputConnection {
        return BaseInputConnection(this, false)
    }

    override fun dispatchKeyEvent(event: KeyEvent): Boolean {
        val dispatchFirst = super.dispatchKeyEvent(event)

        if (event.action == KeyEvent.ACTION_UP){
            val charCode = event.unicodeChar
            // 入力時の処理
            Log.d("MyEditText", "onKey keyCode=$charCode")
            Log.d("MyEditText", "onKey input=${charCode.toChar()}")
        }
        return dispatchFirst
    }
}

新しいViewはもとのViewと同じように使用できます.

MainActivity
package com.usr.myedittexttest

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle

class MainActivity : AppCompatActivity() {
    lateinit var myEditText: MyEditText

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        myEditText = findViewById(R.id.my_edit)
    }
}

activity_main.xmlは使うViewを作成したものに変更します.

activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.usr.myedittexttest.MyEditText
        android:id="@+id/my_edit"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

入力を通知するListenerを作成する場合

入力したことを通知するListenerを使ったほうが便利なのでListenerを作成します.

まずListenerを作成

InputListener
package com.usr.myedittexttest

import java.util.*

interface InputListener: EventListener {
    fun onKey(text: Char)
}

次にMyEditTextを少し改造

MyEditText
package com.usr.myedittexttest

import android.content.Context
import android.util.AttributeSet
import android.util.Log
import android.view.KeyEvent
import android.view.inputmethod.BaseInputConnection
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputConnection
import android.widget.EditText

class MyEditText : EditText {

    private var listener: InputListener? = null

    constructor(context: Context?) : super(context)
    constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)

    override fun onCreateInputConnection(outAttrs: EditorInfo): InputConnection {
        return BaseInputConnection(this, false)
    }

    override fun dispatchKeyEvent(event: KeyEvent): Boolean {
        val dispatchFirst = super.dispatchKeyEvent(event)

        if (event.action == KeyEvent.ACTION_UP){
            val charCode = event.unicodeChar
            // 入力時の処理
            Log.d("MyEditText", "onKey keyCode=$charCode")
            Log.d("MyEditText", "onKey input=${charCode.toChar()}")
            // 入力を通知
            listener?.onKey(charCode.toChar())
        }
        return dispatchFirst
    }

    fun setListener(listener: InputListener){
        this.listener = listener
    }
}

MainActivityでは入力の通知を受け取った時の処理を記述します.
そのためにInputListenerを実装します.
通知を受け取るとonKeyが呼ばれるので,そこに処理を記述してください.

MainActivity.kt
package com.usr.myedittexttest

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log

class MainActivity : AppCompatActivity(), InputListener{
    lateinit var myEditText: MyEditText

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        myEditText = findViewById(R.id.my_edit)
        myEditText.setListener(this)
    }

    override fun onKey(text: Char) {
        Log.d("MainActivity", "text=$text")
        // TODO something
    }
}

終わりに

勉強し始めたばかりですので,より良い方法があるかと思います.よろしければお教えくださいますと幸いです.

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1