拼音输入法(MPinyinIME)

来源:互联网 发布:大数据 应用 编辑:程序博客网 时间:2024/05/09 20:17
目录结构
jni/ - Java Native Interface, 用C/C++实现拼音输入法的功能,供上层Java代码调用的底层代码。
lib/ - 用AIDL文件给上层JAVA应用定义了jni可用的接口集IPinyinDecoderService。AIDL请参考
res/ - Android项目的资源目录(系统静态字典数据文件dict_pinyin.dat也放在这个目录下的raw子目录里)

broadcast delayed

输入法编译选项: 
framework里面也有个这种配置    不过device下面的又设置了一次,把framework的覆盖了




PinyinEMI.java 输入法服务.

http://blog.csdn.net/jianguo_liao19840726/article/details/25370407
http://blog.csdn.net/pi9nc/article/details/9196779
http://blog.csdn.net/z_guijin/article/details/6728197 输入法 DEBUG调式.

第一步,需要理解输入法的XML原理,改界面布局需要改这里.

还需要调用语言什么的?
===================================================

PinyinIME.java 

=== 输入法主界面 public View onCreateInputView() { 

R.layout.skb_container -> 

类似,只是processkey用true作为第二个参数。  Processkey调用commitResultText/sendKeyChar等输入法框架函数把键码送到输入处理。PinyinIME里commitResultText对全键盘和九宫格的处理也不一样,一个是通过SkbContainer处理,一个是直接调用各输入法的commitResultText实现。 

com.android.inputmethod.pinyin.SkbContainer

com.android.inputmethod.pinyin.SoftKeyboardView

=== 候选区界面 public View onCreateCandidatesView() {

R.layout.floating_container -> com.android.inputmethod.pinyin.ComposingView

=== 输入法配置界面 SettingsActivity.java  settings.xml

=== public boolean onKeyDown(int keyCode, KeyEvent event) {


-----------------------------------

skb_phone.xml 
数字键盘有BUG ,需要改写,添加移动方框.

XmlKeyboardLoader.java 
    public SoftKeyboard loadKeyboard(int resourceId, int skbWidth, int skbHeight) { 调用 
SoftKeyboard.java  键值的处理. (添加 beginNewRow, addSoftKey)

 private List<KeyRow> mKeyRows;

public class SoftKey { 一个键值的属性.

----------------------------
如何判断是数字键盘,还是字符键盘的.
在 InputModeSwitcher.java 中的 getSkblayout 函数.

requestInputWithHkb



现在的问题是 当用户选择按键后,代码中是如何显示出去的???
 public void responseSoftKeyEvent(SoftKey sKey) {

==================================
===================================
ondraw(... ...{
 RectF outerRect = new RectF(left, top, right, bottom);  
             Paint paint = new Paint();
             paint.setColor(Color.WHITE);
             paint.setAntiAlias(true);
             paint.setStyle(Paint.Style.STROKE);//设置空心  
             canvas.drawRoundRect(outerRect, 5, 5, paint);
==================================

==================================
XML 键盘布局分析
==================================

【如何创建一个 键盘 布局】

需要添加土耳其或者其它国际化的版本的.
第一个必须是 <keyboard
 
 # 一行的键值. 比如 1, 2, 3, -
 <row>
  <key # 如果是普通的键值 可以考虑 keys
   <toggle_state # 如果需要添加按键 效果.
   ... ...
  ... ...
 </row>
 #
结尾  </keyboard>
keyboard 的属性值说明:
 
 # 数字
 balloon="false" : 是否显示提示框.
    height="25%p"
    key_type="0"
    repeat="false"
    skb_template="@xml/skb_template1"
    width="25%p"
   
 # 字母
 balloon="true"
    height="25%p"
    key_type="0"
    qwerty="true"
    qwerty_uppercase="true"
    repeat="false"
    skb_cache_flag="true"
    skb_template="@xml/skb_template1"
    width="10%p"
 
 # 符号
 balloon="true"
    height="25%p"
    key_type="0"
    repeat="false"
    skb_cache_flag="true"
    skb_template="@xml/skb_template1"
    width="10%p"


==================================
各个过程分析记录
==================================

当鼠标点击 软键盘 输出字符到编辑框的过程

SKbContainer.java

鼠标点击软键盘的过程.
public boolean onTouchEvent(MotionEvent event) {

// 绘制了按下的颜色.
case MotionEvent.ACTION_DOWN:  // 按下的时候

 mSoftKeyDown = mSkv.onKeyPress(x - mSkvPosInContainer[0], y
                        - mSkvPosInContainer[1], mLongPressTimer, false);

  case MotionEvent.ACTION_UP:  // 起来的时候
   // 去掉按下的颜色
   // 字符提示窗口
   // 输入字符到编辑框
      if (null != mSkv) {
                mSkv.onKeyRelease(x - mSkvPosInContainer[0], y
                        - mSkvPosInContainer[1]);
            }

SoftKeryboardView.java

public SoftKey onKeyRelease(int x, int y) {     // 去掉按下的颜色 字符提示窗口

responseKeyEvent(mSoftKeyDown); // 输入字符到编辑框
     ((PinyinIME) mService).responseSoftKeyEvent(sKey); // 发送按键字符.

============================================
============================================

遥控器移动点击OK输出字符到编辑框的过程: (痛鼠标按下的过程差不过的)

realAction  : 用于判断为 按下(false) 和松开(true)!!!

SdbContainer.java
   
按键按下的时候:

     @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {  // PinYinIME.java

       private boolean processKey(KeyEvent event, boolean realAction) {  // PinYinIME.java
     private boolean processFunctionKeys(int keyCode, boolean realAction) {  // PinYinIME.java

   private boolean processEnterKeys(int keyCode, boolean isAccfter) { // PinYinIME.java
   
    public void actionForEnterDown() {
            mSkv.onKeyPress(mSoftKeyDown.mLeft - mSkvPosInContainer[0], mSoftKeyDown.mTop
                                 - mSkvPosInContainer[1], mLongPressTimer, false); //  SoftKeryboardView.java
按键起来的时候:
   @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) { // PinyinIME.java
   private boolean processKey(KeyEvent event, boolean realAction) {
    private boolean processFunctionKeys(int keyCode, boolean realAction) {
    private boolean processEnterKeys(int keyCode, boolean isAccfter) { // PinyinIME.java

  public void actionForEnterUp() { // SkbContainer.java
       mSkv.onKeyRelease(mSoftKeyDown.mLeft - mSkvPosInContainer[0], mSoftKeyDown.mTop
                              - mSkvPosInContainer[1]); // 恢复按下的键
      responseKeyEvent(mSoftKeyDown); // 发送字符 SoftKeryboardView.java


=============================================
输入法布局XML界面的解析过程分析 
=============================================
skbCoreWidth:1280/skbCoreHeight:280  这里主要根据 width="10%p"  ,然后换算出来的按键宽度.

XmlKeyboardLoader.java
    
 @Override
    public void onStartInputView(EditorInfo editorInfo, boolean restarting) { // PinyinIME.java

public void updateInputMode() {   // SkbContainer.java

 private void updateSkbLayout() {  // SkbContainer.java
           switch (mSkbLayout) {
        case R.xml.skb_qwerty:
            majorSkb = skbPool.getSoftKeyboard(R.xml.skb_qwerty,
                    R.xml.skb_qwerty, screenWidth, skbHeight, mContext); // 解析XML布局.

getSoftKeyboard  --- SkbPool.java

public SoftKeyboard loadKeyboard(int resourceId, int skbWidth, int skbHeight) {
          while (mXmlEventType != XmlResourceParser.END_DOCUMENT) {
                      if (XMLTAG_KEYBOARD.compareTo(attr) == 0) {

---- 当软键盘又点击切换的时候,  
public void responseSoftKeyEvent(SoftKey sKey) {  // PinyinIME.java
         if (sKey.isUserDefKey()) {
            updateIcon(mInputModeSwitcher.switchModeForUserKey(keyCode));
            resetToIdleState(false);
            mSkbContainer.updateInputMode(); // 更新输入模式.
            if (mDecInfo.isCandidatesListEmpty()) {
                dismissCandidateWindow();
            }
           // ... ...

public void responseSoftKeyEvent(SoftKey sKey) {
  if (!mSkbContainer.isCurrentSkbSticky()) {
                updateIcon(mInputModeSwitcher.requestBackToPreviousSkb());
                resetToIdleState(false);
                mSkbContainer.updateInputMode();
            }


// 中英文切换
 <key  start_pos_x="0%p" start_pos_y="75%p"
      width="20%p" height="25%p" code="-2" label="中/英文" key_type="1"
      repeat="true">
      <toggle_state state_id="@string/toggle_en_lower" label="英/中文" code="-2"/>
      <toggle_state state_id="@string/toggle_en_upper" label="英/中文" code="-2"/>
  </key>

// ?12
 <key  code="-3"  key_type="2" label="\?12"/>


// 删除
 <key  code="67" key_type="1" 
      repeat="true"/>

// 空格
<key key_type="5" code="62" icon="@drawable/space_icon"
    icon_popup="@drawable/space_popup_icon" width="30.608%p"  />

// 句号
<key id="7" start_pos_x="65.304%p" start_pos_y="75%p"
      width="14.696%p" height="25%p" label="." key_type="0"
      icon="@drawable/period_icon" icon_popup="@drawable/period_popup_icon"/>

// 获取字体颜色 
 mNormalKeyTextSize = env.getKeyTextSize(false);
        mFunctionKeyTextSize = env.getKeyTextSize(true);


// 初始化按键
  public boolean setSoftKeyboard(SoftKeyboard softSkb) {
        if (null == softSkb) {
            return false;
        }
        mSoftKeyboard = softSkb;
        Drawable bg = softSkb.getSkbBackground();

        //mSoftKeyboard.getKeyRowForDisplay(0).mSoftKeys.get(0).setKeySelected(true);
//        mSoftKeyboard.setOneKeySelected(3,4);
        mSoftKeyboard.setOneKeySelected(0,0); // 第0个焦点.


=============================
输入法候选框过程分析
=============================

setCandidatesViewShown(true);  是否显示候选框.

public View onCreateCandidatesView() {  // pinyinIME.java
         mCandidatesContainer = (CandidatesContainer) inflater.inflate(
    R.layout.candidates_container, null); // 候选区


 public void showCandidates(PinyinIME.DecodingInfo decInfo,  // CandidatesContainer.java
         for (int i = 0; i < mFlipper.getChildCount(); i++) {
            CandidateView cv = (CandidateView) mFlipper.getChildAt(i);
            cv.setDecodingInfo(mDecInfo); // 显示传入的拼音字符.
        }


==================================
中/英 文切换过程.
==================================
// SkbContainer.java
private void responseKeyEvent(SoftKey sKey) {
        ((PinyinIME) mService).responseSoftKeyEvent(sKey);

// PinyinIME.java
 public void responseSoftKeyEvent(SoftKey sKey) {
         if (sKey.isUserDefKey()) {
        //                                     updateIcon(mInputModeSwitcher.switchModeForUserKey(keyCode)); // 中/英 切换.
            resetToIdleState(false);
            mSkbContainer.updateInputMode();
            if (mDecInfo.isCandidatesListEmpty()) {
                dismissCandidateWindow();  // 候选框窗口.
            }

========================================
中文处理过程
========================================
// PinyinIME.java
 private boolean processKey(KeyEvent event, boolean realAction) {
 else if (mInputModeSwitcher.isChineseText()) { // 中文
            if (mImeState == ImeState.STATE_IDLE ||
                    mImeState == ImeState.STATE_APP_COMPLETION) {
                mImeState = ImeState.STATE_IDLE;
                return processStateIdle(keyChar, keyCode, event, realAction);
            } else if (mImeState == ImeState.STATE_INPUT) {
                return processStateInput(keyChar, keyCode, event, realAction);
            } else if (mImeState == ImeState.STATE_PREDICT) { /* 中文 */
                return processStatePredict(keyChar, keyCode, event, realAction);
            } else if (mImeState == ImeState.STATE_COMPOSING) {
                return processStateEditComposing(keyChar, keyCode, event,
                        realAction);
            }


     private void updateDecInfoForSearch(int totalChoicesNum) {


 private void chooseAndUpdate(int candId) {
                   if (ImeState.STATE_PREDICT != mImeState) {
            // Get result candidate list, if choice_id < 0, do a new decoding.
            // If choice_id >=0, select the candidate, and get the new candidate
            // list.
            mDecInfo.chooseDecodingCandidate(candId); // 搜索中文词组.

  private void chooseDecodingCandidate(int candId) {
                   if (mPosDelSpl < 0) {
                                totalChoicesNum = mIPinyinDecoderService
                                        .imSearch(mPyBuf, length()); // 搜索中文词组.

private void updateDecInfoForSearch(int totalChoicesNum) {

--------------------------------------------------------

public boolean preparePage(int pageNo) {

 private void getCandiagtesForCache() {

mTotalChoicesNum =4
preparePage
mDecInfo.mPageStart

点击中文输出.. ...到编辑框. PinyinIME.java
public void onClickChoice(int choiceId) {

  private void onChoiceTouched(int activeCandNo) {

########################
private boolean processStateInput(int keyChar, int keyCode, KeyEvent event,
   boolean realAction) {

        if (skbFocusEnable) // 防止执行下面的操作.
    return true;

   if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
    mCandidatesContainer.activeCurseBackward();
   } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
    mCandidatesContainer.activeCurseForward();
 
# 也许需要改这里.
 private boolean processDirectionKeys(int keyCode) {

    只有中文才可以上移动去上面,需要改.


########################
不隐藏输入法,遥控器遥控上,编辑框可以去移动光标.

http://www.iteedu.com/handset/android/androidcnapi5/51.php

加入方向上移动,编辑框可以移动光标,而不用退出输入法界面. (研究)
ic.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));
  ic.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, keyCode));
可以参考这个!!
 if (SIMULATE_KEY_DELETE) { // 模拟,点击软键盘上删除.
     Log.d(TAG, "bbbbbbbb:" + keyCode);
     simulateKeyEventDownUp(keyCode);

修改,给编辑框发送移动.
 ic.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_LEFT));
  ic.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_LEFT));

 /**
         * 在这里加入当打字的时候,没有了,显示出快捷方式出来.
         */
        if (mDecInfo != null && mDecInfo.isCandidatesListEmpty()) {
         mCandidatesContainer.setInputMethodCandState(CandidateView.INPUT_METHOD_FASTER_STATE); // 设置快捷方式.
        }




<LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_marginTop="100dp"
                    android:orientation="vertical" >

                    <LinearLayout
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_margin="10dp"
                        android:orientation="horizontal" >

                        <!-- 头像 -->

                        <com.open.srx.widgets.CircleImageView
                            android:id="@+id/active_iv"
                            android:layout_width="80dp"
                            android:layout_height="80dp"
                            android:layout_marginRight="10dp"
                            android:src="@drawable/radio_kafeiguan_bg" />
                        <!-- 名字 -->

                        <LinearLayout
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:orientation="vertical" >

                            <TextView
                                android:id="@+id/textView1"
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:text="冰雪情缘" />

                            <TextView
                                android:id="@+id/textView11"
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:text="学霸" />
                        </LinearLayout>
                    </LinearLayout>

                    <EditText
                        android:id="@+id/editText1"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:ems="10" >

                        <requestFocus />
                    </EditText>

                    <EditText
                        android:id="@+id/editText2"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:ems="10" />

                    <Button
                        android:id="@+id/button1"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="Button" />

                    <Button
                        android:id="@+id/button2"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="发布课程" />

                    <Button
                        android:id="@+id/button3"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="查询课程" />
                </LinearLayout>


http://www.360doc.com/content/12/1024/08/1538436_243412962.shtml 语言模型在搜狗输入法中的使用.

http://www.oschina.net/p/libpinyin 开源拼音词库

输入法中文词库分析:

com.android.inputmethod.pinyin/
PinyinDecoderService.java

jni/android/
com_android_inputmethod_pinyin_pinyine_PinyinDe...cpp

-------------------------

/**
     * Connection used for binding to the Pinyin decoding service.
     * 拼音词库服务的aidl服务连接.
     */
    public class PinyinDecoderServiceConnection implements ServiceConnection {
        public void onServiceConnected(ComponentName name, IBinder service) {
            mDecInfo.mIPinyinDecoderService = IPinyinDecoderService.Stub
                    .asInterface(service);
        }

        public void onServiceDisconnected(ComponentName name) {
        }
    }

----------------------------------

0 0
原创粉丝点击