Android Open Source - BlueCtrl Keyboard Input View






From Project

Back to project page BlueCtrl.

License

The source code is released under:

GNU General Public License

If you think the Android project BlueCtrl listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * Copyright (C) 2012/*from w  w w .j a  v  a2s. co  m*/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.ronsdev.bluectrl.widget;

import org.ronsdev.bluectrl.HidKeyboard;
import org.ronsdev.bluectrl.KeyEventFuture;

import android.content.Context;
import android.os.Bundle;
import android.os.Parcelable;
import android.os.ResultReceiver;
import android.os.SystemClock;
import android.text.Editable;
import android.text.InputType;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.View;
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;

/**
 * View that handles key events and redirects them to a HID Keyboard.
 */
public class KeyboardInputView extends View {

    private static final String TAG = "KeyboardInputView";
    private static final boolean V = false;


    private static final String SAVED_STATE_INSTANCE = "InstanceState";
    private static final String SAVED_STATE_SHOULD_SHOW_KEYBOARD = "ShouldShowKeyboard";
    private static final String SAVED_STATE_WAS_KEYBOARD_TOGGLED = "WasKeyboardToggled";


    private HidKeyboard mHidKeyboard = null;

    private boolean mShouldShowKeyboard = false;
    private boolean mWasKeyboardToggled = false;


    private OnKeyboardComposingTextListener mOnKeyboardComposingTextListener;


    /**
     * A custom InputConnection that immediately redirects text input as key events.
     */
    private final class KeyboardInputConnection extends BaseInputConnection {

        public KeyboardInputConnection(View targetView) {
            super(targetView, true);
        }

        @Override
        public Editable getEditable() {
            return null;
        }

        @Override
        public boolean setComposingText(CharSequence text, int newCursorPosition) {
            OnKeyboardComposingText(text);
            return true;
        }

        @Override
        public boolean commitText(CharSequence text, int newCursorPosition) {
            sendKeyEvent(new KeyEvent(SystemClock.uptimeMillis(),
                    text.toString(), KeyCharacterMap.BUILT_IN_KEYBOARD, 0));
            return true;
        }
    }


    public KeyboardInputView(Context context) {
        super(context);

        initView();
    }

    public KeyboardInputView(Context context, AttributeSet attrs) {
        super(context, attrs);

        initView();
    }

    public KeyboardInputView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        initView();
    }


    private final void initView() {
        setFocusable(true);
        setFocusableInTouchMode(true);
    }

    public boolean isActive() {
        return ((mHidKeyboard != null) && mHidKeyboard.isConnected());
    }

    public HidKeyboard getHidKeyboard() {
        return mHidKeyboard;
    }
    public void setHidKeyboard(HidKeyboard hidKeyboard) {
        mHidKeyboard = hidKeyboard;
    }

    private void OnKeyboardComposingText(CharSequence composingText) {
        if (mOnKeyboardComposingTextListener != null) {
            mOnKeyboardComposingTextListener.OnKeyboardComposingText(composingText);
        }
    }

    public void setOnKeyboardComposingTextListener(OnKeyboardComposingTextListener listener) {
        mOnKeyboardComposingTextListener = listener;
    }

    private InputMethodManager getInputManager() {
        return (InputMethodManager)getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
    }

    public void showKeyboard() {
        boolean success = false;
        if (isShown()) {
            requestFocus();
            success = getInputManager().showSoftInput(this,
                    InputMethodManager.SHOW_FORCED,
                    new ResultReceiver(null) {
                        @Override
                        protected void onReceiveResult(int resultCode, Bundle resultData) {
                            if (resultCode == InputMethodManager.RESULT_SHOWN) {
                                mWasKeyboardToggled = true;
                            }
                        }
                    });
        }
        mShouldShowKeyboard = !success;
    }

    public void hideToggledKeyboard() {
        mShouldShowKeyboard = false;
        if (mWasKeyboardToggled) {
            mWasKeyboardToggled = false;
            getInputManager().hideSoftInputFromWindow(getWindowToken(), 0);
        }
    }

    public void toggleKeyboard() {
        mWasKeyboardToggled = true;
        requestFocus();

        /*
         * We use the SHOW_FORCED flag instead of the preferred SHOW_IMPLICIT flag because the
         * latter didn't work in the landscape mode.
         */
        getInputManager().toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
    }

    @Override
    protected Parcelable onSaveInstanceState() {
        Bundle outState = new Bundle();

        outState.putParcelable(SAVED_STATE_INSTANCE, super.onSaveInstanceState());
        outState.putBoolean(SAVED_STATE_SHOULD_SHOW_KEYBOARD, mShouldShowKeyboard);
        outState.putBoolean(SAVED_STATE_WAS_KEYBOARD_TOGGLED, mWasKeyboardToggled);

        return outState;
    }

    @Override
    protected void onRestoreInstanceState(Parcelable state) {
        if (state instanceof Bundle) {
            Bundle savedInstanceState = (Bundle)state;

            mShouldShowKeyboard = savedInstanceState.getBoolean(SAVED_STATE_SHOULD_SHOW_KEYBOARD);
            mWasKeyboardToggled = savedInstanceState.getBoolean(SAVED_STATE_WAS_KEYBOARD_TOGGLED);
            super.onRestoreInstanceState(savedInstanceState.getParcelable(SAVED_STATE_INSTANCE));
        } else {
            super.onRestoreInstanceState(state);
        }
    }

    @Override
    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
        outAttrs.inputType = InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS &
                InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE;
        outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI;

        return new KeyboardInputConnection(this);
    }

    @Override
    public void onWindowFocusChanged(boolean hasWindowFocus) {
        super.onWindowFocusChanged(hasWindowFocus);

        if (hasWindowFocus) {
            onKeyboardActiveStateChanged(true);
        }
    }

    @Override
    public void onVisibilityChanged(View changedView, int visibility) {
        super.onVisibilityChanged(changedView, visibility);

        onKeyboardActiveStateChanged(isShown());
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (isActive()) {
            return onSingleKeyEvent(keyCode, event);
        } else {
            return super.onKeyDown(keyCode, event);
        }
    }

    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        if (isActive()) {
            return onSingleKeyEvent(keyCode, event);
        } else {
            return super.onKeyUp(keyCode, event);
        }
    }

    @Override
    public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
        if (isActive()) {
            return onMultipleKeyEvents(event);
        } else {
            return super.onKeyMultiple(keyCode, repeatCount, event);
        }
    }

    public void onActivityPause() {
        onKeyboardActiveStateChanged(false);
    }

    private void onKeyboardActiveStateChanged(boolean isActive) {
        if (isActive) {
            if (mShouldShowKeyboard) {
                showKeyboard();
            }
        } else {
            if (mWasKeyboardToggled) {
                mWasKeyboardToggled = false;
                getInputManager().hideSoftInputFromWindow(getWindowToken(),
                        0,
                        new ResultReceiver(null) {
                            @Override
                            protected void onReceiveResult(int resultCode, Bundle resultData) {
                                if (resultCode == InputMethodManager.RESULT_HIDDEN) {
                                    mShouldShowKeyboard = true;
                                }
                            }
                        });
            }
        }
    }

    private boolean onSingleKeyEvent(int keyCode, KeyEvent event) {
        final int character = event.getUnicodeChar(0);

        if (V) {
            if (event.getAction() == KeyEvent.ACTION_DOWN) {
                Log.v(TAG, String.format("Key Down (Key=%d   Char=%c)", keyCode, character));
            } else if (event.getAction() == KeyEvent.ACTION_UP) {
                Log.v(TAG, String.format("Key Up (Key=%d   Char=%c)", keyCode, character));
            }
        }

        if (handleHardwareKey(keyCode, event) ||
                handleMediaKey(keyCode, event) ||
                handleNonCharKey(keyCode, event) ||
                handleCharKey(character, event)) {
            return true;
        }

        return false;
    }

    private boolean handleHardwareKey(int keyCode, KeyEvent event) {
        final int hardwareKey = convertToHidHardwareKey(keyCode);

        if (hardwareKey != 0) {
            switch (event.getAction()) {
            case KeyEvent.ACTION_DOWN:
                mHidKeyboard.pressHardwareKey(hardwareKey);
                return true;
            case KeyEvent.ACTION_UP:
                mHidKeyboard.releaseHardwareKey(hardwareKey);
                return true;
            }
        }

        return false;
    }

    private boolean handleMediaKey(int keyCode, KeyEvent event) {
        final int mediaKey = convertToHidMediaKey(keyCode);

        if (mediaKey != 0) {
            switch (event.getAction()) {
            case KeyEvent.ACTION_DOWN:
                mHidKeyboard.pressMediaKey(mediaKey);
                return true;
            case KeyEvent.ACTION_UP:
                mHidKeyboard.releaseMediaKey(mediaKey);
                return true;
            }
        }

        return false;
    }

    private boolean handleNonCharKey(int keyCode, KeyEvent event) {
        final int hidModifier = convertToHidModifier(keyCode);
        final int hidKeyCode = convertToHidKeyCode(keyCode);

        if ((hidModifier != 0) || (hidKeyCode != 0)) {
            switch (event.getAction()) {
            case KeyEvent.ACTION_DOWN:
                if (hidModifier != 0) {
                    mHidKeyboard.pressModifierKey(hidModifier);
                }

                if (hidKeyCode != 0) {
                    mHidKeyboard.pressKey(hidKeyCode);
                }

                return true;
            case KeyEvent.ACTION_UP:
                if (hidKeyCode != 0) {
                    mHidKeyboard.releaseKey(hidKeyCode);
                }

                if (hidModifier != 0) {
                    mHidKeyboard.releaseModifierKey(hidModifier);
                }

                return true;
            }
        }

        return false;
    }

    private boolean handleCharKey(int character, KeyEvent event) {
        if (character != 0) {
            switch (event.getAction()) {
            case KeyEvent.ACTION_DOWN:
                return mHidKeyboard.pressCharKey((char)character);
            case KeyEvent.ACTION_UP:
                return mHidKeyboard.releaseCharKey((char)character);
            }
        }

        return false;
    }

    private boolean onMultipleKeyEvents(KeyEvent event) {
        if (event.getKeyCode() == KeyEvent.KEYCODE_UNKNOWN) {
            if (V) Log.v(TAG, String.format("multiple key events (Text='%s')", event.getCharacters()));

            mHidKeyboard.typeText(event.getCharacters());
            return true;
        } else {
            if (V) Log.v(TAG, String.format("multiple key events (Repeat='%d')", event.getRepeatCount()));

            // Repeated keys are ignored because only key changes have to be reported
            return true;
        }
    }

    /**
     * Converts a Android key code to a HID Keyboard code.
     * Only language independent keys that doesn't create characters are handled.
     */
    private static int convertToHidKeyCode(int keyCode) {
        switch (keyCode) {
        case KeyEventFuture.KEYCODE_BREAK:
            return HidKeyboard.KEYCODE_PAUSE;
        case KeyEventFuture.KEYCODE_CAPS_LOCK:
            return HidKeyboard.KEYCODE_CAPS_LOCK;
        case KeyEvent.KEYCODE_CLEAR:
            return HidKeyboard.KEYCODE_CLEAR;
        case KeyEvent.KEYCODE_DEL:
            return HidKeyboard.KEYCODE_DEL;
        case KeyEvent.KEYCODE_DPAD_CENTER:
            return HidKeyboard.KEYCODE_ENTER;
        case KeyEvent.KEYCODE_DPAD_DOWN:
            return HidKeyboard.KEYCODE_DOWN_ARROW;
        case KeyEvent.KEYCODE_DPAD_LEFT:
            return HidKeyboard.KEYCODE_LEFT_ARROW;
        case KeyEvent.KEYCODE_DPAD_RIGHT:
            return HidKeyboard.KEYCODE_RIGHT_ARROW;
        case KeyEvent.KEYCODE_DPAD_UP:
            return HidKeyboard.KEYCODE_UP_ARROW;
        case KeyEvent.KEYCODE_ENTER:
            return HidKeyboard.KEYCODE_ENTER;
        case KeyEventFuture.KEYCODE_ESCAPE:
            return HidKeyboard.KEYCODE_ESCAPE;
        case KeyEventFuture.KEYCODE_F1:
            return HidKeyboard.KEYCODE_F1;
        case KeyEventFuture.KEYCODE_F10:
            return HidKeyboard.KEYCODE_F10;
        case KeyEventFuture.KEYCODE_F11:
            return HidKeyboard.KEYCODE_F11;
        case KeyEventFuture.KEYCODE_F12:
            return HidKeyboard.KEYCODE_F12;
        case KeyEventFuture.KEYCODE_F2:
            return HidKeyboard.KEYCODE_F2;
        case KeyEventFuture.KEYCODE_F3:
            return HidKeyboard.KEYCODE_F3;
        case KeyEventFuture.KEYCODE_F4:
            return HidKeyboard.KEYCODE_F4;
        case KeyEventFuture.KEYCODE_F5:
            return HidKeyboard.KEYCODE_F5;
        case KeyEventFuture.KEYCODE_F6:
            return HidKeyboard.KEYCODE_F6;
        case KeyEventFuture.KEYCODE_F7:
            return HidKeyboard.KEYCODE_F7;
        case KeyEventFuture.KEYCODE_F8:
            return HidKeyboard.KEYCODE_F8;
        case KeyEventFuture.KEYCODE_F9:
            return HidKeyboard.KEYCODE_F9;
        case KeyEventFuture.KEYCODE_FORWARD_DEL:
            return HidKeyboard.KEYCODE_FORWARD_DEL;
        case KeyEventFuture.KEYCODE_INSERT:
            return HidKeyboard.KEYCODE_INSERT;
        case KeyEventFuture.KEYCODE_MOVE_END:
            return HidKeyboard.KEYCODE_END;
        case KeyEventFuture.KEYCODE_MOVE_HOME:
            return HidKeyboard.KEYCODE_HOME;
        case KeyEventFuture.KEYCODE_NUMPAD_0:
            return HidKeyboard.KEYCODE_NUMPAD_0;
        case KeyEventFuture.KEYCODE_NUMPAD_1:
            return HidKeyboard.KEYCODE_NUMPAD_1;
        case KeyEventFuture.KEYCODE_NUMPAD_2:
            return HidKeyboard.KEYCODE_NUMPAD_2;
        case KeyEventFuture.KEYCODE_NUMPAD_3:
            return HidKeyboard.KEYCODE_NUMPAD_3;
        case KeyEventFuture.KEYCODE_NUMPAD_4:
            return HidKeyboard.KEYCODE_NUMPAD_4;
        case KeyEventFuture.KEYCODE_NUMPAD_5:
            return HidKeyboard.KEYCODE_NUMPAD_5;
        case KeyEventFuture.KEYCODE_NUMPAD_6:
            return HidKeyboard.KEYCODE_NUMPAD_6;
        case KeyEventFuture.KEYCODE_NUMPAD_7:
            return HidKeyboard.KEYCODE_NUMPAD_7;
        case KeyEventFuture.KEYCODE_NUMPAD_8:
            return HidKeyboard.KEYCODE_NUMPAD_8;
        case KeyEventFuture.KEYCODE_NUMPAD_9:
            return HidKeyboard.KEYCODE_NUMPAD_9;
        case KeyEventFuture.KEYCODE_NUMPAD_ADD:
            return HidKeyboard.KEYCODE_NUMPAD_ADD;
        case KeyEventFuture.KEYCODE_NUMPAD_COMMA:
            return HidKeyboard.KEYCODE_NUMPAD_COMMA;
        case KeyEventFuture.KEYCODE_NUMPAD_DIVIDE:
            return HidKeyboard.KEYCODE_NUMPAD_DIVIDE;
        case KeyEventFuture.KEYCODE_NUMPAD_DOT:
            return HidKeyboard.KEYCODE_NUMPAD_DOT;
        case KeyEventFuture.KEYCODE_NUMPAD_ENTER:
            return HidKeyboard.KEYCODE_NUMPAD_ENTER;
        case KeyEventFuture.KEYCODE_NUMPAD_EQUALS:
            return HidKeyboard.KEYCODE_NUMPAD_EQUALS;
        case KeyEventFuture.KEYCODE_NUMPAD_LEFT_PAREN:
            return HidKeyboard.KEYCODE_NUMPAD_LEFT_PAREN;
        case KeyEventFuture.KEYCODE_NUMPAD_MULTIPLY:
            return HidKeyboard.KEYCODE_NUMPAD_MULTIPLY;
        case KeyEventFuture.KEYCODE_NUMPAD_RIGHT_PAREN:
            return HidKeyboard.KEYCODE_NUMPAD_RIGHT_PAREN;
        case KeyEventFuture.KEYCODE_NUMPAD_SUBTRACT:
            return HidKeyboard.KEYCODE_NUMPAD_SUBTRACT;
        case KeyEventFuture.KEYCODE_NUM_LOCK:
            return HidKeyboard.KEYCODE_NUM_LOCK;
        case KeyEvent.KEYCODE_PAGE_DOWN:
            return HidKeyboard.KEYCODE_PAGE_DOWN;
        case KeyEvent.KEYCODE_PAGE_UP:
            return HidKeyboard.KEYCODE_PAGE_UP;
        case KeyEventFuture.KEYCODE_SCROLL_LOCK:
            return HidKeyboard.KEYCODE_SCROLL_LOCK;
        case KeyEvent.KEYCODE_SPACE:
            return HidKeyboard.KEYCODE_SPACE;
        case KeyEventFuture.KEYCODE_SYSRQ:
            return HidKeyboard.KEYCODE_SYSRQ;
        case KeyEvent.KEYCODE_TAB:
            return HidKeyboard.KEYCODE_TAB;
        default:
            return 0;
        }
    }

    /** Converts a Android key code to a HID Keyboard modifier. */
    private static int convertToHidModifier(int keyCode) {
        switch (keyCode) {
        case KeyEventFuture.KEYCODE_CTRL_LEFT:
            return HidKeyboard.MODIFIER_LEFT_CTRL;
        case KeyEventFuture.KEYCODE_CTRL_RIGHT:
            return HidKeyboard.MODIFIER_RIGHT_CTRL;
        case KeyEvent.KEYCODE_SHIFT_LEFT:
            return HidKeyboard.MODIFIER_LEFT_SHIFT;
        case KeyEvent.KEYCODE_SHIFT_RIGHT:
            return HidKeyboard.MODIFIER_RIGHT_SHIFT;
        case KeyEvent.KEYCODE_ALT_LEFT:
            return HidKeyboard.MODIFIER_LEFT_ALT;
        case KeyEvent.KEYCODE_ALT_RIGHT:
            return HidKeyboard.MODIFIER_RIGHT_ALT;
        case KeyEventFuture.KEYCODE_META_LEFT:
            return HidKeyboard.MODIFIER_LEFT_GUI;
        case KeyEventFuture.KEYCODE_META_RIGHT:
            return HidKeyboard.MODIFIER_RIGHT_GUI;
        default:
            return 0;
        }
    }

    /** Converts a Android key code to a HID Hardware key code. */
    private static int convertToHidHardwareKey(int keyCode) {
        switch (keyCode) {
        case KeyEventFuture.KEYCODE_MEDIA_EJECT:
            return HidKeyboard.HARDWARE_KEY_EJECT;
        default:
            return 0;
        }
    }

    /** Converts a Android key code to a HID Media key code. */
    private static int convertToHidMediaKey(int keyCode) {
        switch (keyCode) {
        case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
            return HidKeyboard.MEDIA_KEY_PLAY_PAUSE;
        case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
            return HidKeyboard.MEDIA_KEY_FORWARD;
        case KeyEvent.KEYCODE_MEDIA_REWIND:
            return HidKeyboard.MEDIA_KEY_REWIND;
        case KeyEvent.KEYCODE_MEDIA_NEXT:
            return HidKeyboard.MEDIA_KEY_SCAN_NEXT_TRACK;
        case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
            return HidKeyboard.MEDIA_KEY_SCAN_PREV_TRACK;
        case KeyEvent.KEYCODE_MUTE:
            return HidKeyboard.MEDIA_KEY_MUTE;
        case KeyEvent.KEYCODE_VOLUME_UP:
            return HidKeyboard.MEDIA_KEY_VOLUME_INC;
        case KeyEvent.KEYCODE_VOLUME_DOWN:
            return HidKeyboard.MEDIA_KEY_VOLUME_DEC;
        default:
            return 0;
        }
    }
}




Java Source Code List

org.ronsdev.bluectrl.ChangelogDialog.java
org.ronsdev.bluectrl.CharKeyReportMap.java
org.ronsdev.bluectrl.DeviceManager.java
org.ronsdev.bluectrl.DevicePreferenceActivity.java
org.ronsdev.bluectrl.DeviceSettings.java
org.ronsdev.bluectrl.HidKeyboard.java
org.ronsdev.bluectrl.HidMouse.java
org.ronsdev.bluectrl.IntArrayList.java
org.ronsdev.bluectrl.KeyEventFuture.java
org.ronsdev.bluectrl.MainActivity.java
org.ronsdev.bluectrl.OnMouseButtonClickListener.java
org.ronsdev.bluectrl.PairedDevice.java
org.ronsdev.bluectrl.PairingActivity.java
org.ronsdev.bluectrl.TouchpadActivity.java
org.ronsdev.bluectrl.TouchpadTutorialActivity.java
org.ronsdev.bluectrl.daemon.DaemonActivity.java
org.ronsdev.bluectrl.daemon.DaemonCallbackReceiver.java
org.ronsdev.bluectrl.daemon.DaemonListActivity.java
org.ronsdev.bluectrl.daemon.DaemonService.java
org.ronsdev.bluectrl.widget.ComposeTextLayout.java
org.ronsdev.bluectrl.widget.FloatSliderPreference.java
org.ronsdev.bluectrl.widget.KeyboardInputView.java
org.ronsdev.bluectrl.widget.MouseTouchListener.java
org.ronsdev.bluectrl.widget.OnKeyboardComposingTextListener.java
org.ronsdev.bluectrl.widget.OnScrollModeChangedListener.java
org.ronsdev.bluectrl.widget.OnSendComposeTextListener.java
org.ronsdev.bluectrl.widget.OnTouchpadGestureListener.java
org.ronsdev.bluectrl.widget.SummaryListPreference.java
org.ronsdev.bluectrl.widget.TouchpadViewGestureListener.java
org.ronsdev.bluectrl.widget.TouchpadView.java