我正在为我的应用程序设计自定义键盘。我有一个 edittext.with 自定义键盘我必须在按 Enter 时执行一些操作(或者说完成按钮)
Enter(Done) 在右下角。
该键盘的布局如下
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
android:horizontalGap="1px"
android:keyHeight="80dp"
android:keyWidth="30%p"
android:verticalGap="1px">
<Row>
<Key
android:codes="49"
android:keyEdgeFlags="left"
android:keyLabel="1"/>
<Key
android:codes="50"
android:keyLabel="2"/>
<Key
android:codes="51"
android:keyLabel="3"/>
<Key
android:codes="-5"
android:isRepeatable="true"
android:keyEdgeFlags="right"
android:keyIcon="@drawable/backspace"
android:keyWidth="30%p"/>
</Row>
<Row>
<Key
android:codes="52"
android:keyEdgeFlags="left"
android:keyLabel="4"/>
<Key
android:codes="53"
android:keyLabel="5"/>
<Key
android:codes="54"
android:keyLabel="6"/>
<Key
android:codes="46"
android:keyLabel="."
android:keyWidth="30%p"/>
</Row>
<Row>
<Key
android:codes="55"
android:keyEdgeFlags="left"
android:keyLabel="7"/>
<Key
android:codes="56"
android:keyLabel="8"/>
<Key
android:codes="57"
android:keyLabel="9"/>
<Key
android:codes="47"
android:keyEdgeFlags="right"
android:keyLabel="/"
android:keyWidth="30%p"/>
</Row>
<Row android:rowEdgeFlags="bottom">
<Key
android:codes="1100"
android:isRepeatable="true"
android:keyEdgeFlags="left"
android:keyLabel="ABC"
/>
<Key
android:codes="48"
android:keyLabel="0"/>
<Key
android:codes="55007"
android:isRepeatable="true"
android:keyIcon="@drawable/hide_key"
android:keyWidth="30%p"/>
<Key
android:codes="-4"
android:isRepeatable="true"
android:keyEdgeFlags="right"
android:imeOptions="actionDone"
android:keyIcon="@drawable/sym_keyboard_done"
/>
</Row>
</Keyboard>
我正在处理输入按钮按下如下
if (primaryCode == Keyboard.KEYCODE_DONE) {
Log.d("Gajanand", "onKey:connection " + connection);
// connection.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER));
final int options = getCurrentInputEditorInfo().imeOptions;
final int actionId = options & EditorInfo.IME_MASK_ACTION;
switch (actionId) {
case EditorInfo.IME_ACTION_SEARCH:
sendDefaultEditorAction(true);
break;
case EditorInfo.IME_ACTION_GO:
sendDefaultEditorAction(true);
break;
case EditorInfo.IME_ACTION_SEND:
sendDefaultEditorAction(true);
break;
default:
connection.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER));
}
}
我的自定义键盘类
/**
* Copyright 2013 Maarten Pennings
* <p/>
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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.
* <p/>
* If you use this software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
*/
package com.example.manvish.customkeybrd;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.inputmethodservice.InputMethodService;
import android.inputmethodservice.Keyboard;
import android.inputmethodservice.KeyboardView;
import android.os.Build;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.AppCompatEditText;
import android.text.Editable;
import android.text.InputType;
import android.text.TextWatcher;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import android.widget.AutoCompleteTextView;
/**
* When an activity hosts a keyboardView, this class allows several EditText's
* to register for it.
*
* @author Maarten Pennings
* @date 2012 December 23
*/
public class CustomKeyboard extends InputMethodService {
//constant for defining the time duration between the click that can be considered as double-tap
static final int MAX_DURATION = 100;
int touchPosition;
int id;
Boolean longpressded = false;
int clickCount = 0;
//variable for storing the time of first click
long startTime;
//variable for calculating the total time
long duration;
boolean pressed = false;
/**
* A link to the KeyboardView that is used to render this CustomKeyboard.
*/
private KeyboardView mKeyboardView;
/**
* A link to the activity that hosts the {@link #mKeyboardView}.
*/
private AppCompatActivity mHostActivity;
private Keyboard mKeyBoard;
private View mInflater;
private long mLastClickTime = 0;
private KeyboardView.OnKeyboardActionListener mOnKeyboardActionListener = new KeyboardView.OnKeyboardActionListener() {
public final static int CodeDelete = -5; // Keyboard.KEYCODE_DELETE
public final static int CodeCancel = -3; // Keyboard.KEYCODE_CANCEL
public final static int CodePrev = 55000;
public final static int CodeAllLeft = 55001;
public final static int CodeLeft = 55002;
public final static int CodeRight = 55003;
public final static int CodeAllRight = 55004;
public final static int CodeNext = 55005;
public final static int CodeClear = 55006;
public final static int CodeDone = 55007;
public final static int CodeCaps = -1;
public final static int QwertNumberKeypad = 1100;
public final static int QwertNumericKeypad = 1101;
// public final static int CodeBackSpace = -4;
private boolean caps = false;
@SuppressLint("ClickableViewAccessibility")
@Override
public void onKey(final int primaryCode, int[] keyCodes) {
Log.d("Gajanand", "onKey: " + primaryCode);
InputConnection connection = getCurrentInputConnection();
View focusCurrent = mHostActivity.getWindow().getCurrentFocus();
if (focusCurrent == null
|| focusCurrent.getClass() != AppCompatEditText.class)
return;
final AppCompatEditText edittext = (AppCompatEditText) focusCurrent;
edittext.addTextChangedListener(new TextWatcher() {
public void onTextChanged(CharSequence s, int start, int before, int count) {
String searchString = s.toString();
int textLength = searchString.length();
// edittext.setSelection(textLength);
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public void afterTextChanged(Editable s) {
}
});
Editable editables = edittext.getText();
int start = edittext.getSelectionStart();
int end = edittext.getSelectionEnd();
// Apply the key to the edittext
if (primaryCode == CodeCancel) {
hideCustomKeyboard();
} else if (primaryCode == CodeDelete) {
if (editables != null && start > 0) {
editables.delete(start - 1, start);
edittext.setSelection(start - 1);
}
} else if (primaryCode == CodeClear) {
if (editables != null)
editables.clear();
} else if (primaryCode == CodeLeft) {
if (start > 0)
edittext.setSelection(start - 1);
} else if (primaryCode == CodeRight) {
if (start < edittext.length())
edittext.setSelection(start + 1);
} else if (primaryCode == CodeAllLeft) {
edittext.setSelection(0);
} else if (primaryCode == CodeAllRight) {
edittext.setSelection(edittext.length());
} else if (primaryCode == CodePrev) {
View focusNew = edittext.focusSearch(View.FOCUS_BACKWARD);
if (focusNew != null)
focusNew.requestFocus();
} else if (primaryCode == CodeNext) {
View focusNew = edittext.focusSearch(View.FOCUS_FORWARD);
if (focusNew != null)
focusNew.requestFocus();
} else if (primaryCode == CodeDone) {
hideCustomKeyboard();
}
// for capslock
else if (primaryCode == CodeCaps) {
caps = !caps;
mKeyBoard.setShifted(caps);
mKeyboardView.invalidateAllKeys();
// edittext.setInputType(InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS);
//
// edittext.setFilters(new InputFilter[]{new
// InputFilter.AllCaps()});
} else { // insert character
if (primaryCode != QwertNumericKeypad && primaryCode != QwertNumberKeypad) {
char code = (char) primaryCode;
if (Character.isLetter(code) && caps) {
code = Character.toUpperCase(code);
}
editables.insert(start, Character.toString((char) code));
}
}
if (primaryCode == QwertNumberKeypad) {
mKeyboardView.invalidateAllKeys();
mKeyboardView.setKeyboard(new Keyboard(mHostActivity,
R.xml.qwerty));
Log.d("Gajanand", "onKey:in number keypad " + caps);
}
if (primaryCode == QwertNumericKeypad) {
mKeyboardView.invalidateAllKeys();
mKeyboardView.setKeyboard(new Keyboard(mHostActivity,
R.xml.qwerty_numbers));
Log.d("Gajanand", "onKey:in numeric keypad " + caps);
}
if (primaryCode == Keyboard.KEYCODE_DONE) {
Log.d("Gajanand", "onKey:connection " + connection);
// connection.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER));
final int options = getCurrentInputEditorInfo().imeOptions;
final int actionId = options & EditorInfo.IME_MASK_ACTION;
switch (actionId) {
case EditorInfo.IME_ACTION_SEARCH:
sendDefaultEditorAction(true);
break;
case EditorInfo.IME_ACTION_GO:
sendDefaultEditorAction(true);
break;
case EditorInfo.IME_ACTION_SEND:
sendDefaultEditorAction(true);
break;
default:
connection.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER));
}
}
}
@Override
public void onPress(int arg0) {
// Log.d("Gajanand", "onPress:GK ");
// mLastClickTime = SystemClock.elapsedRealtime();
pressed = true;
Log.d("Gajanand", "onPress: " + longpressded);
}
@Override
public void onRelease(int primaryCode) {
// Log.d("Gajanand", "onRelease: GK");
// mLastClickTime=0;
pressed = false;
Log.d("Gajanand", "onRelease: " + longpressded);
}
@Override
public void onText(CharSequence text) {
}
@Override
public void swipeDown() {
}
@Override
public void swipeLeft() {
}
@Override
public void swipeRight() {
}
@Override
public void swipeUp() {
}
};
// public CustomKeyboard(Context context, AttributeSet attrs) {
// super(context, attrs);
// }
/**
* The key (code) handler.
*/
// @Override
// protected boolean onLongPress(Keyboard.Key popupKey) {
//
// pressed = true;
// longpressded = true;
// Log.d("Gajanand", "onLongPress: " + longpressded);
// mKeyboardView.setEnabled(false);
//
// return false;
// }
// @Override
// protected void onSelectionChanged(int selStart, int selEnd) {
// super.onSelectionChanged(selStart, selEnd);
//
// Log.d("Gajanand", "onSelectionChanged: yes changed");
// }
/**
* Create a custom keyboard, that uses the KeyboardView (with resource id
* <var>viewid</var>) of the <var>host</var> activity, and load the keyboard
* layout from xml file <var>layoutid</var> (see {@link Keyboard} for
* description). Note that the <var>host</var> activity must have a
* <var>KeyboardView</var> in its layout (typically aligned with the bottom
* of the activity). Note that the keyboard layout xml file may include key
* codes for navigation; see the constants in this class for their values.
* Note that to enable EditText's to use this custom keyboard, call the
* {@link #registerEditText(int)}.
*
* @param host The hosting activity.
* @param viewid The id of the KeyboardView.
* @param layoutid The id of the xml file containing the keyboard layout.
*/
public CustomKeyboard(AppCompatActivity host, int viewid, int layoutid) {
mHostActivity = host;
mKeyboardView = (KeyboardView) mHostActivity.findViewById(viewid);
mKeyBoard = new Keyboard(mHostActivity, layoutid);
mKeyboardView.setKeyboard(mKeyBoard);
mKeyboardView.setPreviewEnabled(false); // NOTE Do not show the preview
// balloons
mKeyboardView.setOnKeyboardActionListener(mOnKeyboardActionListener);
// Hide the standard keyboard initially
mHostActivity.getWindow().setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
}
public CustomKeyboard() {
}
public CustomKeyboard(AppCompatActivity host, View inflater, int viewid, int layoutid) {
mHostActivity = host;
mInflater = inflater;
mKeyboardView = (KeyboardView) mInflater.findViewById(viewid);
mKeyBoard = new Keyboard(mHostActivity, layoutid);
mKeyboardView.setKeyboard(mKeyBoard);
mKeyboardView.setPreviewEnabled(false); // NOTE Do not show the preview
// balloons
mKeyboardView.setOnKeyboardActionListener(mOnKeyboardActionListener);
// Hide the standard keyboard initially
mHostActivity.getWindow().setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
}
/**
* Returns whether the CustomKeyboard is visible.
*/
public boolean isCustomKeyboardVisible() {
return mKeyboardView.getVisibility() == View.VISIBLE;
}
// @Override
// public boolean onTouchEvent(MotionEvent me) {
// return super.onTouchEvent(me);
// }
/**
* Make the CustomKeyboard visible, and hide the system keyboard for view v.
*/
public void showCustomKeyboard(View v) {
mKeyboardView.setVisibility(View.VISIBLE);
mKeyboardView.setEnabled(true);
if (v != null)
((InputMethodManager) mHostActivity
.getSystemService(AppCompatActivity.INPUT_METHOD_SERVICE))
.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
/**
* Make the CustomKeyboard invisible.
*/
public void hideCustomKeyboard() {
mKeyboardView.setVisibility(View.GONE);
mKeyboardView.setEnabled(false);
sendStatusToActivity("hide");
}
private void sendStatusToActivity(String msg) {
Intent intent = new Intent("KEYPAD");
intent.putExtra("Status", msg);
LocalBroadcastManager.getInstance(mHostActivity).sendBroadcast(intent);
// stopservice();
}
/**
* Register <var>EditText<var> with resource id <var>resid</var> (on the
* hosting activity) for using this custom keyboard.
*
* @param resid The resource id of the EditText that registers to the custom
* keyboard.
*/
@SuppressLint("ClickableViewAccessibility")
public void registerEditText(int resid) {
// Find the EditText 'resid'
AppCompatEditText edittext;
/*View focusCurrent = mHostActivity.getWindow().getCurrentFocus();
if (focusCurrent == null
|| focusCurrent.getClass() != AppCompatEditText.class)
return;
final AppCompatEditText edittext = (AppCompatEditText) focusCurrent;*/
edittext = (AppCompatEditText) mHostActivity.findViewById(resid);
if (edittext == null) {
edittext = (AppCompatEditText) mInflater.findViewById(resid);
}
// Make the custom keyboard appear
edittext.setOnFocusChangeListener(new View.OnFocusChangeListener() {
// NOTE By setting the on focus listener, we can show the custom
// keyboard when the edit box gets focus, but also hide it when the
// edit box loses focus
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus)
showCustomKeyboard(v);
else
hideCustomKeyboard();
}
});
edittext.setOnClickListener(new View.OnClickListener() {
// NOTE By setting the on click listener, we can show the custom
// keyboard again, by tapping on an edit box that already had focus
// (but that had the keyboard hidden).
@Override
public void onClick(View v) {
Log.d("kishan", "onClick: keypad");
showCustomKeyboard(v);
}
});
// Disable standard keyboard hard way
// NOTE There is also an easy way:
// 'edittext.setInputType(InputType.TYPE_NULL)' (but you will not have a
// cursor, and no 'edittext.setCursorVisible(true)' doesn't work )
edittext.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.d("kishan", "onTouch: keypad");
showCustomKeyboard(v);
AppCompatEditText edittext = (AppCompatEditText) v;
float x = event.getX();
float y = event.getY();
touchPosition = edittext.getOffsetForPosition(x, y);
if (touchPosition > 0) {
edittext.setSelection(touchPosition);
}
int inType = edittext.getInputType(); // Backup the input type
edittext.setInputType(InputType.TYPE_NULL); // Disable standard
// keyboard
edittext.onTouchEvent(event); // Call native handler
edittext.setInputType(inType); // Restore input type
return true; // Consume touch event
}
});
// Disable spell check (hex strings look like words to Android)
edittext.setInputType(edittext.getInputType()
| InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
}
public void registerAutoCompleteEditText(int resid) {
// Find the EditText 'resid'
System.out.println("hello ");
AutoCompleteTextView autoCompleteTextView;
autoCompleteTextView = (AutoCompleteTextView) mHostActivity.findViewById(resid);
if (autoCompleteTextView == null) {
autoCompleteTextView = (AutoCompleteTextView) mInflater.findViewById(resid);
}
System.out.println("hello 1");
// Make the custom keyboard appear
autoCompleteTextView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
// NOTE By setting the on focus listener, we can show the custom
// keyboard when the edit box gets focus, but also hide it when the
// edit box loses focus
@Override
public void onFocusChange(View v, boolean hasFocus) {
System.out.println("hello 2");
if (hasFocus)
showCustomKeyboard(v);
else
hideCustomKeyboard();
}
});
autoCompleteTextView.setOnClickListener(new View.OnClickListener() {
// NOTE By setting the on click listener, we can show the custom
// keyboard again, by tapping on an edit box that already had focus
// (but that had the keyboard hidden).
@Override
public void onClick(View v) {
showCustomKeyboard(v);
}
});
// Disable standard keyboard hard way
// NOTE There is also an easy way:
// 'edittext.setInputType(InputType.TYPE_NULL)' (but you will not have a
// cursor, and no 'edittext.setCursorVisible(true)' doesn't work )
autoCompleteTextView.setOnTouchListener(new View.OnTouchListener() {
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
@Override
public boolean onTouch(View v, MotionEvent event) {
AutoCompleteTextView edittext = (AutoCompleteTextView) v;
float x = event.getX();
float y = event.getY();
touchPosition = edittext.getOffsetForPosition(x, y);
if (touchPosition > 0) {
edittext.setSelection(touchPosition);
}
int inType = edittext.getInputType(); // Backup the input type
edittext.setInputType(InputType.TYPE_NULL); // Disable standard
// keyboard
edittext.onTouchEvent(event); // Call native handler
edittext.setInputType(inType); // Restore input type
return true; // Consume touch event
}
});
// Disable spell check (hex strings look like words to Android)
System.out.println("hello 5");
autoCompleteTextView.setInputType(autoCompleteTextView.getInputType()
| InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
}
}
// NOTE How can we change the background color of some keys (like the
// shift/ctrl/alt)?
// NOTE What does android:keyEdgeFlags do/mean
但 getCurrentInputEditorInfo() 抛出空值?如何处理这个?或者它是错误的方式来实现我必须做的任何事情。