Hôm bữa thấy người yêu mình xài điện thoại có cái bàn phím mà style nó hơi bị đẹp 😉 Mình cũng thấy hay hay , thế là lân la gạ hỏi hóa ra cô ấy xài Swift Key , thế là cũng cài vào , thế rồi thắc mắc là tại sao họ có thể làm được cái bàn phím đẹp như thế 😃

Thế là sau vài chục phút mày mò , mình cũng làm ra được 1 cái bàn phím của riêng mình , tuy không cute phô mai que như Swift nhưng kệ , trước mắt cứ như thế đã 😀 Rồi từ từ cải tiến sau , cái gì mà chả có phiên bản 1.0 😄

Okay ! Bắt đầu nào , trước tiên là Demo , tính mình là làm cái gì thì làm trước tiên là phải show kết quả đã rồi nói chuyện sau 😄

Vào Settings -> Virtual Keyboard -> Enable cái custom keyboard của mình

Sau đó chỉ việc change bàn phím

Kết quả nè :😜

Hehehe , bắt đầu thôi , đầu tiên các bạn hãy tạo 1 dự án mới , nhớ là không cần tạo Launcher activity nhé , vì trong ví dụ này chúng ta chạy Service , ko chạy launcher activity (Service là gì thì cứ document của Android mà đọc cho nó chính phái)

Sau khi có dự án rồi , trong thư mục layout tạo ra 2 file XML lần lượt là

  • key_preview.xml (file này sẽ là giao diện để cho các bạn preview character khi select phím)
<?xml version="1.0" encoding="utf-8"?>
<TextView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:gravity="center"
    android:background="#5d5d5d"
    android:textColor="@android:color/white"
    android:textStyle="italic"
    android:textSize="30sp"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

</TextView>
  • keyboard.xml (file này là file UI layout của bàn phím)
<?xml version="1.0" encoding="utf-8"?>
<android.inputmethodservice.KeyboardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/keyboard"
    android:layout_alignParentBottom="true"

    android:keyTextColor="@android:color/white"
    android:keyBackground="@drawable/key_background"
    android:keyPreviewLayout="@layout/key_preview"
    android:background="@color/colorPrimaryDark"

    android:layout_width="match_parent"
    android:layout_height="wrap_content">

</android.inputmethodservice.KeyboardView>

Tiếp theo , click chuột phải vào thư mục res->Add resources directory -> xml

!(https://viblo.asia/uploads/5e927348-7b8e-466d-9819-7550d714c51f.png)

Trong thư mục mới tạo này (xml) , các bạn tạo tiếp 2 file

  • method.xml (Đây là file cấu hình kiểu , ngôn ngữ của bàn phím)
<?xml version="1.0" encoding="utf-8"?>
<input-method xmlns:android="http://schemas.android.com/apk/res/android">
    <subtype
        android:label="English (US)"
        android:imeSubtypeLocale="en_US"
        android:imeSubtypeMode="keyboard"
        />

</input-method>
  • qwerty.xml (Đây là file cấu hình các phím)
<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
    android:keyWidth="10%p"
    android:horizontalGap="0px"
    android:verticalGap="0px"
    android:keyHeight="60dp">

    <Row>
        <Key android:keyLabel="1"
            android:keyEdgeFlags="left"
            android:codes="49"/>
        <Key android:keyLabel="2"
            android:codes="50"/>
        <Key android:keyLabel="3"
            android:codes="51"/>
        <Key android:keyLabel="4"
            android:codes="52"/>
        <Key android:keyLabel="5"
            android:codes="53"/>
        <Key android:keyLabel="6"
            android:codes="54"/>
        <Key android:keyLabel="7"
            android:codes="55"/>
        <Key android:keyLabel="8"
            android:codes="56"/>
        <Key android:keyLabel="9"
            android:codes="57"/>
        <Key android:keyLabel="0"
            android:keyEdgeFlags="right"
            android:codes="48"/>
    </Row>

    <Row>
        <Key android:keyLabel="q" android:keyEdgeFlags="left" android:codes="113"/>
        <Key android:keyLabel="w" android:codes="119"/>
        <Key android:keyLabel="e" android:codes="101"/>
        <Key android:keyLabel="r" android:codes="114"/>
        <Key android:keyLabel="t" android:codes="116"/>
        <Key android:keyLabel="y" android:codes="121"/>
        <Key android:keyLabel="u" android:codes="117"/>
        <Key android:keyLabel="i" android:codes="105"/>
        <Key android:keyLabel="o" android:codes="111"/>
        <Key android:keyLabel="p" android:keyEdgeFlags="right" android:codes="112"/>
    </Row>

    <Row>
        <Key android:keyLabel="a" android:keyEdgeFlags="left" android:codes="97"/>
        <Key android:keyLabel="s" android:codes="115"/>
        <Key android:keyLabel="d" android:codes="100"/>
        <Key android:keyLabel="f" android:codes="102"/>
        <Key android:keyLabel="g" android:codes="103"/>
        <Key android:keyLabel="h" android:codes="104"/>
        <Key android:keyLabel="j" android:codes="106"/>
        <Key android:keyLabel="k" android:codes="107"/>
        <Key android:keyLabel="l" android:codes="108"/>
        <Key android:keyLabel="# @" android:keyEdgeFlags="right" android:codes="35,64"/>
    </Row>

    <Row>
        <Key android:keyLabel="CAPS" android:keyEdgeFlags="left" android:codes="-1"/>
        <Key android:keyLabel="z" android:codes="122"/>
        <Key android:keyLabel="x" android:codes="120"/>
        <Key android:keyLabel="c" android:codes="99"/>
        <Key android:keyLabel="v" android:codes="118"/>
        <Key android:keyLabel="b" android:codes="98"/>
        <Key android:keyLabel="n" android:codes="110"/>
        <Key android:keyLabel="m" android:codes="109"/>
        <Key android:keyLabel="." android:codes="46"/>
        <Key android:keyLabel="? ! :" android:keyEdgeFlags="right" android:codes="63,33,58"/>
    </Row>

    <Row android:rowEdgeFlags="bottom">
        <Key android:keyLabel="," android:keyWidth="10%p" android:keyEdgeFlags="left" android:codes="44"/>
        <Key android:keyLabel="/" android:keyWidth="10%p"  android:codes="47"/>
        <Key android:keyLabel="SPACE" android:keyWidth="40%p" android:isRepeatable="true" android:codes="32"/>
        <Key android:keyLabel="DEL" android:keyWidth="20%p" android:isRepeatable="true" android:codes="-5"/>
        <Key android:keyLabel="DONE" android:keyWidth="20%p" android:keyEdgeFlags="right" android:codes="-4"/>

    </Row>

</Keyboard>

Trong này thì các bạn chỉ cần chú ý các tham số sau
android:keyEdgeFlags=”left” => Đây là vị trí của phím
android:keyLabel=”b” => Label hiển thị trên màn hình
android:codes=”98″ => Mã code của ký tự (ASCII code)


Okay , bây giờ , chúng ta cần tạo 1 Service để xử lý đống trên , click phải vào package name và chọn NEw -> Servc

Code của Service

public class EDMTKeyboard extends InputMethodService implements KeyboardView.OnKeyboardActionListener {

    private KeyboardView kv;
    private Keyboard keyboard;

    private  boolean isCaps = false;


    //Press Ctrl+O


    @Override
    public View onCreateInputView() {
        kv = (KeyboardView)getLayoutInflater().inflate(R.layout.keyboard,null);
        keyboard = new Keyboard(this,R.xml.qwerty);
        kv.setKeyboard(keyboard);
        kv.setOnKeyboardActionListener(this);
        return kv;
    }

    @Override
    public void onPress(int i) {

    }

    @Override
    public void onRelease(int i) {

    }

    @Override
    public void onKey(int i, int ints) {

        InputConnection ic = getCurrentInputConnection();
        playClick(i);
        switch (i)
        {
            case Keyboard.KEYCODE_DELETE:
                ic.deleteSurroundingText(1,0);
            break;
            case Keyboard.KEYCODE_SHIFT:
                isCaps = !isCaps;
                keyboard.setShifted(isCaps);
                kv.invalidateAllKeys();
                break;
            case Keyboard.KEYCODE_DONE:
                ic.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_ENTER));
                break;
                default:
                    char code = (char)i;
                    if(Character.isLetter(code) && isCaps)
                        code = Character.toUpperCase(code);
                    ic.commitText(String.valueOf(code),1);
        }

    }

    private void playClick(int i) {

        AudioManager am = (AudioManager)getSystemService(AUDIO_SERVICE);
        switch(i)
        {
            case 32:
                am.playSoundEffect(AudioManager.FX_KEYPRESS_SPACEBAR);
                break;
            case Keyboard.KEYCODE_DONE:
            case 10:
                am.playSoundEffect(AudioManager.FX_KEYPRESS_RETURN);
                break;
            case Keyboard.KEYCODE_DELETE:
                am.playSoundEffect(AudioManager.FX_KEYPRESS_DELETE);
                break;
            default: am.playSoundEffect(AudioManager.FX_KEYPRESS_STANDARD);
        }
    }

    @Override
    public void onText(CharSequence charSequence) {

    }

    @Override
    public void swipeLeft() {

    }

    @Override
    public void swipeRight() {

    }

    @Override
    public void swipeDown() {

    }

    @Override
    public void swipeUp() {

    }
}

@Override
public View onCreateInputView() {
kv = (KeyboardView)getLayoutInflater().inflate(R.layout.keyboard,null);
keyboard = new Keyboard(this,R.xml.qwerty);
kv.setKeyboard(keyboard);
kv.setOnKeyboardActionListener(this);
return kv;
}
Trong hàm này , chúng ta đã xử lý việc khởi tạo 1 virtual keyboard từ giao diện riêng của chúng ta , sau đó set các sự kiện cho nó

@Override
public void onKey(int i, int ints) {

    InputConnection ic = getCurrentInputConnection();
    playClick(i);
    switch (i)
    {
        case Keyboard.KEYCODE_DELETE:
            ic.deleteSurroundingText(1,0);
        break;
        case Keyboard.KEYCODE_SHIFT:
            isCaps = !isCaps;
            keyboard.setShifted(isCaps);
            kv.invalidateAllKeys();
            break;
        case Keyboard.KEYCODE_DONE:
            ic.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_ENTER));
            break;
            default:
                char code = (char)i;
                if(Character.isLetter(code) && isCaps)
                    code = Character.toUpperCase(code);
                ic.commitText(String.valueOf(code),1);
    }

}

Trong hàm này , chúng ta sẽ xử lý những nút đặc biệt như : Click vào nút DELETE thì xóa ký tự hiện tại , click vào nút SHIFT thì cho phép viết hoa , click vào nút Enter thì xuống dòng , còn lại các nút kia thì in character của nó ra

private void playClick(int i) {
    AudioManager am = (AudioManager)getSystemService(AUDIO_SERVICE);
    switch(i)
    {
        case 32:
            am.playSoundEffect(AudioManager.FX_KEYPRESS_SPACEBAR);
            break;
        case Keyboard.KEYCODE_DONE:
        case 10:
            am.playSoundEffect(AudioManager.FX_KEYPRESS_RETURN);
            break;
        case Keyboard.KEYCODE_DELETE:
            am.playSoundEffect(AudioManager.FX_KEYPRESS_DELETE);
            break;
        default: am.playSoundEffect(AudioManager.FX_KEYPRESS_STANDARD);
    }
}

Hàm này sẽ play âm thanh khi chúng ta nhấn phím

Okay , và đừng quên khai báo Service trong Manifest nhé

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="edmt.dev.androidcustomkeyboard">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <service
            android:name=".EDMTKeyboard"
            android:label="EDMTKeyboard"
           android:permission="android.permission.BIND_INPUT_METHOD"
            >
            <meta-data android:name="android.view.im" android:resource="@xml/method"/>
            <intent-filter>
                <action android:name="android.view.InputMethod"/>
            </intent-filter>

        </service>
    </application>

</manifest>

Đây là file colors.xml của mình , màu đúng y như demo nhé (vì mình set màu bàn phím theo colorPrimary và colorPrimaryDark)

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#3F51B5</color>
    <color name="colorPrimaryDark">#303F9F</color>
    <color name="colorAccent">#FF4081</color>

    <color name="keyboard_background_color">#34495e</color>
    <color name="keyboard_divider">#2c3e50</color>
    <color name="keyboard_pressed">#95a5a6</color>
</resources>

Và hãy thưởng thức nào 😉