天天看點

Android輸入法擴充之外接鍵盤中文輸入Android沒法通過外接鍵盤中文輸入原因問題的解決完美解決方式附錄

        大家想不想要這樣一台Android  Surface平闆,看着就過瘾吧。

Android輸入法擴充之外接鍵盤中文輸入Android沒法通過外接鍵盤中文輸入原因問題的解決完美解決方式附錄

         我們知道,android眼下的輸入都是通過軟鍵盤實作的,用外接鍵盤的少。這個在手機上是能夠了解的。當手機接上外接鍵盤後。總體會顯得頭重腳輕。而且用鍵盤輸入時。人離手機的距離就遠了,自然不太适合看清手機上的内容。那在平闆上呢?假設平闆僅僅是平時用來浏覽看視訊,不進行大量輸入。自然也用不上外接鍵盤。

那到底什麼時候須要用到外接鍵盤呢?本人認為首先要滿足例如以下兩個條件。

1)   平闆和外接鍵盤完美融合,組合後非常像筆記本使用模式。類似上面Android Surface的機器,平闆和鍵盤通過磁性自己主動粘合,變身筆記本模式 2)    Android用在類辦公等須要高速輸入場景,比方寫文章。長時間聊qq等。事實上linux一直以來沒法進入桌面系統的關鍵原因是window在這方面太優秀,它壟斷了使用者的辦公習慣,即用Microsoft office系列軟體辦公。可是如今類linux。尤其Android在這邊已經有了非常大進步,一方面,ubuntu幫組linux積累了一部分使用者。比方libre office體驗好多了。同一時候據說微軟正在為Android開發Microsoft office的響應産品,這個是利好消息。

     從上面看來。事實上市面上已經有滿足上面兩個條件的機器了。比方聯想的A10        

Android輸入法擴充之外接鍵盤中文輸入Android沒法通過外接鍵盤中文輸入原因問題的解決完美解決方式附錄

      它是一台超級本, 但它支援翻轉,當翻轉過來就是平闆。

      那為啥這樣的Android超極本就不夠火呢?當然有非常多原因啊,比方平闆本身需求量小,Android本身就不适合辦公。當然肯定也有另外一個小原因。它這個實體鍵盤居然不能中文輸入。

是以,Android平闆要進入辦公領域并流行,須要實作類似PC端中文輸入的體驗。

     本文說到的外接鍵盤中文輸入,重在中文兩字。其實,Android本身是支援外接鍵盤的。可是僅僅可以實作英文輸入。其實。我們在前幾篇文章已經說到了輸入法,也已經分析到,Android要想輸入中文,必須通過輸入法。

那為啥Android的中文輸入法不能像PC那樣直接通過外接鍵盤輸入呢?以下一一分析。

        Android系統裡,當有外接鍵盤時。輸入法就會消失。這樣自然沒法通過輸入法輸入中文。

這個是由Configuration的keyboard配置項決定的。正常情況下。Configuration的keyboard值是nokeys,而當系統檢測到外接鍵盤(藍牙鍵盤等等)插入時,就會更新系統的Configuration,并将當中的keyboard置為非nokeys(比方Configuration.KEYBOARD_QWERTY),然後系統會将新的Configuration通知給全部程式,包含輸入法。

當輸入法程式檢測到新的Configuration時,它會運作更新操作,然後發現已經有外接裝置就會隐藏自己。這樣輸入法就不見了。

詳細邏輯例如以下:

         我們知道,假設要想輸入法通過外接鍵盤輸出中文,它肯定須要從外接鍵盤讀取到英文輸入。而在Android系統中,按鍵等key事件僅僅發送給焦點程式,可是輸入法本身沒法獲得焦點,是以它自然就沒法讀取到外接鍵盤的輸入。

         從上面的分析可知。輸入法和外接鍵盤沒法共存的根本原因是,輸入法會讀取configuration裡的鍵盤屬性值。

解決問題有兩個方法:

1)  改動用到Configuration的相關函數,比方onEvaluateInputViewShown ,onShowInputRequested函數的實作 這種方法看起來可行,可是不行。由于非常多地方可能用到了這個Configuration,改動量比較大,且非常多函數并不是protected或者public,子類是沒法直接改動的。 2)  改動輸入法的Configuration的值 這種方法可行。從源頭上攻克了這個問題,這樣InputMethodService覺得系統沒有外接鍵盤。自然就不會隐藏輸入法了。

  方法2詳細實作例如以下:

         在輸入法初始化和更新Configuration的點主動改動輸入法的Configuration。

        輸入法實作輸入有兩部分。一是擷取按鍵事件。二是擷取輸入目标

       上面已經提到過。輸入法window是沒法擷取外接鍵盤事件的。怎麼辦?非常好辦,讓輸入法service建立另外一個普通的window(本文稱作bridge window),并将這個window标示為可接受key事件的window,當它是最top的可接受key事件的window時, 它就能夠獲得焦點并獲得外接鍵盤的輸入。

這樣,它作為中間橋梁就能将外接鍵盤事件傳給輸入法 (同一程式裡,非常好做的)。輸入法然後進行翻譯,比方拼音轉為中文。

        輸入法的輸入目标是textView的通信接口InputConnection。它是在程式獲得焦點時候或焦點程式中的焦點view發生變化的時候。焦點程式傳遞給輸入法的。

        是以,問題來了?一旦上面的bridge window獲得焦點後,輸入法的輸入目标就跟着更新了,變成了bridge window的view的InputConnection。這樣即使輸入法完畢了英文到中文的轉換,最後也僅僅能将中文發送給bridge window,并不能發送給使用者想輸入的程式。怎麼解?還好Android系統有一個特殊window flag-----WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,當一個window設定了這個flag, 它成為焦點時。輸入法并不會将輸入目标切換為目前焦點window的InputConnection,而是仍舊保持原來的InputConnection。這為我們帶來了希望,也就是說,我們僅僅需将我們的bridge window加入這個flag就可以,其實确實如此。

        可是還存在一個問題。我們知道InputConnection是相應textView的一個通信接口,當使用者改變輸入view時,輸入法中的InputConnection是須要改動的,可是如今因為目标程式已經不是焦點程式了,當使用者觸摸目标程式其它textView導緻輸入view改變時,系統并不會通知輸入法去更新InputConnection,這樣一來,輸入法的中文始終僅僅能傳遞給一個textView了。

又怎麼解呢?靈光一動,繼續解。當使用者觸摸時。我們能夠讓bridge window臨時失去焦點,這樣目标程式就又一次擷取了焦點,然後輸入view切換時,輸入法就能得到通知,也就是能又一次擷取到新的textView的InputConnection。然後。bridge window又一次擷取焦點,也就是非常短時間後它繼續能夠接受外接鍵盤的輸入了。

     這個方法的重點在bridge window的實作:實作的重點有兩個:

1)     加入WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM flag 2)  監聽OUT_SIDE事件,這樣,當使用者單擊目标程式。切換焦點view時,bridge window可以提前獲知,然後釋放焦點,    讓目标程式成為焦點,然後完畢焦點view的切換,進而完畢輸入法中的輸入目标InputConnection的更新。

        上面的解決方式是直接在輸入法程式内部改動達到實作外接鍵盤輸入中文。屬于應用程範疇。可是仍有一些問題,而這些問題在程式端是沒法解決的。

那該怎麼完美解決呢。Andorid後來的版本号已經攻克了這個。是怎樣解決的?

即全部的按鍵事件先發送給程式。然後程式端的代碼會先将key發送給輸入法,即讓輸入法有一個翻譯轉換過程的機會,然後輸入法再将轉化過的key或者字元發送回程式,也就是說key事件繞了一圈。最後再讓程式端處理。

        近期工作比較忙。代碼還沒有整理好,等整理好後,我會将源代碼發出來。大家能夠一起學習。

/********************************

* 本文來自部落格  “愛踢門”

******************************************/

本文轉自mfrbuaa部落格園部落格,原文連結:http://www.cnblogs.com/mfrbuaa/p/5114169.html,如需轉載請自行聯系原作者

繼續閱讀