Qte中实现输入法窗口跟随光标移动功能

    最近实现一个嵌入式平台的输入法,上网找了下资料,不算很多,只是写论文。根据论文的架构,自己一点一点地实现功能,目前已经能够支持数字、英文、符号、拼音。没有联想,但是对于嵌入式平台,已经足够了。最后想实现输入法的框跟随光标移动的功能。移动输入法的框很简单,但是获得当前光标的坐标费了我很大力气。

    在网上我没有找到类似的文章,完全是自己一点一点摸索出来的。

    想要直接获得光标的坐标是不可能的,所以我分为了两步,

    一、获得当前光标所在的窗口

 m_cursorPos =  (QApplication::activeWindow ())->mapToGlobal(m_cursorPos);

这句话勉强符合我的要求,因为输入法启动时,肯定高亮在输入框上,而我获得当前激活窗口也因该是输入框的父窗口。

需要注意的是一个类似的函数focusWidget

QApplication::focusWidget () 

Returns the application widget that has the keyboard input focus, or 0 if no widget in this application has the focus.

QApplication::activeWindow ()
Returns the application top-level window that has the keyboard input focus, or 0 if no application window has the focus. There might be an activeWindow() even if there is no focusWidget(), for example if no widget in that window accepts key events.

对照看完以上解释,因该就明白什么意思了,也就是说focusWidget获得的是输入框的指针,而activeWindow得到的是最上层窗口,也就是输入框父窗口的指针。所以只能使用activeWindow,否则你磕破脑袋也不会明白错在哪里。

   

    二、获得当前光标在输入框中的位置,这步非常关键,方法也很隐蔽。

    做过嵌入式输入法的人都知道,自己的输入法都是从类QWSInputMethod继承过来的,所以自然而然地会想到类中是不是有什么方法能够得到当前光标,帮助读了好久也没发现类似的函数,只有方法能够得到光标的位置,这个位置只是他在输入框中的多少个字符之后的信息,所以无法完成功能。最后在一个隐蔽的小角落发现有这样一个函数

void QWSInputMethod::sendQuery ( int property ) [protected]
Sends an input method query (internally encapsulated by a QWSEvent of the IMQuery type) for the specified property.
To receive responses to input method queries, the virtual queryResponse() function must be reimplemented.

这个函数的功能就是发送查询,至于查询的方法和可查询的信息一点没说,点进IMQuery也不是对应的事件,所以第一次我放弃了这个方法,在多次尝试他法未果后,我又回到了这个函数,这次我认真地读了函数的用法,还是没有相关的信息。后来我意外地发现QT中有这样一个枚举

enum Qt::InputMethodQuery
Constant    Value    Description
Qt::ImMicroFocus    0    The rectangle covering the area of the input cursor in widget coordinates.
Qt::ImFont    1    The currently used font for text input.
Qt::ImCursorPosition    2    The logical position of the cursor within the text surrounding the input area (see ImSurroundingText).
Qt::ImSurroundingText    3    The plain text around the input area, for example the current paragraph.
Qt::ImCurrentSelection    4    The currently selected text.
Qt::ImMaximumTextLength    5    The maximum number of characters that the widget can hold. If there is no limit, QVariant() is returned.
Qt::ImAnchorPosition    6    The position of the selection anchor. This may be less or greater than ImCursorPosition, depending on which side of selection the cursor is. If there is no selection, it returns the same as ImCursorPosition.
我立即意识到这才是真正的查询事件。这才有了进展。

函数原理是通过QWSInputMethod::sendQuery(Qt::ImMicroFocus);或者QWSServer::sendIMQuery()发起查询请求。后一种方法是静态的,所以任何地方都能调用。然后在QWSInputMethod的继承类中实现void queryResponse ( int property, const QVariant & result );接口接收查询结果。

void XXXXXXXX::queryResponse ( int property, const QVariant & result )
{
    switch(property)
    {
    case Qt::ImMicroFocus:
        。。。

}

接收到是一个QRect的对象,其中包含了当前光标在窗口中的位置,还需要转化为相对于屏幕的坐标:

        QRect rect = result.value<QRect>();
        //(QApplication::focusWidget ())->mapToGlobal(m_cursorPos);
       rect =  (QApplication::activeWindow ())->mapToGlobal(rect);

这样就得到了当前光标相对于屏幕的偏移了。再调用move函数设置窗口,当然建议自己封装一个tryToMove函数,以免窗口移出屏幕。

展开阅读全文

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