IME編程之 游標跟隨

來源:互聯網
上載者:User

   游標跟隨是IME系統最常見的特性。要實現這一特性,需要擷取IME支援程式(最常見如word,notepad等)中插入符號caret的座標位置。在Windows的IME環境中,可以通過使用IME核心資料結構INPUTCONTEXT的cfCompForm成員來擷取IME宿主程式中文本游標位置。cfCompForm具有如下結構:
typedef tagCANDIDATEFORM { //列表視窗資訊
//由IMC_GETCANDIDATEPOS和IMC_SETCANDIDATEPOS訊息處理
DWORD dwIndex; //列表視窗序號
DWORD dwStyle; //屬性:
//=CFS_CANDIDATEPOS 指定顯示位置
//=CFS_EXCLUDE 不可顯示
//=CFS_DEFAULT 根據需要顯示
POINT ptCurrentPos; //座標位置
REC rcArea; //不可顯示區
} CANDIDATEFORM;
其中ptCurrentPos就是我們需要的游標位置,不過因為這是客戶區的座標,需要轉化為螢幕座標才能使用。要使得IME上下文結構INPUTCONTEXT中已經填入了正確的座標位置,需要實現WM_IME_NOTIFY訊息響應事件。在WM_IME_NOTIFY訊息的子訊息IMN_SETCOMPOSITIONWINDOW(設定編碼視窗訊息)被觸發時,系統會返回正確的座標位置。WM_IME_NOTIFY訊息響應函數類似如下形式:
/*
 * IMENotifyHandle():                                              
 *                                                                   
 * Handle WM_IME_NOTIFY messages.                                    
 */
LONG IMENotifyHandle(HIMC hUICurIMC, HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
  LONG lRet = 0L;
  LPINPUTCONTEXT lpIMC; 

  if (!(lpIMC = ImmLockIMC(hUICurIMC)))
      return 0L;

  switch (wParam)
  {
  case IMN_CLOSESTATUSWINDOW:
   TRACE("UIWnd:WM_IME_NOTIFY:IMN_CLOSESTATUSWINDOW/n");

   /// hide the status window
   g_pStatus->Hide();  
   break;
  
  case IMN_OPENSTATUSWINDOW:
   TRACE("UIWnd:WM_IME_NOTIFY:IMN_OPENSTATUSWINDOW/n");
  
   /// create the status window, but don't show
   g_pStatus->Create(hWnd);
   break;
  
  case IMN_OPENCANDIDATE:
   TRACE("UIWnd:WM_IME_NOTIFY:IMN_OPENCANDIDATE/n");
   break;
  
  case IMN_CHANGECANDIDATE:
   TRACE("UIWnd:WM_IME_NOTIFY:IMN_CHANGECANDIDATE/n");
   break;
  
  case IMN_CLOSECANDIDATE:
   TRACE("UIWnd:WM_IME_NOTIFY:IMN_CLOSECANDIDATE/n");
   break;
  
  case IMN_SETCONVERSIONMODE:
   TRACE("UIWnd:WM_IME_NOTIFY:IMN_SETCONVERSIONMODE/n");

   /// repaint the status window
   g_pStatus->Repaint();
   break;
  
  case IMN_SETSENTENCEMODE:
   TRACE("UIWnd:WM_IME_NOTIFY:IMN_SETSENTENCEMODE/n");
   break;
  
  case IMN_SETOPENSTATUS:
   TRACE("UIWnd:WM_IME_NOTIFY:IMN_SETOPENSTATUS/n"); 

   /// repaint the status window
   g_pStatus->Repaint();
   break;
  
  case IMN_SETCANDIDATEPOS:
   TRACE("UIWnd:WM_IME_NOTIFY:IMN_SETCANDIDATEPOS/n");
   break;
  
  case IMN_SETCOMPOSITIONFONT:
   TRACE("UIWnd:WM_IME_NOTIFY:IMN_SETCOMPOSITIONFONT/n");
   break;
  
  case IMN_SETCOMPOSITIONWINDOW:
   TRACE("UIWnd:WM_IME_NOTIFY:IMN_SETCOMPOSITIONWINDOW/n");

   /// adjust the postion of comp and cand windows   
   POINT ptSrc;
   SIZE szOffset;
   HDC hDC; 

   ptSrc = lpIMC->cfCompForm.ptCurrentPos;
   ClientToScreen(lpIMC->hWnd, &ptSrc);
   hDC = GetDC(lpIMC->hWnd);  
   GetTextExtentPoint(hDC,"A",1,&szOffset);  
   ReleaseDC(lpIMC->hWnd,hDC);

   g_ptTopLeft.x = ptSrc.x + szOffset.cx;
   g_ptTopLeft.y = ptSrc.y + szOffset.cy;   
   break;
  
  case IMN_GUIDELINE:
   TRACE("UIWnd:WM_IME_NOTIFY:IMN_GUIDELINE/n");
   break;
  
  case IMN_SETSTATUSWINDOWPOS:
   TRACE("UIWnd:WM_IME_NOTIFY:IMN_SETSTATUSWINDOWPOS/n");
   break;
  
  case IMN_PRIVATE:
   TRACE("UIWnd:WM_IME_NOTIFY:IMN_PRIVATE/n");
   break;
  
  default:
   break;
  }
 
  ImmUnlockIMC(hUICurIMC);

  return lRet;
}
其中,需要注意的是要確保擷取正確的位置,必須有先發送過WM_IME_STARTCOMPOSITION訊息,這個訊息一般在剛開始輸入新拼音時候發送!關於IME訊息處理可以看MSDN相關文檔。
    即便如此,仍然不能保證在所有程式中,IME都能正確地體現游標跟隨,我遇到的情況是在UtraEdit中,上述代碼毫無作用,IMN_SETCOMPOSITIONWINDOW根本就沒有被系統觸發,這時我只好通過GetCaretPos來僥倖地擷取游標位置。
 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.