系统软键盘">Android在外接物理键盘时,如何强制调用系统软键盘?

第一次写,写的不好请见谅

物理键盘映射过程:

手机/system/usr/keylayout/*.kl :内核将keyCode映射成有含义的字符串
KeycodeLabels.h : framework 将字符串映射成keyEvent的keyCode
frameworks/…/res/values/attrs.xml

主要部分:android.jar

一、问题描述:
当平板连接上蓝牙扫描枪(外接物理键盘)时候,不能弹出软键盘输入,需要打开系统的输入法选择界面关闭硬件物理键盘后才能调用弹出系统软键盘;

理想效果:
在平板连接上蓝牙扫描枪后仍可以调用系统软键盘输入,将系统的物理键盘默认设置为关闭状态,或不需要开启关闭物理键盘,

二、思路

1.首先:你要知道AndroidManifest.xml文件。这里这里有的信息对于理解程序又很大的意义。
2.学会使用grep命令。修改系统的源代码时候这个很重要,
3.当想修改一个程序时,先找到这个程序的位置,大部分只要修改framework 和package 两个文件夹下的内容
4.关键字,例如要修改statuBars。先使用hierarchyviewer查看statuBar属于那个部分。
5.根据图标,使用grep在framework中查找对应的位置。
6.然后就是修改程序了。

三、部分代码

android版本源码

frameworks/base/services/Java/com/android/server/wm/WindowManagerService.java
关键代码:行6618 computeScreenConfigurationLocked()方法中
[java] view plaincopy在CODE上查看代码片派生到我的代码片

boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS;  if (hardKeyboardAvailable != mHardKeyboardAvailable) {  mHardKeyboardAvailable = hardKeyboardAvailable;  mHardKeyboardEnabled = !hardKeyboardAvailable;  mH.removeMessages(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);  mH.sendEmptyMessage(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);  }  if (!mHardKeyboardEnabled) {  config.keyboard = Configuration.KEYBOARD_NOKEYS;  }

将mHardKeyboardEnabled直接改成false
这样改软键盘是能用但是物理键盘是用不了的

最后研究代码frameworks\base\services\core\java\com\android\server\wm\WindowManagerService.java
如果把updateShowImeWithHardKeyboard方法中的showImeWithHardKeyboard变量直接置为true,则可以实现软键盘与物理键盘的同时使用,
但此举修改影响范围很大,不推荐。

public void updateShowImeWithHardKeyboard() { //modified by Janning for enble the HardKeyboard start final boolean showImeWithHardKeyboard = Settings.Secure.getIntForUser( mContext.getContentResolver(), Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0, mCurrentUserId) == 1; //final boolean showImeWithHardKeyboard = true; //modified by Janning for enble the HardKeyboard end synchronized (mWindowMap) { if (mShowImeWithHardKeyboard != showImeWithHardKeyboard) { mShowImeWithHardKeyboard = showImeWithHardKeyboard; mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); } } }

后续继续研究代码发现在WindowManagerService.java的computeScreenConfigurationLocked方法中有通过判断当前物理键盘类型来控制是否同时启用软件盘的处理逻辑:

boolean computeScreenConfigurationLocked(Configuration config) { if (!mDisplayReady) { return false; }  // TODO(multidisplay): For now, apply Configuration to main screen only. final DisplayContent displayContent = getDefaultDisplayContentLocked();  // Use the effective "visual" dimensions based on current rotation final boolean rotated = (mRotation == Surface.ROTATION_90 || mRotation == Surface.ROTATION_270); final int realdw = rotated ? displayContent.mBaseDisplayHeight : displayContent.mBaseDisplayWidth; final int realdh = rotated ? displayContent.mBaseDisplayWidth : displayContent.mBaseDisplayHeight; int dw = realdw; int dh = realdh;  if (mAltOrientation) { if (realdw > realdh) { // Turn landscape into portrait. int maxw = (int)(realdh/1.3f); if (maxw < realdw) { dw = maxw; } } else { // Turn portrait into landscape. int maxh = (int)(realdw/1.3f); if (maxh < realdh) { dh = maxh; } } }  if (config != null) { config.orientation = (dw <= dh) ? Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE; }  // Update application display metrics. final int appWidth = mPolicy.getNonDecorDisplayWidth(dw, dh, mRotation); final int appHeight = mPolicy.getNonDecorDisplayHeight(dw, dh, mRotation); final DisplayInfo displayInfo = displayContent.getDisplayInfo(); synchronized(displayContent.mDisplaySizeLock) { displayInfo.rotation = mRotation; displayInfo.logicalWidth = dw; displayInfo.logicalHeight = dh; displayInfo.logicalDensityDpi = displayContent.mBaseDisplayDensity; displayInfo.appWidth = appWidth; displayInfo.appHeight = appHeight; displayInfo.getLogicalMetrics(mRealDisplayMetrics, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null); displayInfo.getAppMetrics(mDisplayMetrics); mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager( displayContent.getDisplayId(), displayInfo); } if (false) { Slog.i(TAG, "Set app display size: " + appWidth + " x " + appHeight); }  final DisplayMetrics dm = mDisplayMetrics; mCompatibleScreenScale = CompatibilityInfo.computeCompatibleScaling(dm, mCompatDisplayMetrics);  if (config != null) { config.screenWidthDp = (int)(mPolicy.getConfigDisplayWidth(dw, dh, mRotation) / dm.density); config.screenHeightDp = (int)(mPolicy.getConfigDisplayHeight(dw, dh, mRotation) / dm.density); computeSizeRangesAndScreenLayout(displayInfo, rotated, dw, dh, dm.density, config);  config.compatScreenWidthDp = (int)(config.screenWidthDp / mCompatibleScreenScale); config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale); config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, dm, dw, dh); config.densityDpi = displayContent.mBaseDisplayDensity;  // Update the configuration based on available input devices, lid switch, // and platform configuration. config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH; config.keyboard = Configuration.KEYBOARD_NOKEYS; config.navigation = Configuration.NAVIGATION_NONAV;  int keyboardPresence = 0; int navigationPresence = 0; final InputDevice[] devices = mInputManager.getInputDevices(); final int len = devices.length; for (int i = 0; i < len; i++) { InputDevice device = devices[i]; if (!device.isVirtual()) { final int sources = device.getSources(); final int presenceFlag = device.isExternal() ? WindowManagerPolicy.PRESENCE_EXTERNAL : WindowManagerPolicy.PRESENCE_INTERNAL;  if (mIsTouchDevice) { if ((sources & InputDevice.SOURCE_TOUCHSCREEN) == InputDevice.SOURCE_TOUCHSCREEN) { config.touchscreen = Configuration.TOUCHSCREEN_FINGER; } } else { config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH; }  if ((sources & InputDevice.SOURCE_TRACKBALL) == InputDevice.SOURCE_TRACKBALL) { config.navigation = Configuration.NAVIGATION_TRACKBALL; navigationPresence |= presenceFlag; } else if ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD && config.navigation == Configuration.NAVIGATION_NONAV) { config.navigation = Configuration.NAVIGATION_DPAD; navigationPresence |= presenceFlag; } // 判断该物理设备的类型, InputDevice.KEYBOARD_TYPE_ALPHABETIC 是表示物理键盘设备 if (device.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC) { config.keyboard = Configuration.KEYBOARD_QWERTY; keyboardPresence |= presenceFlag; } // 获取物理设备名称,判断是否是指定的名称,如果是则把 config.keyboard // 的属性置为 Configuration.KEYBOARD_NOKEYS ,如此则可以同时兼容软键盘 // 物理键盘与软键盘可以同时启用 // Add by Janning start // for show IME with HardKeyboard if (device.getName().equals("XXX-vinput-keypad")) { Slog.w("SLCODE", "the hard device name is: " + device.getName()); config.keyboard = Configuration.KEYBOARD_NOKEYS; } // Add by Janning end } }  if (config.navigation == Configuration.NAVIGATION_NONAV && mHasPermanentDpad) { config.navigation = Configuration.NAVIGATION_DPAD; navigationPresence |= WindowManagerPolicy.PRESENCE_INTERNAL; }  // Determine whether a hard keyboard is available and enabled. boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS; if (hardKeyboardAvailable != mHardKeyboardAvailable) { mHardKeyboardAvailable = hardKeyboardAvailable; mH.removeMessages(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE); mH.sendEmptyMessage(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE); } if (mShowImeWithHardKeyboard) { config.keyboard = Configuration.KEYBOARD_NOKEYS; }  // Let the policy update hidden states. config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO; config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO; config.navigationHidden = Configuration.NAVIGATIONHIDDEN_NO; mPolicy.adjustConfigurationLw(config, keyboardPresence, navigationPresence); }  return true; }  public boolean isHardKeyboardAvailable() { synchronized (mWindowMap) { return mHardKeyboardAvailable; } }  public void updateShowImeWithHardKeyboard() { // 此处修改也可以实现物理键盘与软键盘的同时启用,即把showImeWithHardKeyboard 直接置为 true, // 但此方法影响太大,不推荐该方案,建议根据设备名称判断 修改config.keyboard 属性值(代码见上文) //changed by Janning start //modified by Janning for enble the HardKeyboard start final boolean showImeWithHardKeyboard = Settings.Secure.getIntForUser( mContext.getContentResolver(), Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0, mCurrentUserId) == 1; //final boolean showImeWithHardKeyboard = true; //modified by Janning for enble the HardKeyboard end //changed by Janning end synchronized (mWindowMap) { if (mShowImeWithHardKeyboard != showImeWithHardKeyboard) { mShowImeWithHardKeyboard = showImeWithHardKeyboard; mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); } } }

当插入物理键盘后通知栏会弹出相应的选择键盘布局通知,对于该通知可以选择隐藏:
根据字符串查找到是在 frameworks\base\services\core\java\com\android\server\input\InputManagerService.java 中调用显示该通知的,
进一步分析代码发现是在 deliverInputDevicesChanged 方法中控制通知的显示。

InputManagerService.java

private void deliverInputDevicesChanged(InputDevice[] oldInputDevices) {  。。。。。。。。。。。。。。。。  if (missingLayoutForExternalKeyboard) { if (missingLayoutForExternalKeyboardAdded) { if (multipleMissingLayoutsForExternalKeyboardsAdded) { // We have more than one keyboard missing a layout, so drop the // user at the generic input methods page so they can pick which // one to set. showMissingKeyboardLayoutNotification(null); } else { // 如果只插入了一个物理键盘则判断该物理键盘的名称是否是指定的,如果是则不让其显示键盘布局的通知 // Modify by Janning begin if (keyboardMissingLayout != null && !keyboardMissingLayout.getName().equals("XXXX-vinput-keypad")) { showMissingKeyboardLayoutNotification(keyboardMissingLayout); } // Modify by Janning end } } } else if (mKeyboardLayoutNotificationShown) { hideMissingKeyboardLayoutNotification(); } } mTempFullKeyboards.clear(); }

注意 注意 注意,重要的说三遍;

加入以上你都修改了,以为这样都OK了,那你就OUT了

时间: 2024-12-26 09:35:09

系统软键盘">Android在外接物理键盘时,如何强制调用系统软键盘?的相关文章

调用系统相册

import android.app.Activity; import android.content.Intent; import android.database.Cursor; import android.graphics.Bitmap; import android.net.Uri; import android.os.Bundle; import android.provider.MediaStore; import android.support.v7.app.AppCompatA

使用downloadmanager调用系统的下载

/** * 文件名 UpdateDownload.java * 包含类名列表 com.issmobile.numlibrary.tool * 版本信息  版本号  * 创建日期 2014年7月14日 * 版权声明  */ package com.issmobile.numlibrary.tool; import com.iss.utils.LogUtil; import android.annotation.SuppressLint;import android.app.DownloadMana

Android 弹出软键盘android:windowSoftInputMode设置总结

当在Android的layout设计里面如果输入框过多,则在输入弹出软键盘的时候,下面的输入框会有一部分被软件盘挡住,从而不能获取焦点输入.或者是有使用framentlayout悬浮在底部的button也会挡住输入框. 一.解决办法 方法一: 在你的activity中的oncreate中setContentView之前写上这个代码getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN); 方法二:

软键盘android:windowSoftInputMode属性详解

android:windowSoftInputModeactivity主窗口与软键盘的交互模式,可以用来避免输入法面板遮挡问题,Android1.5后的一个新特性.这个属性能影响两件事情:[一]当有焦点产生时,软键盘是隐藏还是显示[二]是否减少活动主窗口大小以便腾出空间放软键盘它的设置必须是下面列表中的一个值,或一个”state…”值加一个”adjust…”值的组合.在任一组设置多个值——多个”state…”values,例如&mdash有未定义的结果.各个值之间用|分开.例如: 在这设置的值(

[Phonegap+Sencha Touch] 移动开发24 打包wp8.1的App,运行时输入框聚焦弹出软键盘之后,界面上移而不恢复原位的解决办法

这个现象只出现在phonegap打包sencha touch的wp8.1程序会出现(仅wp8.1,wp8正常),其它js框架我测试了几个(app framework, jquery mobile),好像没有这个问题. 我来描述一下这个现象: 1.运行phonegap打包的wp8程序,打开一个有输入框的界面,如下图: 2.点击输入框,使其弹出软键盘,界面会上移,如下图: 3.点返回键隐藏软键盘(或者点击界面上其它地方隐藏软键盘),此时界面不恢复原位,如下图: 我的一些研究结果: 1.这种现象只出现

【Android】使用Intent调用系统其它程序,使用onKeyDown对音量键的监听,长按事件

Intent在安卓编程中非常常见,在<[Android]多个Activity之间利用bundle传递数值>(点击打开链接)中已经展示了它可以唤醒其它Activity并在Activity之间传递数据.其实Intent的作用远非于此,它还可以调用系统中其它固有程序,比如拨打电话.发送短信等.onKeyDown也是如此,不仅仅可以对设备的菜单键进行监听,这在<[Android]各式各样的弹出框与对菜单键.返回键的监听>(点击打开链接)中已经展示过的,对设备的音量调节键也是可以监听的, 下

android设备外接高拍仪

最近在研究android设备外接摄像头,手边正好有个高拍仪,就顺手试了一下,没想到高拍仪也能成功预览 1.应该并不是所有的android设备都能支持 2.用otg线连接的,没有修改android系统 3.目前只能拍照,不能录像 欢迎来讨论录像问题,我能获取bitmap流,但是无法将这些流保存为视频文件, qq601209821

Android图片系列(1)-------调用系统相册与相机获取图片

Android开发过程中,我们经常需要获取图片,你可以通过获取手机相册的图片,也可以调用相机拍照获取图片.这里主要讲这两个获取图片的方式,并记录其中遇到的小问题. 调用相册获取图片 这个功能非常简单,这里不多说了,这里贴出关键代码 Intent openAlbumIntent = new Intent(Intent.ACTION_GET_CONTENT); openAlbumIntent.setType("image/*"); startActivityForResult(openAl

Android调用系统相机、自定义相机、处理大图片

Android调用系统相机和自定义相机实例 本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显示出来,该例子也会涉及到Android加载大图片时候的处理(避免OOM),还有简要提一下有些人SurfaceView出现黑屏的原因. Android应用拍照的两种方式,下面为两种形式的Demo展示出来的效果.    知识点: 一.调用系统自带的相机应用 二.自定义我们自己的拍照界面 三.关于计算机解析图片原理(如何正确加载图片到Android应用中) 所需