秋·风

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 :: 管理 ::

lazarus 4.8及之前的版本QT5中文输入多字词组时只输入前2个中文

lazarus 4.8及之前的版本QT5中文输入多字词组时只输入前2个中文,lazarus trunk的QT5已修复这个Bug.
lazarus 4.8版可以参考lazarus trunk的版处理就可以。
lazarus/lcl/interfaces/qt5/qtwidgets.pas单元的
function TQtWidget.SlotInputMethod(Sender: QObjectH; Event: QEventH): Boolean; cdecl;

负责QT5文字输入。

function TQtWidget.SlotInputMethod(Sender: QObjectH; Event: QEventH): Boolean; cdecl;
var
  InputEvent: QInputMethodEventH;
  WStr: WideString;
  UnicodeChar: Cardinal;
  UnicodeOutLen: integer;
  KeyEvent: QKeyEventH;
  s:TStringList;
begin
  Result := True;
  if not (QEvent_type(Event) = QEventInputMethod) then Exit;
  {$ifdef VerboseQt}
    DebugLn('TQtWidget.SlotInputMethod ', dbgsname(LCLObject));
  {$endif}
  InputEvent := QInputMethodEventH(Event);
  QInputMethodEvent_commitString(InputEvent, @WStr);
  s:=TStringList.Create;
  s.Add(WStr);
  s.SaveToFile('/home/lbz/111.txt');
  UnicodeChar := UTF8CodepointToUnicode(PChar(WStr), UnicodeOutLen);
  {$IFDEF VerboseQtKeys}
  writeln('> TQtWidget.SlotInputMethod ',dbgsname(LCLObject),' event=QEventInputMethod:');
  writeln('   commmitString ',WStr,' len ',length(WStr),' UnicodeChar ',UnicodeChar,
    ' UnicodeLen ',UnicodeOutLen);
  writeln('   sending QEventKeyPress');
  {$ENDIF}

  KeyEvent := QKeyEvent_create(QEventKeyPress, PtrInt(UnicodeChar), QGUIApplication_keyboardModifiers, @WStr, False, 1);
  try
    // do not send it to queue, just pass it to SlotKey
    Result := SlotKey(Sender, KeyEvent);
  finally
    QKeyEvent_destroy(KeyEvent);
  end;
  {$IFDEF VerboseQtKeys}
  writeln('< TQtWidget.SlotInputMethod End: ',dbgsname(LCLObject),' event=QEventInputMethod, sent QEventKeyPress');
  {$ENDIF}
end;

修复方法:
打开lazarus/lcl/interfaces/qt5/qtwidgets.pas
添加3个变量(红色3行):

  TQtWidget = class(TQtObject, IUnknown)
  private
    FDefaultFocusReason: QtFocusReason;
    FInResizeEvent: boolean;
    FWidgetState: TQtWidgetStates;
    FWidgetDefaultFont: TQtFont;
    FWidgetLCLFont: TQtFont;
    FWidgetNeedFontColorInitialization: Boolean;
    FChildOfComplexWidget: TChildOfComplexWidget;
    FOwnWidget: Boolean;
    FProps: TStringList;
    FPaintData: TPaintData;
    FCentralWidget: QWidgetH;
    FContext: HDC;
    FParams: TCreateParams;
    FDefaultCursor: QCursorH;
    FKeysToEat: TByteSet;
    FText: WideString;
    FHasCaret: Boolean;
    FLastCaretPos: TQtPoint;
    FHasPaint: Boolean;
    FOwner: TQtWidget;

    FWidgetColorRole: QPaletteColorRole;
    FTextColorRole: QPaletteColorRole;
    FPalette: TQtWidgetPalette;
    { Input Method }
    FPreEditStr: WideString;
    FCommitStr: WideString;
    FIMPreedit: Boolean;

找到

function TQtWidget.SlotInputMethod(Sender: QObjectH; Event: QEventH): Boolean; cdecl;

复制以下代码替换原有的SlotInputMethod

function TQtWidget.SlotInputMethod(Sender: QObjectH; Event: QEventH): Boolean; cdecl;
var
  InputEvent: QInputMethodEventH;
  WStr, temps: WideString;
  UnicodeChar: Cardinal;
  i: integer;
  KeyEvent: QKeyEventH;
  Msg: TLMessage;
begin
  Result := False;
  if not (QEvent_type(Event) = QEventInputMethod) then Exit;
  {$ifdef VerboseQt}
    DebugLn('TQtWidget.SlotInputMethod ', dbgsname(LCLObject));
  {$endif}
  InputEvent := QInputMethodEventH(Event);
  FPreEditStr:='';
  FCommitStr:='';
  QInputMethodEvent_commitString(InputEvent, @FCommitStr);
  QInputMethodEvent_preeditString(InputEvent, @FPreEditStr);
  WStr:=FCommitStr;
  { commit }
  if FCommitStr<>'' then
  begin
    if CanSendLCLMessage then
    begin
      Msg.Msg:=LM_IM_COMPOSITION;
      Msg.WParam:=GTK_IM_FLAG_COMMIT or GTK_IM_FLAG_END;
      Msg.LParam:=LPARAM(@FCommitStr);
      Result:=DeliverMessage(Msg)<>0;
    end;
    FIMPreedit:=False;
  end;
  { preedit }
  if CanSendLCLMessage then
  begin
    Msg.Msg:=LM_IM_COMPOSITION;
    Msg.WParam:=GTK_IM_FLAG_PREEDIT;
    if not FIMPreedit then
      Msg.WParam:=Msg.WParam or GTK_IM_FLAG_START
      else
        Msg.WParam:=Msg.WParam or GTK_IM_FLAG_REPLACE;
    Msg.LParam:=LPARAM(@FPreEditStr);
    { Don't update result }
    DeliverMessage(Msg);
  end;
  FIMPreedit:=FPreEditStr<>'';
  { commit to keyinput }
  if WStr<>'' then
  begin
    {$IFDEF VerboseQtKeys}
    writeln('> TQtWidget.SlotInputMethod ',dbgsname(LCLObject),' event=QEventInputMethod:');
  writeln('   commmitString ',WStr,' len ',length(WStr),' UnicodeChar ',UnicodeChar)
    writeln('   sending QEventKeyPress');
    {$ENDIF}
    for i:=1 to Length(WStr) do
    begin
      UnicodeChar := PWord(@WStr[i])^;
      temps:=WStr[i];
      KeyEvent := QKeyEvent_create(QEventKeyPress, PtrInt(UnicodeChar), QGUIApplication_keyboardModifiers, @temps);
      try
        // do not send it to queue, just pass it to SlotKey
        Result := SlotKey(Sender, KeyEvent);
      finally
        QKeyEvent_destroy(KeyEvent);
      end;
      {$IFDEF VerboseQtKeys}
      writeln('< TQtWidget.SlotInputMethod End: ',dbgsname(LCLObject),' event=QEventInputMethod, sent QEventKeyPress');
      {$ENDIF}
    end;
  end;
end;

重构lazarus及重新编译应用就可以修复多字词组的输入。

posted on 2026-08-14 20:29  秋·风  阅读(66)  评论(2)    收藏  举报