输入法编程之 光标跟随

        光标跟随是输入法系统最常见的特性。要实现这一特性,需要获取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就是我们需要的光标位置,不过因为这是客户区的坐标,需要转化为屏幕坐标才能使用。要使得输入法上下文结构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相关文档。
    即便如此,仍然不能保证在所有程序中,输入法都能正确地体现光标跟随,我遇到的情况是在UtraEdit中,上述代码毫无作用,IMN_SETCOMPOSITIONWINDOW根本就没有被系统触发,这时我只好通过GetCaretPos来侥幸地获取光标位置。
 



Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1349102


 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
问题描述: 在Linux下运行javaswing程序时,中文输入法下输入时,光标不会随着输入移动,会停留在原位置。 问题分析: 这是Linux系统下中文输入法的默认行为,由于输入法引擎和Java GUI的事件处理机制不同,在输入时会出现光标不跟随的现象。 解决方案: 可以通过在程序中监听键盘事件,并手动更新光标位置来解决这个问题。下面是一个示例代码: ``` import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Point; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.im.InputContext; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; public class InputMethodCursor extends JFrame implements KeyListener { /** * */ private static final long serialVersionUID = 1L; JTextArea inputArea; JPanel panel; public InputMethodCursor() { setTitle("Input Method Cursor"); setSize(new Dimension(400, 400)); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); inputArea = new JTextArea(); inputArea.setPreferredSize(new Dimension(300, 300)); inputArea.setWrapStyleWord(true); inputArea.setLineWrap(true); inputArea.addKeyListener(this); JScrollPane scrollPane = new JScrollPane(inputArea); panel = new JPanel(new GridBagLayout()); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 0; gbc.anchor = GridBagConstraints.NORTHWEST; panel.add(scrollPane, gbc); getContentPane().setLayout(new BorderLayout()); getContentPane().add(panel, BorderLayout.CENTER); setVisible(true); } @Override public void keyPressed(KeyEvent e) { if (InputContext.getInstance().getLocale().equals("zh_CN")) { Point point = inputArea.getCaretPosition(); inputArea.setText(inputArea.getText() + e.getKeyChar()); inputArea.setCaretPosition(point.x + 1); } } @Override public void keyReleased(KeyEvent arg0) { // TODO Auto-generated method stub } @Override public void keyTyped(KeyEvent arg0) { // TODO Auto-generated method stub } public static void main(String[] args) { new InputMethodCursor(); } } ``` 在输入法为中文时,监听键盘事件,获取当前光标位置并手动更新位置。 这样就可以在Linux系统上正常使用中文输入法了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值