输入法最核心的是输入法引擎,输入法引擎负责加载和管理输入法配置和输入法的词库,输入法引擎对用户输入的拼音字符串进行处理并返回对应的候选列表。通过引入输入法引擎我们就可以将我们输入法的拼音串转换成对应的中文候选了。

这里我不建议用户自己开发输入法引擎,这个难度还是很大的,涉及到了音节拆分和智能组词等等。如果是简单的使用的话,采用开源的输入法引擎库就行,这里我采用的是谷歌的开源输入法引擎,引擎项目的地址如下:
谷歌拼音输入法安卓版

由于谷歌拼音输入法的引擎接口比较多,新手调用起来比较吃力,这里对输入法的引擎进行了简单的封装,封装之后就可以无脑使用了。封装的接口如下:
pinyin_engine.h

#ifndef _PINYIN_ENGINE_H_
#define _PINYIN_ENGINE_H_

#include <QObject>
class pinyin_engine : public QObject
{
    Q_OBJECT

public:
    explicit pinyin_engine (QObject *parent = 0);
    ~pinyin_engine ();


public:
    /**@brief 初始化输入法引擎
   * @param[in]  dir            词库文件的目录
   * @param[in]  max_spell_len  字符串最长的长度默认64
   * @param[in]  max_output_len 输出中文文本的最长长度
   * @return  函数执行结果
   * - 1  执行成功
   * - 0  执行错误
   */
    bool init(const QString &dir = "", int max_spell_len = 64, int max_output_len = 64);

    /**@brief 关闭输入法引擎
   */
    void deinit();

    /**@brief 清空词库缓存
   */
    void flush_cache();

    /**@brief 通过拼音的拼音字符串查找对应的候选结果
   * @param[in]  search 拼音字符串
   * @return  候选词的个数
   */
    unsigned int search(const QString &spell);

    /**@brief 删除候选拼音串中的音节然后重新获取候选
   * @param[in]  pos 删除音节的位置
   * @return  候选词的个数
   */
    unsigned int del_search(unsigned pos);

    /**@brief 对检索进行重置
   */
    void reset_search();

    /**@brief 查找正在检索的音节的位置
   * @return  对应的位置
   */
    unsigned short cur_search_pos();

    /**@brief 获取固定索引位置的候选词
   * @param[in]  index 候选词索引的位置
   * @return  候选词字符串
   */
    QString get_candidate(unsigned int index);

    /**@brief 选择部分音节的候选词作为部分词
   * @param[in]  index 部分音节的候选词
   * @return  候选词的个数
   */
    unsigned int choose(unsigned int index);

    /**@brief 取消上一次的候选
   * @return  返回取消候选之后的候选词的个数
   */
    unsigned unchoose();

private:
    bool m_enable;      //引擎开关
    int  m_spell_len;   //字符串长度
    int  m_output_len;  //输出字符串的长度
};

#endif

pinyin_engine.cpp

#include "pinyin_engine.h"
#include <QApplication>
#include <pinyinime.h>
#include <string.h>

using namespace ime_pinyin;

//系统词库的名称
#define DICT_PATH           "dict_pinyin.dat"

//用户词库的名称
#define DICT_USER_PATH      "dict_pinyin_user.dat"

//最多的汉字的候选个数
#define MAX_SINGLE_ZI 60

static size_t fix_cand_len (size_t cand, int output_len)
{

    size_t i;
    size_t decode_len;
    size_t single = 0;
    size_t multi = 0;
    char16 *cand_buf = new char16[output_len];

    //查找字拼音串中还没有被解析出来的拼音串的长度
    im_get_sps_str(&decode_len);

    //如果只有一个拼音字符的话候选只保留10个
    if (decode_len == 1) {
        if (cand > 10) {
            cand = 10;
        }
        delete cand_buf;
        return  cand;
    }

    for (i = 0; i < cand; i++) {
        //查找满足固定长度的候选
        im_get_candidate(i, cand_buf, output_len);

        //候选词的个数
        if (strlen((char *)cand_buf) > 2)
        {
            multi++;
        }
        //候选字的个数
        else
        {
            single++;
            if (single > MAX_SINGLE_ZI) {
                break;
            }
        }
    }

    cand = multi + single;
    delete cand_buf;
    return  cand;
}

pinyin_engine::pinyin_engine(QObject *parent) :
    QObject(parent),m_enable(false)
{
}

pinyin_engine::~pinyin_engine()
{
}

bool pinyin_engine::init(const QString &dir, int max_spell_len, int max_output_len)
{
    bool    ret;
    QString app_dir = dir;
    if (app_dir.isEmpty()) {
        app_dir = qApp->applicationDirPath() + "/dict";
    }

    //打开用户词库和系统词库
    ret = im_open_decoder(QString("%1/" DICT_PATH).arg(app_dir).toLocal8Bit().data(),
                          QString("%1/" DICT_USER_PATH).arg(app_dir).toLocal8Bit().data());
    m_enable = ret;

    if (ret == false) {
        return ret;
    }
    im_set_max_lens(max_spell_len ,max_output_len);
    reset_search();

    m_spell_len = max_spell_len;
    m_output_len = max_output_len;

    return  ret;
}

void pinyin_engine::deinit()
{
    im_close_decoder();
}

void pinyin_engine::flush_cache()
{
    im_flush_cache();
}


unsigned int pinyin_engine::search(const QString &spell)
{
    if (!m_enable)
    {
        return 0;
    }
    QByteArray bytearray;
    char    *pinyin;

    bytearray = spell.toUtf8();
    pinyin = bytearray.data();
    bytearray.size();

    size_t cand = im_search(pinyin, bytearray.size());

    cand = fix_cand_len(cand, m_output_len);
    return  (unsigned)cand;
}


unsigned int pinyin_engine::del_search(unsigned pos)
{
    if (!m_enable)
    {
        return 0;
    }
    size_t cand = im_delsearch(pos, false, false);

    cand = fix_cand_len(cand, m_output_len);

    return  (unsigned)cand;
}

void pinyin_engine::reset_search()
{
    if (!m_enable)
    {
        return;
    }
    im_reset_search();
}

unsigned short pinyin_engine::cur_search_pos()
{
    const uint16 *start_pos;
    size_t  pos_len;
    size_t  fixed_len = im_get_fixed_len();

    pos_len = im_get_spl_start_pos(start_pos);
    if (fixed_len <= pos_len) {
        return  (start_pos[fixed_len]);
    }
    return  0;
}

QString pinyin_engine::get_candidate(unsigned int index)
{
    char16 *cand_buf = new char16[m_output_len];
    char16 *cand;
    QString cand_str;

    cand = im_get_candidate(index, cand_buf, m_output_len);
    if (cand) {
        cand_str = QString::fromUtf16(cand);
        if (index == 0) {
            cand_str.remove(0, im_get_fixed_len());
        }
    } else {
        cand_str = "";
    }

    delete cand_buf;
    return cand_str;
}


unsigned int pinyin_engine::choose(unsigned int index)
{
    size_t left;

    left = im_choose(index);

    left = fix_cand_len(left, m_output_len);
    if (left < 1)
    {
        return  0;
    } else {
        return  (left - 1);
    }
}

unsigned pinyin_engine::unchoose()
{
    size_t cand = im_cancel_last_choice();

    cand = fix_cand_len(cand, m_output_len);

    return  (unsigned)cand;
}

通过封装的接口我们就可以很方便的将用户输入的音节字符串转换成对应的中文候选了,这个功能是输入法的基础很重要。

相关推荐

输入法开发之:疑难杂症

套娃开始:当键盘事件被触发时,获得的参数是ITfContext。但是ITfContext并不能直接修改内容添加文字等,需要调用RequestEditSession,传入一个ITfEditSession

获取输入法坐标

以下是微软TSF输入法取坐标的方法,从里面扒出来的int 取坐标(ITfContext *pContext, TfEditCookie ec, ITfComposition* pRangeCompos

微软输入法TSF SampleIME 源码分析(转载)

类:CCandidateWindow,候选字窗口CCompositionPricessorEngine,拼写引擎CSampleIME,主程序CStringRange, 一个特殊的字符串类 见于 Sam

输入法的注册、安和卸载

注册输入法输入法的安装和普通应用程序有一个大的区别是,除了复制文件到安装目录、做一些必要的设置外,还需要向Windows系统注册这个输入法。我们前期一篇博文 TSF(Text Service Fram

逗比的输入法实现(二):基础概念和常用接口

为什么叫 Meow?因为这是给猫用的输入法。。。目录(一):基本情况(二):基础概念和常用接口(三):整体构架(四):编辑和候选(五):界面管理和无界面模式(六):词库和候选算法(七):皮肤的实现(八

Windows IMM-IME汉字输入法

1.IMM与IMEIMM是Input Method Manage(输入法管理器)的缩写,IME是Input Method Editor(输入法编辑器)的缩写。微软公司在Windows 95/98/NT

TSF(Text Services Framework)和输入法

1.TSF输入接口IMM-IME架构成熟,稳定,易于实现,在Windows中被广泛使用,甚至在Linux曾大量使用的中文输入接口SCIM中也可以看到IMM-IME的影子。但是由于IMM-IME在操作权

[输入法]TSF框架中预先上屏的字符管理和控制

在TSF框架中有时候我们需要通过框架上屏一些占位字符来进行定位,这时候我们就需要对预先上屏的字符进行管理,以微软的输入法为例图中红框框选出来的部分就是预先上屏的字符。在TSF框架中通过ITfRange

输入法TSF框架候选栏定位研究

在开发输入法应用的时候,我们需要让候选栏时刻跟踪输入光标的位置,来进行输入。但候选栏定位不准,一直会困扰输入法的开发者。windows老的输入法框架imm在部分场景下比如chrome应用中会定位不准,

[输入法]Qt实现软键盘

在使用输入法的时候,为了输入一些特殊字符我们往往会用到软键盘和符号大全。符号大全和软件盘是一类程序,主要实现的就是通过界面点击向目标程序输出对应的符号。这里介绍一下如何通过QT编写软键盘类程序,实现软