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

可以加群:466059178,可以共同讨论,大神指导

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

参考:
http://blog.csdn.net/DrakeBlue/article/details/39049495
http://blog.csdn.NET/hclydao/article/details/44240799
http://blog.csdn.Net/jdsjlzx/article/details/39495319

物理键盘映射过程:

手机/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了

看看下面的你或许根本不知道,慢慢研究吧!骚年

四、以下操作全在ubuntu系统下完成

可以参考:http://blog.csdn.net/y150481863/article/details/8023422
操作步骤(不具体说明):
1.下载好ubuntu系统之后。
2.在找到sdk位置(就是你的SDK 找到你用的那个系统,在到ubuntu修改)。
………………………..(做起来不是这么简单)
3.再用ub系统上生成.jar,再放在SDK里面

你的打赏是我最大的幸运:

有问题:
欢迎加群:

466059178

,欢迎投稿!

更多相关文章

  1. Android(安卓)build.prop修改详细说明
  2. Android软键盘监听KeyboardWatcher
  3. Windows下修改android 模拟机 hosts文件
  4. PopupWindow软键盘弹出遮挡输入框
  5. Android(安卓)修改Camera拍照的默认保存路径
  6. Android系统移植与调试之------->如何修改Android设备的默认休眠
  7. Android(安卓)如何修改自动同步数据的默认开关 M
  8. android 源码编译导入library project
  9. Android(安卓)监听软键盘状态的实例详解

随机推荐

  1. 【iOS-cocos2d-X 游戏开发之三】Mac下配
  2. Android异步加载全解析之开篇瞎扯淡
  3. Android换行符变成方框的解决方法
  4. Android(安卓)实用工具Hierarchy Viewer
  5. Android(安卓)JNI作用及其详解
  6. Android中实现全屏、无标题栏的两种办法(
  7. Android官方入门文档
  8. Android相机开发那些坑
  9. Android(安卓)stuido常用快捷方式整理
  10. Android深入浅出之Audio第三部分Audio Po