精华内容
下载资源
问答
  • 首先输入法必备的19个接口自己不要删除,不然输入法编译出来安装失败不要狗叫= = 其次输入法的文件类型要设置为驱动,子类型要设置为输入法才能被ImmInstallIME函数安装,不然安装失败不能注入 如何修改参照最下面的...
    代码思路原作者,不详.......................膜拜第一位作者的开创思维
    
    本人只是稍作修改和写入一些原作者没有告诉的东西
    
    首先输入法必备的19个接口自己不要删除,不然输入法编译出来安装失败不要狗叫= =
    
    其次输入法的文件类型要设置为驱动,子类型要设置为输入法才能被ImmInstallIME函数安装,不然安装失败不能注入
    
    如何修改参照最下面的方法
    
    ‍------------------------------------------------------------------
    
    思路:
    
      1.创建一个文件映射对象,映射到内存,写入需要注入的dll名称,进程ID
    
      2.保存原有默认输入法句柄,复制输入法程序到系统目录,并调用ImmInstallIME安装输入法
    
      3.创建事件对象,以便同步dll的加载与卸载。
    
      4.向目标进程的窗口句柄发送WM_INPUTLANGCHANGEREQUEST消息,lParam为输入法句柄
    
      5.等待注入完成,广播WM_INPUTLANGCHANGEREQUEST消息,lParam为原有默认输入法句柄
    
      6.卸载输入法,释放事件对象。
    
     
    
    先来ime输入法,记得把编译出来的程序后缀设置为ime
    
    library   Ime;
    
    uses
    
      Windows,
    
      SysUtils,
    
      Classes,
    
      Psapi,
    
      ImeMain in 'ImeMain.pas',
    
      ImeInject in 'ImeInject.pas';
    
    {$E ime}
    
    {$R  Ime.res}
    
    procedure MyDllProc(Reason: Integer);
    
    var
    
      LoadDllEvent:THandle;
    
      UnLoadDllEvent:THandle;
    
    begin
    
      case Reason of
    
        DLL_PROCESS_ATTACH:
    
          begin
    
            UnLoadDllEvent:=OpenEvent(EVENT_ALL_ACCESS,False,GUID_UNLOADDLL);
    
            if UnLoadDllEvent>0 then
    
            begin
    
              ResetEvent(UnLoadDllEvent);
    
            end;
    
            RegisterImeWindow;
    
            GetImeInjectInfo(@InjectInfo);
    
            if InjectInfo.ProcessId=GetCurrentProcessId then
    
            begin
    
              LoadDllEvent:=OpenEvent(EVENT_ALL_ACCESS,False,GUID_LOADDLL);
    
              LoadLibrary(@InjectInfo.DllName);       
    
               if LoadDllEvent>0 then
    
              begin
    
                SetEvent(LoadDllEvent);
    
              end;
    
            end;
    
          end;
    
        DLL_PROCESS_DETACH:
    
          begin
    
            UnRegisterImeWindow;
    
            UnLoadDllEvent:=OpenEvent(EVENT_ALL_ACCESS,False,GUID_UNLOADDLL);
    
            if UnLoadDllEvent>0 then
    
            begin
    
              SetEvent(UnLoadDllEvent);
    
            end;
    
          end;
    
     end;
    
    end;
    
     exports
    
      ImeConversionList,
    
      ImeConfigure,
    
      ImeDestroy,
    
      ImeEscape,
    
      ImeInquire,
    
      ImeProcessKey,
    
      ImeSelect,
    
      ImeSetActiveContext,
    
      ImeSetCompositionString,
    
      ImeToAsciiEx,
    
      NotifyIME,
    
      ImeRegisterWord,
    
      ImeUnregisterWord,
    
      ImeGetRegisterWordStyle,
    
      ImeEnumRegisterWord,
    
      UIWndProc,
    
      StatusWndProc,
    
      CompWndProc,
    
      CandWndProc;
    
    begin
    
      DllProc := @MyDllProc;
    
      MyDllProc(DLL_PROCESS_ATTACH);
    
    end.
    
    ‍-----------------------------------------------------
    
    ime的主要单元
    
    unit ImeMain;
    
    interface
    
    uses Windows,SysUtils,Classes,Imm,ImeInject;
    
    const
    
      IME_WINDOWCLASSNAME='Ime';
    
      IME_SMODE_NONE=$0000;
    
      UI_CAP_2700=$00000001;
    
      SELECT_CAP_CONVERSION=$00000001;
    
      // IME property bits
    
      IME_PROP_END_UNLOAD=$00000001;
    
      IME_PROP_KBD_CHAR_FIRST=$00000002;
    
      IME_PROP_IGNORE_UPKEYS=$00000004;
    
      IME_PROP_NEED_ALTKEY=$00000008;
    
      IME_PROP_NO_KEYS_ON_CLOSE=$00000010;
    
      IME_PROP_AT_CARET=$00010000;
    
      IME_PROP_SPECIAL_UI=$00020000;
    
      IME_PROP_CANDLIST_START_FROM_1=$00040000;
    
      IME_PROP_UNICODE=$00080000;
    
      IME_PROP_COMPLETE_ON_UNSELECT=$00100000;
    
    type
    
      PImeInfo=^TImeInfo;
    
      TImeInfo=record
    
        dwPrivateDataSize:DWORD;
    
        fdwProperty:DWORD;
    
        fdwConversionCaps:DWORD;
    
        fdwSentenceCaps:DWORD;
    
        fdwUICaps:DWORD;
    
        fdwSCSCaps:DWORD;
    
        fdwSelectCaps:DWORD;
    
      end;
    
      PTransMsg = ^TTransMsg;
    
      TTransMsg = record
    
        message: uInt;
    
        wParam: WParam;
    
        lParam: LParam;
    
      end;
    
      PTransMsgList = ^TTransMsgList;
    
      TTransMsgList = record
    
        uMsgCount: uInt;
    
        TransMsg: array[0..0] of TTransMsg;
    
      end;
    
      PPrivContext = ^TPrivContext;
    
      TPrivContext = record
    
        iImeState: Integer; 
    
        fdwImeMsg: DWord;   
    
        dwCompChar: DWord;  
    
        fdwGcsFlag: DWord;  
    
        uSYHFlg: uInt;
    
        uDYHFlg: uInt;
    
        uDSMHCount: uInt;
    
        uDSMHFlg: uInt;
    
        bSeq: array[0..12] of Char; // sequence code of input char
    
        fdwGB: DWord;
    
      end;
    
    function RegisterImeWindow:BOOL;
    
    procedure UnRegisterImeWindow;
    
    function ImeConversionList(hImc:HIMC;lpSource:PChar;lpCandList:PCandidateList;
    
      uBufLen,uFlag:UINT):DWORD;stdcall;
    
    function ImeConfigure(hKl:HKL;hWnd:HWND;dwMode:DWORD;lpData:Pointer)
    
      :BOOL;stdcall;
    
    function ImeDestroy(uForce:UINT):BOOL;stdcall;
    
    function ImeEscape(hImc:HIMC;uSubFunc:UINT;lpData:PChar):LRESULT;stdcall;
    
    function ImeInquire(lpImeInfo:PImeInfo;lpszUIClass:PChar;lpszOption:DWORD)
    
      :BOOL;stdcall;
    
    function ImeProcessKey(hImc:HIMC;uKey:UINT;lKeyData:LPARAM;
    
      lpbKeyState:PKeyboardState):BOOL;stdcall;
    
    function ImeSelect(hImc:HIMC;fSelect:BOOL):BOOL;stdcall;
    
    function ImeSetActiveContext(hImc:HIMC;fFlag:BOOL):BOOL;stdcall;
    
    function ImeSetCompositionString(hImc:HIMC;dwIndex:DWORD;lpComp:Pointer;
    
      dwComp:DWORD;lpRead:Pointer;dwRead:DWORD):BOOL;stdcall;
    
    function ImeToAsciiEx(uVKey,uScanCode:UINT;lpbKeyState:PKeyboardState;
    
      lpdwTransKey:PTransMsgList;fuState:UINT;hImc:HIMC):UINT;stdcall;
    
    function NotifyIME(hImc:HIMC;dwAction:DWORD;dwIndex:DWORD;
    
      dwValue:DWORD):BOOL;stdcall;
    
    function ImeRegisterWord(lpszReading:PChar;dwStyle:DWORD;lpszString:PChar)
    
      :BOOL;stdcall;
    
    function ImeUnregisterWord(lpszReading:PChar;dwStyle:DWORD;lpszString:PChar)
    
      :BOOL;stdcall;
    
    function ImeGetRegisterWordStyle(nItem:UINT;lpStyleBuf:PStyleBuf):UINT;stdcall;
    
    function ImeEnumRegisterWord(lpfnRegisterWordEnumProc:RegisterWordEnumProc;
    
      lpszReading:PChar;dwStyle:DWORD;lpszString:PChar;lpData:Pointer):UINT;stdcall;
    
    function UIWndProc(hWnd:HWND;Msg:UINT;wParam:WPARAM;lParam:LPARAM)
    
      :LRESULT;stdcall;
    
    function StatusWndProc(hWnd:HWND;Msg:UINT;wParam:WPARAM;lParam:LPARAM)
    
      :LRESULT;stdcall;
    
    function CompWndProc(hWnd:HWND;Msg:UINT;wParam:WPARAM;lParam:LPARAM)
    
      :LRESULT;stdcall;
    
    function CandWndProc(hWnd:HWND;Msg:UINT;wParam:WPARAM;lParam:LPARAM)
    
      :LRESULT;stdcall;
    
    var
    
      InjectInfo:TImeInject;
    
    implementation
    
    function RegisterImeWindow:BOOL;
    
    var
    
      wc:WNDCLASSEX;
    
    begin
    
      wc.style:=CS_IME or CS_VREDRAW or CS_HREDRAW or CS_DBLCLKS;
    
      wc.lpfnWndProc:=@UIWndProc;
    
      wc.cbClsExtra:=0;
    
      wc.cbWndExtra:=0;
    
      wc.hInstance:=HInstance;
    
      wc.hIcon:=0;
    
      wc.hCursor:=LoadCursor(0, IDC_ARROW );
    
      wc.hbrBackground:=GetStockObject(WHITE_BRUSH);
    
      wc.lpszMenuName:=nil;
    
      wc.lpszClassName:=IME_WINDOWCLASSNAME;
    
      wc.hIconSm:=0;
    
      Result:=Windows.RegisterClassEx(wc)<>0;
    
    end;
    
    procedure UnRegisterImeWindow;
    
    begin
    
      Windows.UnregisterClass(IME_WINDOWCLASSNAME,HInstance);
    
    end;
    
    function ImeConversionList(hImc:HIMC;lpSource:PChar;lpCandList:PCandidateList;
    
      uBufLen,uFlag:UINT):DWORD;
    
    begin
    
      Result:=0;
    
    end;
    
    function ImeConfigure(hKl:HKL;hWnd:HWND;dwMode:DWORD;lpData:Pointer):BOOL;
    
    begin
    
      Result:=dwMode=IME_CONFIG_GENERAL;
    
    end;
    
    function ImeDestroy(uForce:UINT):BOOL;
    
    begin
    
      Result:=not BOOL(uForce);
    
    end;
    
    function ImeEscape(hImc:HIMC;uSubFunc:UINT;lpData:PChar):LRESULT;
    
    begin
    
      Result:=0;
    
    end;
    
    function ImeInquire(lpImeInfo:PImeInfo;lpszUIClass:PChar;lpszOption:DWORD):BOOL;
    
    begin
    
      Result := False;
    
      lpImeInfo.dwPrivateDataSize:=SizeOf(TPrivContext);
    
      lpImeInfo.fdwProperty:=IME_PROP_KBD_CHAR_FIRST or IME_PROP_IGNORE_UPKEYS;
    
      lpImeInfo.fdwConversionCaps:=IME_CMODE_FULLSHAPE or IME_CMODE_NATIVE;
    
      lpImeInfo.fdwSentenceCaps:=IME_SMODE_NONE;
    
      lpImeInfo.fdwUICaps:=UI_CAP_2700;
    
      lpImeInfo.fdwSCSCaps:=0;
    
      lpImeInfo.fdwSelectCaps:=SELECT_CAP_CONVERSION;
    
      StrCopy(lpszUIClass,IME_WINDOWCLASSNAME);
    
      Result:=True;
    
    end;
    
    function ImeProcessKey(hImc:HIMC;uKey:UINT;lKeyData:LPARAM;
    
      lpbKeyState:PKeyboardState):BOOL;
    
    begin
    
      Result:=False;
    
    end;
    
    function ImeSelect(hImc:HIMC;fSelect:BOOL):BOOL;
    
    begin
    
      Result:=True;
    
    end;
    
    function ImeSetActiveContext(hImc:HIMC;fFlag:BOOL):BOOL;
    
    begin
    
      Result:=True;
    
    end;
    
    function ImeSetCompositionString(hImc:HIMC;dwIndex:DWORD;lpComp:Pointer;
    
      dwComp:DWORD;lpRead:Pointer;dwRead:DWORD):BOOL;
    
    begin
    
      Result:=False;
    
    end;
    
    function ImeToAsciiEx(uVKey,uScanCode:UINT;lpbKeyState:PKeyboardState;
    
      lpdwTransKey:PTransMsgList;fuState:UINT;hImc:HIMC):UINT;
    
    begin
    
      Result:=0;
    
    end;
    
    function NotifyIme(hImc:HIMC;dwAction:DWORD;dwIndex:DWORD;
    
      dwValue:DWORD):BOOL;
    
    begin
    
      Result:=False;
    
    end;
    
    function ImeRegisterWord(lpszReading:PChar;dwStyle:DWORD;lpszString:PChar):BOOL;
    
    begin
    
      Result:=False;
    
    end;
    
    function ImeUnregisterWord(lpszReading:PChar;dwStyle:DWORD;lpszString:PChar)
    
      :BOOL;
    
    begin
    
      Result:=False;
    
    end;
    
    function ImeGetRegisterWordStyle(nItem:UINT;lpStyleBuf:PStyleBuf):UINT;
    
    begin
    
      Result:=0;
    
    end;
    
    function ImeEnumRegisterWord(lpfnRegisterWordEnumProc:RegisterWordEnumProc;
    
      lpszReading:PChar;dwStyle:DWORD;lpszString:PChar;lpData:Pointer):UINT;
    
    begin
    
      Result:=0;
    
    end;
    
    function UIWndProc(hWnd:HWND;Msg:UINT;wParam:WPARAM;lParam:LPARAM):LRESULT;
    
    begin
    
      Result:=0;
    
    end;
    
    function StatusWndProc(hWnd:HWND;Msg:UINT;wParam:WPARAM;lParam:LPARAM):LRESULT;
    
    begin
    
      Result:=0;
    
    end;
    
    function CompWndProc(hWnd:HWND;Msg:UINT;wParam:WPARAM;lParam:LPARAM):LRESULT;
    
    begin
    
      Result:=0;
    
    end;
    
    function CandWndProc(hWnd:HWND;Msg:UINT;wParam:WPARAM;lParam:LPARAM):LRESULT;
    
    begin
    
      Result:=0;
    
    end;
    
    end.
    
    ---------------------------------------------------------------
    
    ime和注入程序的公共单元
    
    unit ImeInject;
    
    interface
    
    uses Windows,SysUtils;
    
    const
    
      GUID_INJECT='{7E145D1D-663A-5BDC-EA47-B11342BF2315}';
    
      GUID_LOADDLL='{7E145D1D-663A-5BDC-EA47-B11342BF2416}';
    
      GUID_UNLOADDLL='{7E145D1D-663A-5BDC-EA47-B11342BF2517}';
    
    type
    
      PImeInject= ^TImeInject;
    
      TImeInject= packed record
    
        DllName:array[0..MAX_PATH] of Char;//注入的dll路径
    
        ProcessId: DWORD;//注入的进程ID
    
      end;
    
    procedure CreateImeInjectInfo(DllName: string; ProcessId: DWORD; var FileMapHandle:THandle);
    
    procedure GetImeInjectInfo(ImeInject:PImeInject);
    
    implementation
    
    procedure CreateImeInjectInfo(DllName:string; ProcessId: DWORD; var FileMapHandle:THandle);
    
    var
    
      InjectInfo:PImeInject;
    
    begin
    
      FileMapHandle:=0;
    
      FileMapHandle := CreateFileMapping(INVALID_HANDLE_VALUE,nil,PAGE_READWRITE,0,SizeOf(TImeInject),GUID_INJECT); //以可读写形式创建有名文件映象
    
      if FileMapHandle > 0 then //返回的文件映射对象句柄不为零
    
      begin
    
        InjectInfo:=MapViewOfFile(FileMapHandle,FILE_MAP_ALL_ACCESS,0,0,0); //在调用的进程中地址空间映射一个可完全控制文件视图
    
        if InjectInfo<>nil then  //如果返回的映射视图的起始地址不为空
    
        begin
    
          ZeroMemory(InjectInfo,SizeOf(TImeInject)); //TImeInject结构内存填零
    
          CopyMemory(@(InjectInfo.DllName),PChar(DllName),MAX_PATH-1);  //填写结构体里的内容
    
          InjectInfo.ProcessId:=ProcessId; //填写进程ID
    
          UnmapViewOfFile(InjectInfo);  // 删除映射视图
    
        end;
    
      end;
    
    end;
    
    procedure GetImeInjectInfo(ImeInject:PImeInject);
    
    var
    
      FileMapHandle:THandle;
    
      InjectInfo:PImeInject;
    
    begin
    
      ZeroMemory(ImeInject,SizeOf(TImeInject));  //结构体内存填零
    
      FileMapHandle:=OpenFileMapping(FILE_MAP_READ,False,GUID_INJECT); //打开GUID_INJECT的文件映射
    
      if FileMapHandle>0 then 
    
      begin
    
        InjectInfo:=MapViewOfFile(FileMapHandle,FILE_MAP_READ,0,0,0);
    
        if InjectInfo<>nil then
    
        begin
    
          CopyMemory(ImeInject,InjectInfo,SizeOf(TImeInject));
    
          UnmapViewOfFile(InjectInfo);
    
        end;
    
        CloseHandle(FileMapHandle);
    
      end;
    
    end;
    
    end.
    
    -----------------------------------------------------------------------------------------
    
    注入程序,注意引用 ImeInject 单元 ,Imm 单元 和 Registry 单元
    
     
    
    const
    
      WM_INPUTLANGCHANGEREQUEST = $0050;
    
    var
    
      FileMapHandle: THandle;
    
     
    
    Procedure Inject(WindowName:string;Dllpath:string);
    
    var
    
      WindowHandle: THandle;
    
      InjectProcessId: DWORD;
    
      LoadDllEvent: THandle;
    
      UnLoadDllEvent: THandle;
    
      DefaultImeHandle: THandle;
    
      ImeHandle: THandle;
    
      ImeId: string;
    
      ImePath: string;
    
      SysDir: array[0..MAX_PATH] of Char;
    
    begin
    
      WindowHandle := FindWindow(nil, PChar(WindowName));
    
      if WindowHandle > 0 then
    
      begin
    
        GetWindowThreadProcessId(WindowHandle, InjectProcessId);
    
        if InjectProcessId > 0 then
    
        begin
    
          if FileMapHandle > 0 then
    
            CloseHandle(FileMapHandle);
    
          CreateImeInjectInfo(PChar(Dllpath), InjectProcessId,
    
            FileMapHandle);
    
          if FileMapHandle > 0 then
    
          begin
    
            SystemParametersInfo(SPI_GETDEFAULTINPUTLANG, 0, @DefaultImeHandle, 0);
    
            ZeroMemory(@SysDir, MAX_PATH);
    
            GetSystemDirectory(@SysDir, MAX_PATH);
    
            ImePath := string(SysDir) + '\ImeInject.ime';
    
            //复制输入法文件到系统目录
    
            if CopyFile(PChar(ExtractFilePath(Application.ExeName) + 'ImeInject.ime'),
    
              PChar(ImePath), False) then
    
            begin
    
              //安装输入法
    
              ImeHandle := ImmInstallIME(PChar(ImePath), 'zhusjm输入法');
    
              if ImeHandle > 0 then
    
              begin
    
                UnLoadDllEvent := CreateEvent(nil, True, True, GUID_UNLOADDLL);
    
                LoadDllEvent := CreateEvent(nil, True, False, GUID_LOADDLL);
    
                //向目标窗口发送激活输入法的消息
    
                PostMessage(WindowHandle,WM_INPUTLANGCHANGEREQUEST, 0,ImeHandle);
    
                //等待注入完成
    
                if WaitForSingleObject(LoadDllEvent, 3000) = WAIT_OBJECT_0 then
    
                begin
    
                  ShowMessage('注入成功');
    
                  //广播消息,使我们的输入法卸载
    
                  PostMessage(HWND_BROADCAST, WM_INPUTLANGCHANGEREQUEST, 0,
    
                    DefaultImeHandle);
    
                  //等待输入法卸载
    
                  if WaitForSingleObject(UnLoadDllEvent, 3000) = WAIT_OBJECT_0 then
    
                  begin
    
                  end;
    
                end;
    
                UnloadKeyboardLayout(ImeHandle);
    
                DeleteFile(ImePath);
    
                CloseHandle(UnLoadDllEvent);
    
                CloseHandle(LoadDllEvent);
    
              end;
    
            end;
    
          end;
    
        end;
    
      end;
    
    end;‍
    
    ---------------------------------------------------------------------
    
    因为ime的文件类型要设置为驱动,子类型要设置为输入法才能被ImmInstallIME函数安装,不然安装失败
    
    输入法ime的 资源文件,新建 rc 写入以下内容用delphi的brcc32.exe编译成res 然后 ime 里面
    
    引用这个资源再编译出来ime输入法才能被ImmInstallIME函数安装
    
    VS_VERSION_INFO VERSIONINFO //版本信息结构
    
    FILEVERSION 1,0,0,1   //文件版本
    
    PRODUCTVERSION 1,0,0,1 //这里是主版本信息
    
    FILEFLAGSMASK 0x3fL   //这里设为0x3fL就好
    
    #ifdef _DEBUG
    
    FILEFLAGS 0x1L       //VS_FF_DEBUG包括debug信息
    
    #else
    
    FILEFLAGS 0x0L       //无
    
    #endif
    
    FILEOS 0x4L         //win32程序
    
    FILETYPE 0x3L       //文件类型,2是dll,1是exe,3是VFT_DRV 驱动程序 
    
    FILESUBTYPE 0xbL    //VFT2_DRV_INPUTMETHOD 输入法驱动程序
    
    BEGIN
    
      BLOCK "StringFileInfo" //这里设置文件其他的版本信息(详细信息)
    
      BEGIN
    
        BLOCK "080403A8"   //所用语言080403A8简体中文
    
        BEGIN
    
            VALUE "Comments","Microsoft(R) Windows(R) Operating System"   //备注 
    
            VALUE "CompanyName","Microsoft(R)\0"           //公司名
    
            VALUE "FileDescription", "zhu.ime\0"       //产品描述
    
            VALUE "FileVersion", "1. 0. 0. 1\0"       //文件版本
    
            VALUE "InternalName", ""               //内部名称
    
            VALUE "LegalCopyright", "Copyright (C) 2000.01\0" //版权信息
    
            VALUE "OriginalFilename", "zhu.ime\0"         //源文件名
    
            VALUE "ProductName", "zhu.ime\0"           //产品名
    
            VALUE "ProductVersion", "1. 0. 0. 1\0"       //产品版本
    
        END
    
      END
    
      BLOCK "VarFileInfo"
    
      BEGIN
    
        VALUE "Translation", 0x804, 0x03A8
    
      END                    
    
    END
    
    绿色

    转载于:https://www.cnblogs.com/cnpler/archive/2012/03/19/2405433.html

    展开全文
  • vc编写输入法程序,T9输入法程序 vc编写输入法程序,T9输入法程序
  • 这是一个介绍用单片机开发手机输入法程序代码,压缩包中有完整的工程,可下载直接使用。
  • VC实现输入法程序

    热门讨论 2011-12-25 18:35:45
    输入法程序如何编写? 这是一个使用VC++实现的输入法程序
  • Qt编写输入法终极版V2018

    千次阅读 热门讨论 2018-05-17 10:26:31
    输入法是很多Qt+嵌入式linux开发的同学的痛,自从5.7自带了输入法后,这个痛终于缓解了不少,不过还有大量的嵌入式linux程序停留在qt4时代,为此特意选择了QWidget来写这个输入法,为了兼容qt4到qt5所有版本,陆续...

    输入法是很多Qt+嵌入式linux开发的同学的痛,自从5.7自带了输入法后,这个痛终于缓解了不少,不过还有大量的嵌入式linux程序停留在qt4时代,为此特意选择了QWidget来写这个输入法,为了兼容qt4到qt5所有版本,陆续完善了好几年,吸收过不少的建议,也卖出过不少份,感谢大家!
    1:纯QWidget编写,支持任何目标平台(亲测windows、linux、嵌入式linux等),支持任意Qt版本(亲测Qt4.6.0到Qt5.10.1)。
    2:调用极为方便,pri文件调用形式,只要改成文件包含即可,例如pro文件中写 include($$PWD/inputnew/inputnew.pri)。
    3:界面清晰简洁,UI美观友好,非常适合触摸设备。
    4:同时支持实体键盘输入+鼠标单击输入+触摸输入。
    5:支持迷你模式,界面大小随意设置,采用布局自使用任何分辨率。
    6:界面自适应屏幕大小,输入法弹出位置为控件底部时,当超过桌面右边或者底部时,自动调整位置。
    7:自由控制需要显示输入法和不需要显示输入法,当某些控件不需要弹出输入法,只需要对应不需要弹出输入法的控件设置属性noinput为真即可。例如ui->txt->setProperty("noinput", true);
    8:实现了长按超过500毫秒重复执行按下的键的功能。例如长按退格键,不断删除。
    9:shift键切换输入法,esc键隐藏输入法,空格选中第一个汉字,回车选中输入的拼音。和搜狗输入法处理一致。
    10:英文、中文、手写(功能编写中)、数字字母、大小写、特殊字符自由切换。
    11:支持单拼双拼词组输入,网上大部分只支持单个汉字输入。智能分页算法,可任意翻页查看汉字词组。
    12:默认自带5种皮肤颜色,可随意切换,用户也可用QSS自定义皮肤。
    13:字库文件可大可小,提供迷你版字库大小仅120KB,方便存储空间紧张的硬件,完整版字库25MB。
    14:整个输入法代码行数约1000行,非常小,不会对程序增加大小造成负担。

     

    15:代码结构极为清晰,注释详细,非常容易阅读和理解,同时也可以自行修改拓展自定义的需求。

     

    展开全文
  • Qt编写输入法V2019终极版

    千次阅读 2019-08-15 15:39:37
    之前写过的V2018版本的输入法,本来已经很完善了,不打算更新升级了,最近有个朋友找我定制一个输入法,需要高仿一个苹果MAC电脑的输入法,MAC操作系统的审美无疑是相当棒的,于是乎直接拿以前的输入法高仿了一个,...

    一、前言

    之前写过的V2018版本的输入法,本来已经很完善了,不打算更新升级了,最近有个朋友找我定制一个输入法,需要高仿一个苹果MAC电脑的输入法,MAC操作系统的审美无疑是相当棒的,于是乎直接拿以前的输入法高仿了一个,由于之前有做过输入法这块的开发,而且改进了四年,各种需求都遇到过,陆陆续续完善了很多年,所以这个高仿起来难度不大,而且要支持滑动选词,直接撸代码。
    体验地址:https://pan.baidu.com/s/1vIyEdB4QGo5OvxLYj7kq5g 提取码:sysn

    二、功能特点

    1. 未采用Qt系统层输入法框架,独创输入切换机制。
    2. 纯QWidget编写,支持任何目标平台(亲测windows、linux、嵌入式linux等),支持任意Qt版本(亲测Qt4.6.0到Qt5.13),支持任意编译器(亲测mingw、gcc、msvc等),支持任意控件输入包括网页中的输入控件。
    3. 调用极为方便,pri文件调用形式,只要改成文件包含即可,例如pro文件中写 include($$PWD/input2019/input2019.pri)。
    4. 界面清晰简洁,UI美观友好,高仿IOS输入法,非常适合触摸设备。
    5. 顶部滑动选词+弹出汉字面板选词,支持滑动。
    6. 具有记忆功能,之前选中过的词语首先显示,支持单个拼音多个汉字,自动调整优先级。
    7. 具有造词功能,可以直接打开文件文件写入自定义词组,最高级别显示。
    8. 支持Qt程序嵌入的浏览器中的网页中的文本框等控件的输入。
    9. 界面大小随意设置,采用布局自使用任何分辨率。
    10. 属性控制数字输入,例如需要文本框默认弹出的是数字则设置代码 ui->txt->setProperty(“flag”, “number”);
    11. 自由控制需要显示输入法和不需要显示输入法,当某些控件不需要弹出输入法,只需要对应不需要弹出输入法的控件设置属性noinput为真即可。例如ui->txt->setProperty(“noinput”, true);
    12. 界面自适应屏幕大小,输入法弹出位置为控件底部时,当超过桌面右边或者底部时,自动调整位置。
    13. 实现了长按超过500毫秒重复执行按下的键的功能。例如长按退格键,不断删除。
    14. 英文、中文、数字字母、大小写、特殊字符自由切换。
    15. 支持单拼、全拼、模糊拼音输入,智能分页算法,可任意翻页查看汉字词组。
    16. 默认自带5种皮肤颜色,可随意切换,用户也可用QSS自定义皮肤。
    17. 谷歌内核的输入法引擎,品质保证,字库文件1MB,不依赖数据库,资源占用低效率极高。支持模糊拼音,比如nh=你好。
    18. 可选windows专有版本,支持外部程序输入,比如输入到记事本、QQ聊天窗口等。
    19. 整个输入法代码行数1000行左右,非常小,不会对程序增加大小造成负担。
    20. 代码结构极为清晰,注释详细,非常容易阅读和理解,同时也可以自行修改拓展自定义的需求。

    三、效果图

    在这里插入图片描述

    四、使用方法

    1. 将input2019整个目录放到你的项目的pro同一级别目录中。
    2. 在你的主程序的pro文件中加一行 include($$PWD/input2019/input2019.pri)
    3. 在你的程序的main函数中引入头文件 #include “input2019/frminput2019.h”
    4. 在你的程序的main函数中加一行代码 QApplication a(argc, argv);之后加 frmInput2019::Instance()->hide();
    5. 将源码下的dict_pinyin.dat+dict_pinyin_user.dat字库文件复制到可执行文件同一目录。

    五、其他说明

    1. 如果想设置更小的尺寸,可用setFixedSize。
    2. 源码下的chinese_user.txt为自定义词组文件,打开编辑即可,该文件放到可执行文件同一目录即可。
    3. 如果是dialog窗体,请在dialog窗体exec前增加一行代码,QDialog dialog;dialog.setWindowModality(Qt::WindowModal);否则会阻塞窗体消息。
    4. 在某些嵌入式linux系统中,如果没有带有XCB,则输入法需要先show再hide一次,然后输入法才能起作用,不然程序会崩溃。

    六、核心代码

    bool frmInput2019::eventFilter(QObject *watched, QEvent *event)
    {
        if (watched == this) {
            //处理自身拖动
            static QPoint mousePoint;
            static bool mousePressed = false;
            QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
    
            //按下的时候记住坐标,移动到鼠标松开的位置
            if (event->type() == QEvent::MouseButtonPress) {
                if (mouseEvent->button() == Qt::LeftButton) {
                    mousePressed = true;
                    mousePoint = mouseEvent->globalPos() - this->pos();
                    return true;
                }
            } else if (event->type() == QEvent::MouseButtonRelease) {
                mousePressed = false;
                return true;
            } else if (event->type() == QEvent::MouseMove) {
                if (mousePressed && (mouseEvent->buttons() && Qt::LeftButton && position != "bottom")) {
                    this->move(mouseEvent->globalPos() - mousePoint);
                    this->update();
                    return true;
                }
            }
        } else if (watched == ui->labMore) {
            if (event->type() == QEvent::MouseButtonPress) {
                if (inputType == "chinese" && !upper && labCn.first()->isEnabled()) {
                    if (!ui->widgetChinese->isVisible()) {
                        ui->widgetLetter->setVisible(false);
                        ui->widgetNumber->setVisible(false);
                        ui->widgetChinese->setVisible(true);
                    } else {
                        ui->widgetLetter->setVisible(true);
                        ui->widgetNumber->setVisible(false);
                        ui->widgetChinese->setVisible(false);
                    }
    
                    //重新设置图标
                    QString strMore = ui->widgetMore->isVisible() ? "up" : "down";
                    ui->labMore->setPixmap(QString(":/image/btn_%1_%2.png").arg(strMore).arg(iconType));
                    return true;
                }
            }
        } else if (watched == ui->labType) {
            if (event->type() == QEvent::MouseButtonPress) {
                if (inputType == "english") {
                    setInputType("chinese");
                } else if (inputType == "chinese") {
                    setInputType("english");
                }
            }
        } else if (watched == ui->labType2) {
            if (event->type() == QEvent::MouseButtonPress) {
                setInputType("english");
            }
        } else if (watched == ui->widgetCn) {
            //没有汉字或者按下的地方没有汉字或者当前汉字标签个数过少都不用继续
            if (!labCn.first()->isEnabled() || lastText.isEmpty()) {
                return false;
            }
    
            //记住最后按下拖动的时间,过短则认为是滑动,启动滑动动画
            static bool pressed = false;
            static QPoint lastPos = QPoint();
            static QDateTime lastTime = QDateTime::currentDateTime();
            QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
    
            if (event->type() == QEvent::MouseButtonPress) {
                pressed = true;
                lastPos = mouseEvent->pos();
                animationCn->stop();
                lastTime = QDateTime::currentDateTime();
            } else if (event->type() == QEvent::MouseButtonRelease) {
                pressed = false;
                if (lastPos != mouseEvent->pos()) {
                    //判断当前时间和鼠标按下事件比较,时间短则说明是滑动
                    QDateTime now = QDateTime::currentDateTime();
                    if (lastTime.msecsTo(now) < 600) {
                        //可以改变下面的值来调整幅度
                        bool moveleft = (mouseEvent->pos().x() - lastPos.x()) < 0;
                        int offset = moveleft ? 350 : -350;
                        int value = ui->scrollAreaCn->horizontalScrollBar()->value();
                        animationCn->setStartValue(value);
                        animationCn->setEndValue(value + offset);
                        animationCn->start();
                    }
                }
            } else if (event->type() == QEvent::MouseMove) {
                if (pressed && labCn.first()->isEnabled()) {
                    //计算滑过的距离
                    bool moveleft = (mouseEvent->pos().x() - lastPos.x()) < 0;
                    int offset = moveleft ? 5 : -5;
                    int value = ui->scrollAreaCn->horizontalScrollBar()->value();
                    ui->scrollAreaCn->horizontalScrollBar()->setValue(value + offset);
                    return true;
                }
            }
        } else if (watched == ui->widgetMore) {
            //没有汉字或者按下的地方没有汉字或者当前汉字标签个数过少都不用继续
            if (!labMore.first()->isEnabled() || lastText.isEmpty()) {
                return false;
            }
    
            //记住最后按下拖动的时间,过短则认为是滑动,启动滑动动画
            static bool pressed = false;
            static QPoint lastPos = QPoint();
            static QDateTime lastTime = QDateTime::currentDateTime();
            QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
    
            if (event->type() == QEvent::MouseButtonPress) {
                pressed = true;
                lastPos = mouseEvent->pos();
                animationMore->stop();
                lastTime = QDateTime::currentDateTime();
            } else if (event->type() == QEvent::MouseButtonRelease) {
                pressed = false;
                if (lastPos != mouseEvent->pos()) {
                    //判断当前时间和鼠标按下事件比较,时间短则说明是滑动
                    QDateTime now = QDateTime::currentDateTime();
                    if (lastTime.msecsTo(now) < 600) {
                        //可以改变下面的值来调整幅度
                        bool movebottom = (mouseEvent->pos().y() - lastPos.y()) < 0;
                        int offset = movebottom ? 150 : -150;
                        int value = ui->scrollAreaMore->verticalScrollBar()->value();
                        animationMore->setStartValue(value);
                        animationMore->setEndValue(value + offset);
                        animationMore->start();
                    }
                }
            } else if (event->type() == QEvent::MouseMove) {
                if (pressed && labMore.first()->isEnabled()) {
                    //计算滑过的距离
                    bool movebottom = (mouseEvent->pos().y() - lastPos.y()) < 0;
                    int offset = movebottom ? 5 : -5;
                    int value = ui->scrollAreaMore->verticalScrollBar()->value();
                    ui->scrollAreaMore->verticalScrollBar()->setValue(value + offset);
                    return true;
                }
            }
        } else if (watched->inherits("QLabel")) {
            QLabel *lab = (QLabel *)watched;
            if (!upper && inputType == "chinese") {
                if (lab->property("labCn").toBool()) {
                    //记住最后按下的滚动条位置,如果滚动条一直没有变化则认为单击了标签
                    static int lastPosition = 0;
                    if (event->type() == QEvent::MouseButtonPress) {
                        lastPosition = ui->scrollAreaCn->horizontalScrollBar()->value();
                        lastText = lab->text();
                    } else if (event->type() == QEvent::MouseButtonRelease) {
                        if (lastPosition == ui->scrollAreaCn->horizontalScrollBar()->value() && !lastText.isEmpty()) {
                            insertValue(lab->text());
                            clearChinese();
                        }
                    }
                } else if (lab->property("labMore").toBool()) {
                    //记住最后按下的滚动条位置,如果滚动条一直没有变化则认为单击了标签
                    static int lastPosition = 0;
                    if (event->type() == QEvent::MouseButtonPress) {
                        lastPosition = ui->scrollAreaMore->verticalScrollBar()->value();
                        lastText = lab->text();
                    } else if (event->type() == QEvent::MouseButtonRelease) {
                        if (lastPosition == ui->scrollAreaMore->verticalScrollBar()->value() && !lastText.isEmpty()) {
                            insertValue(lab->text());
                            clearChinese();
                        }
                    }
                }
            }
        } else {
            if (event->type() == QEvent::MouseButtonPress) {
                if (currentWidget != 0) {
                    if (!isVisible()) {
                        showPanel();
                    }
                } else {
                    if (isVisible()) {
                        hidePanel();
                    }
                }
            }
        }
    
        return QWidget::eventFilter(watched, event);
    }
    
    void frmInput2019::initForm()
    {
    #if (QT_VERSION > QT_VERSION_CHECK(5,0,0))
        setWindowFlags(Qt::Tool | Qt::WindowDoesNotAcceptFocus | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint);
    #else
        setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint);
    #endif
    
        currentWidget = 0;
        upper = false;
        number = false;
        onlyControl = false;
        autoHide = false;
        columnCount = 8;
        maxCount = 256;
        dbPath = qApp->applicationDirPath();
    
        //绑定按钮到事件
        QList<QPushButton *> btns;
        btns << ui->widgetLetter->findChildren<QPushButton *>();
        btns << ui->widgetNumber->findChildren<QPushButton *>();
        foreach (QPushButton *btn, btns) {
            btn->setProperty("btnInput", true);
            connect(btn, SIGNAL(clicked()), this, SLOT(btnClicked()));
        }
    
        //设置字母属性
        btns.clear();
        btns << ui->widgetLetter1->findChildren<QPushButton *>();
        btns << ui->widgetLetter2->findChildren<QPushButton *>();
        foreach (QPushButton *btn, btns) {
            btn->setProperty("btnLetter", true);
        }
    
        //设置所有按钮输入法不可用+长按自动重复事件
        btns.clear();
        btns << this->findChildren<QPushButton *>();
        foreach (QPushButton *btn, btns) {
            btn->setFocusPolicy(Qt::NoFocus);
            btn->setProperty("noinput", true);
            btn->setAutoRepeat(true);
            btn->setAutoRepeatDelay(500);
        }
    
        //默认最大生成256个,添加到顶部滚动区域中
        for (int i = 0; i < maxCount; i++) {
            QLabel *lab = new QLabel;
            lab->setProperty("labCn", true);
            lab->setEnabled(false);
            ui->layout->addWidget(lab);
            labCn << lab;
        }
    
        //默认最大生成256个,添加到更多滚动区域中
        int row = 0;
        int column = 0;
        for (int i = 0; i < maxCount; i++) {
            QLabel *lab = new QLabel;
            lab->setProperty("labMore", true);
            lab->setEnabled(false);
            lab->setAlignment(Qt::AlignCenter);
            lab->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
            ui->gridLayout->addWidget(lab, row, column);
            labMore << lab;
    
            column++;
            if (column >= columnCount) {
                row++;
                column = 0;
            }
        }
    
        ui->lab1->setEnabled(false);
        ui->lab2->setEnabled(false);
        ui->labPY->setEnabled(false);
        ui->labMore->setEnabled(false);
    
        //输入法面板的字体名称和按钮字体大小即汉字区域字体大小
        setFontInfo(this->font().family(), 11, 10);
        //图标固定大小
        setIconSize(20, 20);
        //按钮之间的间隔
        setSpacing(6);
        //顶部汉字区域高度
        setTopHeight(40);
    
        //输入法面板的显示位置  control--显示在对应输入框的正下方 bottom--填充显示在底部  center--窗体居中显示
        setPosition("control");
        //输入法模式 english--英文模式  chinese--中文模式  number--数字特殊字符模式
        setInputType("english");
        //输入法面板的样式  black--黑色  blue--淡蓝色  brown--灰黑色  gray--灰色  silvery--银色
        setStyleName("black");
    
        //定义动画产生平滑数值
        animationCn = new QPropertyAnimation(ui->scrollAreaCn->horizontalScrollBar(), "value");
        animationCn->setEasingCurve(QEasingCurve::OutCirc);
        animationCn->setDuration(500);
    
        animationMore = new QPropertyAnimation(ui->scrollAreaMore->verticalScrollBar(), "value");
        animationMore->setEasingCurve(QEasingCurve::OutCirc);
        animationMore->setDuration(500);
    }
    
    void frmInput2019::init()
    {
        if (onlyControl) {
            ui->labPY->setVisible(false);
            this->installEventFilter(this);
            ui->labType->installEventFilter(this);
            ui->labType2->installEventFilter(this);
            ui->labMore->installEventFilter(this);
            ui->widgetCn->installEventFilter(this);
            ui->widgetMore->installEventFilter(this);
    
            foreach (QLabel *lab, labCn) {
                lab->installEventFilter(this);
            }
    
            foreach (QLabel *lab, labMore) {
                lab->installEventFilter(this);
            }
        } else {
            //绑定全局改变焦点信号槽
            connect(qApp, SIGNAL(focusChanged(QWidget *, QWidget *)), this, SLOT(focusChanged(QWidget *, QWidget *)));
            qApp->installEventFilter(this);
        }
    
        py.open(dbPath);
        readChinese();
    }
    
    展开全文
  • 如何在程序中切换输入法程序(visual studio VB源代码编写)对今后学习vb.net很帮助
  • Qt编写输入法V2018超级终结版

    千次阅读 热门讨论 2018-09-22 15:08:11
    要么不支持实体键盘同步,要么不能汉字输入,要么不支持网页输入等,这几年通过陆续接触大量的各种输入法应用场景客户,得到真实需求,不断改进,最近几天特意完善了数字键盘模式+外部程序输入支持(输入到记事本QQ...

    对于qt嵌入式linux开发人员来说,输入法一直是个鸡肋问题,要么不支持实体键盘同步,要么不能汉字输入,要么不支持网页输入等,这几年通过陆续接触大量的各种输入法应用场景客户,得到真实需求,不断改进,最近几天特意完善了数字键盘模式+外部程序输入支持(输入到记事本QQ等程序)+网页输入支持,花了不少的心血,头发都快掉光了!目前除了还剩T9布局输入+手写输入还没有实现外,基本上算是比较完美了。市面上能做到支持任意操作系统+任意Qt版本+任意编译器的支持的,基本上没有。
    功能特点:  
    1:未采用Qt系统层输入法框架,独创输入切换机制。
    2:纯QWidget编写,支持任何目标平台(亲测windows、linux、嵌入式linux等),支持任意Qt版本(亲测Qt4.6.0到Qt5.11.2),支持任意编译器(亲测mingw、gcc、msvc等),支持任意控件输入包括网页中的输入控件。
    3:调用极为方便,pri文件调用形式,只要改成文件包含即可,例如pro文件中写 include($$PWD/inputnew/inputnew.pri)。
    4:界面清晰简洁,UI美观友好,非常适合触摸设备。
    5:同时支持实体键盘输入+鼠标单击输入+触摸输入。
    6:支持Qt程序嵌入的浏览器中的网页中的文本框等控件的输入。
    7:支持迷你模式,界面大小随意设置,采用布局自使用任何分辨率。
    8:支持纯数字键盘模式,自由控制弹出完整输入法面板和数字键盘面板,只需要对控件设置属性即可。例如ui->txt->setProperty("flag", "number");
    9:自由控制需要显示输入法和不需要显示输入法,当某些控件不需要弹出输入法,只需要对应不需要弹出输入法的控件设置属性noinput为真即可。例如ui->txt->setProperty("noinput", true);
    10:界面自适应屏幕大小,输入法弹出位置为控件底部时,当超过桌面右边或者底部时,自动调整位置。
    11:实现了长按超过500毫秒重复执行按下的键的功能。例如长按退格键,不断删除。
    12:shift键切换输入法,esc键隐藏输入法,空格选中第一个汉字,回车选中输入的拼音。和搜狗输入法处理一致。
    13:英文、中文、手写、数字字母、大小写、特殊字符自由切换。
    14:支持单拼双拼词组输入,网上大部分只支持单个汉字输入。智能分页算法,可任意翻页查看汉字词组。
    15:默认自带5种皮肤颜色,可随意切换,用户也可用QSS自定义皮肤。
    16:字库文件可大可小,提供迷你版字库大小仅120KB,方便存储空间紧张的硬件,完整版字库25MB。
    17:可选谷歌内核的输入法引擎,字库文件1MB,不依赖数据库,资源占用低效率极高。支持模糊拼音,比如nh=你好。
    18:可选windows专有版本,支持外部程序输入,比如输入到记事本、QQ聊天窗口等。
    19:整个输入法代码行数1000行左右,非常小,不会对程序增加大小造成负担。
    20:代码结构极为清晰,注释详细,非常容易阅读和理解,同时也可以自行修改拓展自定义的需求。

    演示下载:https://pan.baidu.com/s/1FbafbGV6zUHwEFnbHxNq0g 

    输入到其他程序版本下载:https://pan.baidu.com/s/1Vry8a1FwCAffxyUoTPVIsg

    展开全文
  • 自己写的中文输入法程序,中文信息处理实验
  • Qt编写输入法源码V2019 未采用Qt系统层输入法框架,独创输入切换机制。 纯QWidget编写,支持任何目标平台(亲测windows、linux、嵌入式linux等),支持任意Qt版本(亲测Qt4.6.0到Qt5.13),支持任意编译器(亲测...
  • 不太清楚汉字在计算机中是如何存储的,想知道例如微软的智能ABC以及搜狗输入法是怎样实现拼音拼写下的汉字输入。
  • 一、前言之前写过的V2018版本的输入法,本来已经很完善了,不打算更新升级了,最近有个朋友找我定制一个输入法,需要高仿一个苹果MAC电脑的输入法,MAC操作系统的审美无疑是相当棒的,于是乎直接拿以前的输入法高仿...
  • 用delphi编写输入法这方面的资源和例程太少了,我在网上只找到一个,这就是区位输入法delpi版.拼音的呢?五笔的呢?如果这方面的高手不愿提供免费的例程的话,何不出书呢?相信会有不少的读者.最好在程序中加入较多中文...
  • 软键盘类 软键盘类编写如同输入法的软键盘 这是用VC编写程序
  • 这是一个国产的Javascript程序,叫做 JustInput,能够在线使用输入法,而不要求你机器上安装任何输入法程序,主要支持中文输入五笔、拼音、双拼、注音等等常用输入法。而且它因为是JavaScript写的,所以只要有浏览器...
  • IME输入法编程.doc

    2011-05-08 10:24:57
    程序员在编写输入法程序时只需要实现这些接口并导出就可以作为输入法使用。关于具体接口的定义不是本文的重点,如果您需要了解只需要在网络中搜索“输入法编程指南”就可以明白 ,更多信息参考MSDN。
  • 输入法手势程序源码

    2013-01-21 22:21:00
    2019独角兽企业重金招聘Python工程师标准>>> ...
  • 漫谈WinCE输入法编写
  • 硬件:树莓派3B系统:2017-08-16-raspbian-stretch.img本以为是个简单的问题,可是解决...最终只好采取妥协办法:用QT4,使用无法输入中文的qtcreator编出可以输入中文的qt4程序。先说一个结论。在raspbian下QT5的中...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 14,954
精华内容 5,981
热门标签
关键字:

如何编写输入法程序