键盘那些事儿

原文链接:https://juejin.im/post/5bee64f3e51d4543a64350f9

首先界面如下所示

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context="com.example.guoyan1.keyboarddemo.MainActivity">
    <EditText
        android:id="@+id/top_edit"
        android:text="点击展示键盘"
        android:layout_width="match_parent"
        android:layout_height="100dp"/>
    <EditText
        android:layout_alignParentBottom="true"
        android:id="@+id/keyboard_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!" />
</RelativeLayout>复制代码

第一种情况:

清单文件如下所示

<activity
    android:name=".MainActivity"
    >
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>

        <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>
</activity>复制代码


当我们点击顶部的输入框的时候键盘弹出情况如下:


这个时候界面没有被顶上去,只是键盘盖在了界面上,接着我们继续点击底部的输入框界面显示如下:


整个界面被顶上去了,而且底部的输入框紧贴着键盘显示。

解决办法:

如果我们取消第二个输入框的焦点呢,手动去调用该view的点击事件,在点击的时候添加如下事件

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mTopEdit = (EditText) findViewById(R.id.top_edit);
    mKeyboard = (EditText) findViewById(R.id.keyboard_tv);
    mKeyboard.clearFocus();
    mKeyboard.setFocusable(false);
    mKeyboard.setFocusableInTouchMode(false);
    mKeyboard.setOnClickListener(this);
}

@Override
public void onClick(View v) {
    if (v.hasFocus()){
        Toast.makeText(getApplicationContext(),"hasFocus",0).show();
    }
    show(v);
}

public static void show(View view) {
    if (null != view) {
        InputMethodManager imm = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.toggleSoftInput(InputMethodManager.RESULT_UNCHANGED_SHOWN, InputMethodManager.RESULT_UNCHANGED_HIDDEN);
    }
}复制代码

此时我们发现点击顶部的输入框和底部的输入框点击之后的界面的显示效果是一致的都如下图所示:键盘盖在了界面上


也就是说如果在界面的底部有输入框并且该输入框的的view有焦点的话,当点击该view键盘弹出的时候,输入框会随着键盘的弹出被顶起来进而整个界面上移,所以不让其顶起的办法就是底部的输入框去除焦点手动添加点击事件,但是去除某一个view的焦点又有一个坑,那就是

mKeyboard.clearFocus();复制代码

这句代码并没有起作用,要想真正的去除某一个view的焦点需要添加如下代码:

mKeyboard.clearFocus();
mKeyboard.setFocusable(false);
mKeyboard.setFocusableInTouchMode(false);复制代码

第二种情况:

但是如你的清单文件如下所示:

<activity
    android:name=".MainActivity"
    android:configChanges="orientation|screenSize|keyboardHidden"
    android:windowSoftInputMode="stateAlwaysHidden|adjustResize"
    >
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>

        <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>
</activity>复制代码

adjustResize意思是当键盘弹出的时候整个界面会被重新绘制(拙见),一般情况下无论是点击底部的Editext还是点击顶部的EditText的时候界面都不会被顶上去,但是底部的EditText会随着会随着键盘的出现而上移,如下图所示:


但是如果你设置了全屏模式

getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
        WindowManager.LayoutParams.FLAG_FULLSCREEN);复制代码

以上代码又把结果拉回了第一种情况点击顶部的EditText的时候键盘弹起盖在整个页面上,点击底部的EditText的时候整个页面被弹起了(还是焦点的问题)如果去底部EditText的焦点并手动添加点击事件呼起键盘的时候结果又同第一中情况的解决办法,键盘改在了界面上底部的EditText被盖住了,但是产品的需求是底部的输入框要紧贴着键盘被顶起来但是整个见面不能动。(未完待续)



展开阅读全文

USB键盘背后的那些事儿 --- Legacy USB

05-01

最近晚上闲来无事,决定写几篇技术文章和大家共享一下。关于议题,我想了很久,觉得还是重点写些大家平时接触不到,或者说不容易在其他地方见到的一些概念吧。这样可以一方面开拓大家的知识面,另一方面我也想打破目前BIOS技术过于封闭的局面。现在的BIOS业界的确是过于封闭了,有句话说的不错:在我们这个行业,就那么几个人,大家在不同的公司跳来跳去……原因就在这个行业技术上过于封闭。不是BIOS从业的工程师,很难自学BIOS编程的。rnrn于是呼,我第一篇就选择了谈谈Legacy USB。rnrn1. Legacy USB是什么?rnrnUSB0设备我们每天都在用,那么什么又是Leacgy USB呢?随便Google一下,网上什么说法都有,但是很少有说对的。大多数朋友都知道这是一个主板BIOS上的选项,并且几乎都设置成了Enable,但是在问及这个东东到底是干什么的时候,就基本上没人知道了。很多朋友误认为这是USB 1.1支持选项。这是完全错误的,任何一项技术都应该默认做到backward rncompatibility(向后兼容),如果USB因为升级到2.0就不再支持大量的1.1设备,那么我想估计就没人用USB了。rnrn所以Legacy USB不是USB 1.1支持选项!那么它到底是干什么用的呢?我们不妨来做个实验,现在就重启你的电脑,进入BIOS,将这一项设置成Disable,然后进DOS,接着试试你的USB键盘,看看现在还能不能用呢?或者不进DOS,我们对WinXP来一次非正常关机,然后重启,OS应该会出现一个菜单,接着读秒,提示非正常关机,按任意键继续这样的话,这个时候按下你的USB键盘,看看这个任意键能否被OS识别呢?答案势必是不行。不过在读秒完成后,进入OS,我们的USB键盘又活了。呵呵rnrn所谓的Legacy USB是在传统的环境下,对USB设置(主要是USB键盘,鼠标)提供支持的选项。所谓的传统的环境,是指DOS,或者那些直接去访问8042兼容键盘控制器的程序,或者那些使用BIOS调用INT 9H来取键盘响应的程序。这样的程序一般都比较老,但是在某些场合他们仍然在起作用,况且在OS起来之前,几乎100%都是Legacy USB的应用场合。rnrn那么为什么会有这个问题呢?说起来就远了,大家只要大致明白就可。之前在USB设备出来之前,尤其是USB键盘出来之前,人们并没有想象到未来的某一天还会有个USB键盘这个东西,那个时候我们的PC比较老实,键盘的工业标准是8042,同时访问8042的编程标准则是两个I/O端口,60H和64H。rnrn文不想变成又一篇描述如何控制8042的启蒙文章,大家只要知道,过去我们一直是通过访问上述两个端口来给8042发一些指令,如读键盘缓冲区,打开/关闭键盘上的LED灯,来进行等等这样的类似的操作。而8042也可以被配置成轮询或者中断模式,在中断模式下,如果键盘缓冲区里有足够多的键,那么8042产生一个中断,接着一个键盘驱动就会取走这些键,然后处理。rnrn一切都那么完美?不是吗?很不幸,当我们的USB键盘出现后,这一切都不是那么完美了。USB键盘并不归8042管辖,当然也不可能使用60/64来通信。这可把那些过去直接使用60/64的程序幽了一默。这些直接访问8042的程序无法对USB键盘的按键做出任何响应。更重要的是,DOS也这么干。一般来说,当你新安装一个设备,如果不能使用,你会想到:啊,那我安装它的驱动啊!的确是这样,但是对于键盘这样一个设备来说,很难想象如果它不能使用还能否安装驱动(也许用户根本无法操作计算机)。换言之,用户希望对自己原来的程序不加修改,就能直接使用USB键盘。rnrn为了保护用户投资,我们必须找到一个方法,使得那些老的系统,老的程序能够能够在不认识USB键盘的条件下,仍然能够使用USB键盘/鼠标。是的,也许方法你已经想到了,那就是:rnrnLEGACY USBrnrn2. Legacy USB:实现rnrn我仍然记得,在我刚刚入行的时候,我的老板对我说道:你知道吗?在PC里,什么设备最难编程?是小小的USB键盘!我当时十分不解,一个小小的键盘怎么会最难呢?后来我惊讶的发现,Legacy USB竟然是各家BIOS Vendor竞争的一个焦点所在。谁能提供这个支持,谁就能在竞争占据有利地位。那都是因为这个技术实在是太难了。rnrn从一个OS下的程序员的角度,他可能永远都不明白为什么这个问题如此困难。将两完全不一样的硬件做到软件兼容,的确有些难度。不,是很有难度。rnrn么如何实现呢?问的好!答案是模拟。既然系统可以认识PS/2,那么我们就把USB设备模拟成PS/2设备好了。但是如何模拟呢?rnrn我们必须能够截获所有的USB中断,然后判断这个中断是不是一个来自键盘/鼠标的数据传输中断(在IA32架构下,这个事情被保留给了IRQ1/IRQ12)。如果是的话,那么读取USB键盘/鼠标里的数据,之后判断一下是不是一个新按的键,如果是的话,就把这个键译码成PS/2使用的Scan code Set 2.然后把这个键写到8042缓冲区里去。换言之我们模拟了一次PS/2键盘按键/鼠标移动。如果按键缓冲区满,模拟程序还必须主动触发一个IRQ1/IRQ12以便叫那些访问60/64端口的程序能够工作。rnrn以上就是Legacy USB的大致实现,实际的实现要复杂的多,而且这必须被实现成SMI,一旦涉及到SMI,那么事情将变得特别复杂。光是想想SMI能够在内存里搬来搬去就令人头晕N次了。rnrn 论坛

没有更多推荐了,返回首页