~ubuntu-branches/ubuntu/saucy/lazarus/saucy

« back to all changes in this revision

Viewing changes to components/synedit/lazsynimm.pas

  • Committer: Package Import Robot
  • Author(s): Paul Gevers, Abou Al Montacir, Bart Martens, Paul Gevers
  • Date: 2013-06-08 14:12:17 UTC
  • mfrom: (1.1.9)
  • Revision ID: package-import@ubuntu.com-20130608141217-7k0cy9id8ifcnutc
Tags: 1.0.8+dfsg-1
[ Abou Al Montacir ]
* New upstream major release and multiple maintenace release offering many
  fixes and new features marking a new milestone for the Lazarus development
  and its stability level.
  - The detailed list of changes can be found here:
    http://wiki.lazarus.freepascal.org/Lazarus_1.0_release_notes
    http://wiki.lazarus.freepascal.org/Lazarus_1.0_fixes_branch
* LCL changes:
  - LCL is now a normal package.
      + Platform independent parts of the LCL are now in the package LCLBase
      + LCL is automatically recompiled when switching the target platform,
        unless pre-compiled binaries for this target are already installed.
      + No impact on existing projects.
      + Linker options needed by LCL are no more added to projects that do
        not use the LCL package.
  - Minor changes in LCL basic classes behaviour
      + TCustomForm.Create raises an exception if a form resource is not
        found.
      + TNotebook and TPage: a new implementation of these classes was added.
      + TDBNavigator: It is now possible to have focusable buttons by setting
        Options = [navFocusableButtons] and TabStop = True, useful for
        accessibility and for devices with neither mouse nor touch screen.
      + Names of TControlBorderSpacing.GetSideSpace and GetSpace were swapped
        and are now consistent. GetSideSpace = Around + GetSpace.
      + TForm.WindowState=wsFullscreen was added
      + TCanvas.TextFitInfo was added to calculate how many characters will
        fit into a specified Width. Useful for word-wrapping calculations.
      + TControl.GetColorResolvingParent and
        TControl.GetRGBColorResolvingParent were added, simplifying the work
        to obtain the final color of the control while resolving clDefault
        and the ParentColor.
      + LCLIntf.GetTextExtentExPoint now has a good default implementation
        which works in any platform not providing a specific implementation.
        However, Widgetset specific implementation is better, when available.
      + TTabControl was reorganized. Now it has the correct class hierarchy
        and inherits from TCustomTabControl as it should.
  - New unit in the LCL:
      + lazdialogs.pas: adds non-native versions of various native dialogs,
        for example TLazOpenDialog, TLazSaveDialog, TLazSelectDirectoryDialog.
        It is used by widgetsets which either do not have a native dialog, or
        do not wish to use it because it is limited. These dialogs can also be
        used by user applications directly.
      + lazdeviceapis.pas: offers an interface to more hardware devices such
        as the accelerometer, GPS, etc. See LazDeviceAPIs
      + lazcanvas.pas: provides a TFPImageCanvas descendent implementing
        drawing in a LCL-compatible way, but 100% in Pascal.
      + lazregions.pas. LazRegions is a wholly Pascal implementation of
        regions for canvas clipping, event clipping, finding in which control
        of a region tree one an event should reach, for drawing polygons, etc.
      + customdrawncontrols.pas, customdrawndrawers.pas,
        customdrawn_common.pas, customdrawn_android.pas and
        customdrawn_winxp.pas: are the Lazarus Custom Drawn Controls -controls
        which imitate the standard LCL ones, but with the difference that they
        are non-native and support skinning.
  - New APIs added to the LCL to improve support of accessibility software
    such as screen readers.
* IDE changes:
  - Many improvments.
  - The detailed list of changes can be found here:
    http://wiki.lazarus.freepascal.org/New_IDE_features_since#v1.0_.282012-08-29.29
    http://wiki.lazarus.freepascal.org/Lazarus_1.0_release_notes#IDE_Changes
* Debugger / Editor changes:
  - Added pascal sources and breakpoints to the disassembler
  - Added threads dialog.
* Components changes:
  - TAChart: many fixes and new features
  - CodeTool: support Delphi style generics and new syntax extensions.
  - AggPas: removed to honor free licencing. (Closes: Bug#708695)
[Bart Martens]
* New debian/watch file fixing issues with upstream RC release.
[Abou Al Montacir]
* Avoid changing files in .pc hidden directory, these are used by quilt for
  internal purpose and could lead to surprises during build.
[Paul Gevers]
* Updated get-orig-source target and it compinion script orig-tar.sh so that they
  repack the source file, allowing bug 708695 to be fixed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
unit LazSynIMM;
 
2
 
 
3
{$mode objfpc}{$H+}
 
4
 
 
5
{off $DEFINE WinIMEDebug}
 
6
 
 
7
interface
 
8
 
 
9
uses
 
10
  windows, imm, Classes, SysUtils, LazLoggerBase, LCLType, LCLProc, Controls,
 
11
  Graphics, SynEditMiscClasses, SynTextDrawer, SynEditPointClasses, SynEditMarkupSelection,
 
12
  SynEditMarkup, SynEditTypes, SynEditKeyCmds, LazSynEditText;
 
13
 
 
14
type
 
15
 
 
16
  { LazSynIme }
 
17
 
 
18
  LazSynIme = class(TSynEditFriend)
 
19
  private
 
20
    FInvalidateLinesMethod: TInvalidateLines;
 
21
  protected
 
22
    FInCompose: Boolean;
 
23
    procedure InvalidateLines(FirstLine, LastLine: integer);
 
24
    procedure StopIme(Success: Boolean);
 
25
  public
 
26
    constructor Create(AOwner: TSynEditBase); reintroduce;
 
27
    procedure WMImeRequest(var Msg: TMessage); virtual;
 
28
    procedure WMImeNotify(var Msg: TMessage); virtual;
 
29
    procedure WMImeComposition(var Msg: TMessage); virtual;
 
30
    procedure WMImeStartComposition(var Msg: TMessage); virtual;
 
31
    procedure WMImeEndComposition(var Msg: TMessage); virtual;
 
32
    procedure FocusKilled; virtual;
 
33
    property InvalidateLinesMethod : TInvalidateLines write FInvalidateLinesMethod;
 
34
  end;
 
35
 
 
36
  { LazSynImeSimple }
 
37
 
 
38
  LazSynImeSimple = class(LazSynIme)
 
39
  private
 
40
    FImeBlockSelection: TSynEditSelection;
 
41
    FImeWinX, FImeWinY: Integer;
 
42
    FTextDrawer: TheTextDrawer;
 
43
    procedure SetTextDrawer(AValue: TheTextDrawer);
 
44
    procedure UpdateImeWinXY(aX, aY: Integer; aImc: HIMC = 0; aForce: Boolean = False);
 
45
    procedure UpdateImeWinFont(aImc: HIMC = 0);
 
46
    procedure DoStatusChanged(Sender: TObject; Changes: TSynStatusChanges);
 
47
    procedure DoDrawerFontChanged(Sender: TObject);
 
48
    procedure DoOnCommand(Sender: TObject; AfterProcessing: boolean; var Handled: boolean;
 
49
      var Command: TSynEditorCommand; var AChar: TUTF8Char; Data: pointer;
 
50
      HandlerData: pointer);
 
51
    procedure DoOnMouse(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X,
 
52
      Y: Integer);
 
53
  public
 
54
    constructor Create(AOwner: TSynEditBase);
 
55
    destructor Destroy; override;
 
56
    procedure WMImeNotify(var Msg: TMessage); override;
 
57
    procedure WMImeComposition(var Msg: TMessage); override;
 
58
    procedure WMImeStartComposition(var Msg: TMessage); override;
 
59
    procedure WMImeEndComposition(var Msg: TMessage); override;
 
60
    procedure FocusKilled; override;
 
61
    property TextDrawer: TheTextDrawer read FTextDrawer write SetTextDrawer;
 
62
  end;
 
63
 
 
64
  { LazSynImeFull }
 
65
 
 
66
  LazSynImeFull = class(LazSynIme)
 
67
  private
 
68
    FImeBlockSelection, FImeBlockSelection2: TSynEditSelection;
 
69
    FImeMarkupSelection, FImeMarkupSelection2: TSynEditMarkupSelection;
 
70
    FInImeMsg: Boolean;
 
71
    procedure SetImeTempText(const s: string);
 
72
    procedure DoOnCommand(Sender: TObject; AfterProcessing: boolean; var Handled: boolean;
 
73
      var Command: TSynEditorCommand; var AChar: TUTF8Char; Data: pointer;
 
74
      HandlerData: pointer);
 
75
    procedure DoOnMouse(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X,
 
76
      Y: Integer);
 
77
    procedure DoStatusChanged(Sender: TObject; Changes: TSynStatusChanges);
 
78
  public
 
79
    constructor Create(AOwner: TSynEditBase);
 
80
    destructor Destroy; override;
 
81
    procedure WMImeRequest(var Msg: TMessage); override;
 
82
    procedure WMImeNotify(var Msg: TMessage); override;
 
83
    procedure WMImeComposition(var Msg: TMessage); override;
 
84
    procedure WMImeStartComposition(var Msg: TMessage); override;
 
85
    procedure WMImeEndComposition(var Msg: TMessage); override;
 
86
    procedure FocusKilled; override;
 
87
  end;
 
88
 
 
89
implementation
 
90
uses SynEdit;
 
91
 
 
92
{ LazSynIme }
 
93
 
 
94
procedure LazSynIme.InvalidateLines(FirstLine, LastLine: integer);
 
95
begin
 
96
  FInvalidateLinesMethod(FirstLine, LastLine);
 
97
end;
 
98
 
 
99
procedure LazSynIme.StopIme(Success: Boolean);
 
100
var
 
101
  imc: HIMC;
 
102
begin
 
103
  if (not FInCompose) or (not FriendEdit.HandleAllocated) then exit;
 
104
 
 
105
  imc := ImmGetContext(FriendEdit.Handle);
 
106
  if (imc <> 0) then begin
 
107
    if Success then
 
108
      ImmNotifyIME(imc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0)
 
109
    else
 
110
      ImmNotifyIME(imc, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
 
111
    ImmReleaseContext(FriendEdit.Handle, imc);
 
112
  end;
 
113
end;
 
114
 
 
115
constructor LazSynIme.Create(AOwner: TSynEditBase);
 
116
begin
 
117
  FriendEdit := AOwner;
 
118
end;
 
119
 
 
120
procedure LazSynIme.WMImeRequest(var Msg: TMessage);
 
121
begin
 
122
end;
 
123
 
 
124
procedure LazSynIme.WMImeComposition(var Msg: TMessage);
 
125
begin
 
126
end;
 
127
 
 
128
procedure LazSynIme.WMImeNotify(var Msg: TMessage);
 
129
begin
 
130
end;
 
131
 
 
132
procedure LazSynIme.WMImeStartComposition(var Msg: TMessage);
 
133
begin
 
134
end;
 
135
 
 
136
procedure LazSynIme.WMImeEndComposition(var Msg: TMessage);
 
137
begin
 
138
end;
 
139
 
 
140
procedure LazSynIme.FocusKilled;
 
141
begin
 
142
end;
 
143
 
 
144
{ LazSynImeSimple }
 
145
 
 
146
procedure LazSynImeSimple.DoStatusChanged(Sender: TObject; Changes: TSynStatusChanges);
 
147
begin
 
148
  UpdateImeWinXY(TCustomSynEdit(FriendEdit).CaretXPix, TCustomSynEdit(FriendEdit).CaretYPix);
 
149
  if Changes * [scCaretX, scCaretY] <> [] then
 
150
    StopIme(False);
 
151
end;
 
152
 
 
153
procedure LazSynImeSimple.DoDrawerFontChanged(Sender: TObject);
 
154
var
 
155
  imc: HIMC;
 
156
begin
 
157
  if not FriendEdit.HandleAllocated then
 
158
    exit;
 
159
  imc := ImmGetContext(FriendEdit.Handle);
 
160
  if (imc <> 0) then begin
 
161
    UpdateImeWinFont(imc);
 
162
    UpdateImeWinXY(TCustomSynEdit(FriendEdit).CaretXPix, TCustomSynEdit(FriendEdit).CaretYPix, imc);
 
163
    ImmReleaseContext(FriendEdit.Handle, imc);
 
164
  end;
 
165
end;
 
166
 
 
167
procedure LazSynImeSimple.DoOnCommand(Sender: TObject; AfterProcessing: boolean;
 
168
  var Handled: boolean; var Command: TSynEditorCommand; var AChar: TUTF8Char; Data: pointer;
 
169
  HandlerData: pointer);
 
170
begin
 
171
  StopIme(True);
 
172
end;
 
173
 
 
174
procedure LazSynImeSimple.DoOnMouse(Sender: TObject; Button: TMouseButton; Shift: TShiftState;
 
175
  X, Y: Integer);
 
176
begin
 
177
  StopIme(True);
 
178
end;
 
179
 
 
180
procedure LazSynImeSimple.UpdateImeWinXY(aX, aY: Integer; aImc: HIMC; aForce: Boolean);
 
181
var
 
182
  cf: CompositionForm;
 
183
  imc: HIMC;
 
184
begin
 
185
  if not FriendEdit.HandleAllocated then exit;
 
186
  if (not aForce) and (aX = FImeWinX) and (aY = FImeWinY) then exit;
 
187
  FImeWinX := aX;
 
188
  FImeWinY := aY;
 
189
 
 
190
  cf.dwStyle := CFS_POINT;
 
191
  cf.ptCurrentPos := Point(aX, aY);
 
192
  if aImc = 0 then
 
193
    imc := ImmGetContext(FriendEdit.Handle)
 
194
  else
 
195
    imc := aImc;
 
196
  if (imc <> 0) then begin
 
197
    ImmSetCompositionWindow(imc, @cf);
 
198
    if (aImc = 0) then
 
199
      ImmReleaseContext(FriendEdit.Handle, imc);
 
200
  end;
 
201
end;
 
202
 
 
203
procedure LazSynImeSimple.SEtTextDrawer(AValue: TheTextDrawer);
 
204
begin
 
205
  if FTextDrawer = AValue then Exit;
 
206
  if FTextDrawer <> nil then
 
207
    FTextDrawer.UnRegisterOnFontChangeHandler(@DoDrawerFontChanged);
 
208
  FTextDrawer := AValue;
 
209
  if FTextDrawer <> nil then
 
210
    FTextDrawer.RegisterOnFontChangeHandler(@DoDrawerFontChanged);
 
211
end;
 
212
 
 
213
procedure LazSynImeSimple.UpdateImeWinFont(aImc: HIMC);
 
214
var
 
215
  imc: HIMC;
 
216
  logFont: TLogFont;
 
217
begin
 
218
  if not FriendEdit.HandleAllocated then exit;
 
219
  if aImc = 0 then
 
220
    imc := ImmGetContext(FriendEdit.Handle)
 
221
  else
 
222
    imc := aImc;
 
223
  if (imc <> 0) then begin
 
224
    GetObject(FriendEdit.Font.Handle, SizeOf(TLogFont), @logFont);
 
225
    ImmSetCompositionFontA(imc, @logFont);
 
226
    if (aImc = 0) then
 
227
      ImmReleaseContext(FriendEdit.Handle, imc);
 
228
  end;
 
229
end;
 
230
 
 
231
constructor LazSynImeSimple.Create(AOwner: TSynEditBase);
 
232
begin
 
233
  inherited Create(AOwner);
 
234
  FImeBlockSelection := TSynEditSelection.Create(ViewedTextBuffer, False);
 
235
  FImeBlockSelection.InvalidateLinesMethod := {$IFDEF FPC}@{$ENDIF}InvalidateLines;
 
236
 
 
237
  TCustomSynEdit(FriendEdit).RegisterStatusChangedHandler(@DoStatusChanged, [scCaretX, scCaretY, scLeftChar, scTopLine, scModified]);
 
238
  TCustomSynEdit(FriendEdit).RegisterCommandHandler(@DoOnCommand, nil, [hcfInit]);
 
239
  TCustomSynEdit(FriendEdit).RegisterBeforeMouseDownHandler(@DoOnMouse);
 
240
end;
 
241
 
 
242
destructor LazSynImeSimple.Destroy;
 
243
begin
 
244
  TextDrawer := nil;
 
245
  FreeAndNil(FImeBlockSelection);
 
246
  TCustomSynEdit(FriendEdit).UnregisterBeforeMouseDownHandler(@DoOnMouse);
 
247
  TCustomSynEdit(FriendEdit).UnregisterCommandHandler(@DoOnCommand);
 
248
  TCustomSynEdit(FriendEdit).UnRegisterStatusChangedHandler(@DoStatusChanged);
 
249
  inherited Destroy;
 
250
end;
 
251
 
 
252
procedure LazSynImeSimple.WMImeNotify(var Msg: TMessage);
 
253
var
 
254
  imc: HIMC;
 
255
{$IFDEF WinIMEDebug}
 
256
  s: String;
 
257
{$ENDIF}
 
258
begin
 
259
  {$IFDEF WinIMEDebug}
 
260
  case msg.wParam of
 
261
    IMN_CLOSESTATUSWINDOW: s:= 'IMN_CLOSESTATUSWINDOW, ';
 
262
    IMN_OPENSTATUSWINDOW: s:= 'IMN_OPENSTATUSWINDOW, ';
 
263
    IMN_CHANGECANDIDATE: s:= 'IMN_CHANGECANDIDATE, ';
 
264
    IMN_CLOSECANDIDATE: s:= 'IMN_CLOSECANDIDATE, ';
 
265
    IMN_OPENCANDIDATE: s:= 'IMN_OPENCANDIDATE, ';
 
266
    IMN_SETCONVERSIONMODE: s:= 'IMN_SETCONVERSIONMODE, ';
 
267
    IMN_SETSENTENCEMODE: s:= 'IMN_SETSENTENCEMODE, ';
 
268
    IMN_SETOPENSTATUS: s:= 'IMN_SETOPENSTATUS, ';
 
269
    IMN_SETCANDIDATEPOS: s:= 'IMN_SETCANDIDATEPOS, ';
 
270
    IMN_SETCOMPOSITIONFONT: s:= 'IMN_SETCOMPOSITIONFONT, ';
 
271
    IMN_SETCOMPOSITIONWINDOW: s:= 'IMN_SETCOMPOSITIONWINDOW, ';
 
272
    IMN_SETSTATUSWINDOWPOS: s:= 'IMN_SETSTATUSWINDOWPOS, ';
 
273
    IMN_GUIDELINE: s:= 'IMN_GUIDELINE, ';
 
274
    IMN_PRIVATE: s:= 'IMN_PRIVATE, ';
 
275
  end;
 
276
  debugln(['TCustomSynEdit.WMImeNotify ',s,' ', dbgHex(Msg.lParam), ' ,  ', dbgHex(Msg.wParam)]);
 
277
  {$ENDIF}
 
278
 
 
279
  case Msg.WParam of
 
280
    IMN_SETOPENSTATUS: begin
 
281
      imc := ImmGetContext(FriendEdit.Handle);
 
282
      if (imc <> 0) then begin
 
283
        UpdateImeWinFont(imc);
 
284
        UpdateImeWinXY(TCustomSynEdit(FriendEdit).CaretXPix, TCustomSynEdit(FriendEdit).CaretYPix, imc, True);
 
285
        ImmReleaseContext(FriendEdit.Handle, imc);
 
286
      end;
 
287
    end;
 
288
    IMN_CLOSESTATUSWINDOW:
 
289
      StopIme(True);
 
290
  end;
 
291
end;
 
292
 
 
293
procedure LazSynImeSimple.WMImeComposition(var Msg: TMessage);
 
294
var
 
295
  imc: HIMC;
 
296
  ImeCount: LongWord;
 
297
  p: PChar;
 
298
begin
 
299
  if ((Msg.LParam and GCS_RESULTSTR) <> 0) then begin
 
300
    imc := ImmGetContext(FriendEdit.Handle);
 
301
    try
 
302
      if imc <> 0 then begin
 
303
        ImeCount := ImmGetCompositionStringW(imc, GCS_RESULTSTR, nil, 0);
 
304
        {$IFDEF WinIMEDebug}
 
305
        DebugLn(['--- GCS_RESULTSTR  ', dbgHex(ImeCount)]);
 
306
        {$ENDIF}
 
307
        if ImeCount > 0 then begin
 
308
          GetMem(p, ImeCount + 2);
 
309
          try
 
310
            TCustomSynEdit(FriendEdit).BeginUpdate;
 
311
            ImmGetCompositionStringW(imc, GCS_RESULTSTR, p, ImeCount + 2);
 
312
            p[ImeCount] := #0;
 
313
            p[ImeCount+1] := #0;
 
314
            FImeBlockSelection.SelText := UTF16ToUTF8(PWCHAR(p));
 
315
            FImeBlockSelection.StartLineBytePos := FImeBlockSelection.EndLineBytePos;
 
316
            CaretObj.LineBytePos := FImeBlockSelection.StartLineBytePos;
 
317
            Msg.Result := 1;
 
318
          finally
 
319
            FreeMem(p, ImeCount + 2);
 
320
            TCustomSynEdit(FriendEdit).EndUpdate;
 
321
          end;
 
322
        end;
 
323
      end;
 
324
    finally
 
325
      ImmReleaseContext(FriendEdit.Handle, imc);
 
326
    end;
 
327
  end;
 
328
 
 
329
 
 
330
end;
 
331
 
 
332
procedure LazSynImeSimple.WMImeStartComposition(var Msg: TMessage);
 
333
var
 
334
  imc: HIMC;
 
335
begin
 
336
  //debugln(['TCustomSynEdit.WMImeStartComposition ']);
 
337
  imc := ImmGetContext(FriendEdit.Handle);
 
338
  if (imc <> 0) then begin
 
339
    UpdateImeWinFont(imc);
 
340
    UpdateImeWinXY(TCustomSynEdit(FriendEdit).CaretXPix, TCustomSynEdit(FriendEdit).CaretYPix, imc, True);
 
341
    ImmReleaseContext(FriendEdit.Handle, imc);
 
342
  end;
 
343
  FInCompose := True;
 
344
  FImeBlockSelection.StartLineBytePos := CaretObj.LineBytePos;
 
345
end;
 
346
 
 
347
procedure LazSynImeSimple.WMImeEndComposition(var Msg: TMessage);
 
348
begin
 
349
  FInCompose := False;
 
350
end;
 
351
 
 
352
procedure LazSynImeSimple.FocusKilled;
 
353
begin
 
354
  StopIme(True);
 
355
end;
 
356
 
 
357
{ LazSynImeFull }
 
358
 
 
359
procedure LazSynImeFull.DoOnCommand(Sender: TObject; AfterProcessing: boolean;
 
360
  var Handled: boolean; var Command: TSynEditorCommand; var AChar: TUTF8Char; Data: pointer;
 
361
  HandlerData: pointer);
 
362
begin
 
363
  StopIme(True);
 
364
end;
 
365
 
 
366
procedure LazSynImeFull.DoOnMouse(Sender: TObject; Button: TMouseButton; Shift: TShiftState;
 
367
  X, Y: Integer);
 
368
begin
 
369
  StopIme(True);
 
370
end;
 
371
 
 
372
procedure LazSynImeFull.DoStatusChanged(Sender: TObject; Changes: TSynStatusChanges);
 
373
begin
 
374
  if FInImeMsg then exit;
 
375
  StopIme(True);
 
376
end;
 
377
 
 
378
procedure LazSynImeFull.SetImeTempText(const s: string);
 
379
var
 
380
  p1, p2: TPoint;
 
381
  f: Boolean;
 
382
begin
 
383
  p1 := FImeBlockSelection.FirstLineBytePos;
 
384
 
 
385
  f := FInImeMsg;
 
386
  FInImeMsg := True;
 
387
  ViewedTextBuffer.UndoList.Lock;
 
388
  ViewedTextBuffer.RedoList.Lock;
 
389
  FImeBlockSelection.SelText := s;
 
390
  ViewedTextBuffer.UndoList.Unlock;
 
391
  ViewedTextBuffer.RedoList.Unlock;
 
392
  FInImeMsg := f;
 
393
 
 
394
  p2 := FImeBlockSelection.FirstLineBytePos;
 
395
  FImeBlockSelection.StartLineBytePos := p1;
 
396
  FImeBlockSelection.EndLineBytePos := p2;
 
397
end;
 
398
 
 
399
constructor LazSynImeFull.Create(AOwner: TSynEditBase);
 
400
begin
 
401
  inherited Create(AOwner);
 
402
 
 
403
  FImeBlockSelection := TSynEditSelection.Create(ViewedTextBuffer, False);
 
404
  FImeBlockSelection.InvalidateLinesMethod := {$IFDEF FPC}@{$ENDIF}InvalidateLines;
 
405
  FImeBlockSelection2 := TSynEditSelection.Create(ViewedTextBuffer, False);
 
406
  FImeBlockSelection2.InvalidateLinesMethod := {$IFDEF FPC}@{$ENDIF}InvalidateLines;
 
407
 
 
408
  FImeMarkupSelection  := TSynEditMarkupSelection.Create(FriendEdit, FImeBlockSelection);
 
409
  FImeMarkupSelection2 := TSynEditMarkupSelection.Create(FriendEdit, FImeBlockSelection2);
 
410
 
 
411
  TSynEditMarkupManager(MarkupMgr).AddMarkUp(FImeMarkupSelection);
 
412
  TSynEditMarkupManager(MarkupMgr).AddMarkUp(FImeMarkupSelection2);
 
413
 
 
414
  FImeMarkupSelection.MarkupInfo.Clear;
 
415
  FImeMarkupSelection.MarkupInfo.FramePriority := 999;
 
416
  FImeMarkupSelection.MarkupInfo.FrameColor := clDefault;
 
417
  FImeMarkupSelection.MarkupInfo.FrameStyle := slsDotted;
 
418
  FImeMarkupSelection.MarkupInfo.FrameEdges := sfeAround;
 
419
 
 
420
  FImeMarkupSelection2.MarkupInfo.Clear;
 
421
  FImeMarkupSelection2.MarkupInfo.FramePriority := 999+1;
 
422
  FImeMarkupSelection2.MarkupInfo.FrameColor := clDefault;
 
423
  FImeMarkupSelection2.MarkupInfo.FrameStyle := slsSolid;
 
424
  FImeMarkupSelection2.MarkupInfo.FrameEdges := sfeBottom;
 
425
 
 
426
  TCustomSynEdit(FriendEdit).RegisterStatusChangedHandler(@DoStatusChanged, [scCaretX, scCaretY, scModified]);
 
427
  TCustomSynEdit(FriendEdit).RegisterCommandHandler(@DoOnCommand, nil, [hcfInit]);
 
428
  TCustomSynEdit(FriendEdit).RegisterBeforeMouseDownHandler(@DoOnMouse);
 
429
 
 
430
end;
 
431
 
 
432
destructor LazSynImeFull.Destroy;
 
433
begin
 
434
  TCustomSynEdit(FriendEdit).UnregisterBeforeMouseDownHandler(@DoOnMouse);
 
435
  TCustomSynEdit(FriendEdit).UnregisterCommandHandler(@DoOnCommand);
 
436
  TCustomSynEdit(FriendEdit).UnRegisterStatusChangedHandler(@DoStatusChanged);
 
437
 
 
438
  FreeAndNil(FImeBlockSelection);
 
439
  FreeAndNil(FImeBlockSelection2);
 
440
  inherited Destroy;
 
441
end;
 
442
 
 
443
procedure LazSynImeFull.WMImeRequest(var Msg: TMessage);
 
444
var
 
445
  {$IFDEF WinIMEDebug}
 
446
  s: String;
 
447
  {$ENDIF}
 
448
  cp: PIMECHARPOSITION;
 
449
  p1: TPoint;
 
450
  CWidth: TPhysicalCharWidths;
 
451
  i, x: integer;
 
452
begin
 
453
  {$IFDEF WinIMEDebug}
 
454
  case msg.wParam of
 
455
    IMR_COMPOSITIONWINDOW: s:= 'IMR_COMPOSITIONWINDOW, ';
 
456
    IMR_CANDIDATEWINDOW: s:= 'IMR_CANDIDATEWINDOW, ';
 
457
    IMR_COMPOSITIONFONT: s:= 'IMR_COMPOSITIONFONT, ';
 
458
    IMR_RECONVERTSTRING: s:= 'IMR_RECONVERTSTRING, ';
 
459
    IMR_CONFIRMRECONVERTSTRING: s:= 'IMR_CONFIRMRECONVERTSTRING, ';
 
460
    IMR_DOCUMENTFEED: s:= 'IMR_DOCUMENTFEED, ';
 
461
  end;
 
462
  if s <> '' then debugln(['TCustomSynEdit.WMImeRequest ', s,' ' , dbgHex(Msg.lParam)]);
 
463
  {$ENDIF}
 
464
 
 
465
  case msg.wParam of
 
466
    IMR_QUERYCHARPOSITION: begin
 
467
        cp := PIMECHARPOSITION(Msg.lParam);
 
468
        p1 := FImeBlockSelection.StartLineBytePos;
 
469
 
 
470
        CWidth := ViewedTextBuffer.GetPhysicalCharWidths(FImeBlockSelection.StartLinePos - 1);
 
471
        x := p1.x - 1;
 
472
        i := cp^.dwCharPos;
 
473
        while (i > 0) and (x < length(CWidth)) do begin
 
474
          inc(x);
 
475
          while (x < length(CWidth)) and (CWidth[x] = 0) do
 
476
            inc(x);
 
477
          dec(i);
 
478
        end;
 
479
        p1.x := x + i + 1;
 
480
        p1 := FriendEdit.ClientToScreen(TCustomSynEdit(FriendEdit).RowColumnToPixels(ViewedTextBuffer.LogicalToPhysicalPos(p1)));
 
481
 
 
482
        cp^.pt.y := p1.y;
 
483
        cp^.pt.x :=  p1.x;
 
484
        cp^.cLineHeight := TCustomSynEdit(FriendEdit).LineHeight;
 
485
        cp^.rcDocument.TopLeft := FriendEdit.ClientToScreen(FriendEdit.ClientRect.TopLeft);
 
486
        cp^.rcDocument.BottomRight := FriendEdit.ClientToScreen(FriendEdit.ClientRect.BottomRight);
 
487
        {$IFDEF WinIMEDebug}
 
488
        debugln(['--- TCustomSynEdit.WMImeRequest ** IMR_QUERYCHARPOSITION ', dbgs(cp^.dwCharPos), '  ', dbgs(x),'   ', dbgs(p1.x)]);
 
489
        {$ENDIF}
 
490
        Msg.Result := 1;
 
491
      end;
 
492
  end;
 
493
end;
 
494
 
 
495
procedure LazSynImeFull.WMImeNotify(var Msg: TMessage);
 
496
{$IFDEF WinIMEDebug}
 
497
var
 
498
  s: String;
 
499
{$ENDIF}
 
500
begin
 
501
  {$IFDEF WinIMEDebug}
 
502
  case msg.wParam of
 
503
    IMN_CLOSESTATUSWINDOW: s:= 'IMN_CLOSESTATUSWINDOW, ';
 
504
    IMN_OPENSTATUSWINDOW: s:= 'IMN_OPENSTATUSWINDOW, ';
 
505
    IMN_CHANGECANDIDATE: s:= 'IMN_CHANGECANDIDATE, ';
 
506
    IMN_CLOSECANDIDATE: s:= 'IMN_CLOSECANDIDATE, ';
 
507
    IMN_OPENCANDIDATE: s:= 'IMN_OPENCANDIDATE, ';
 
508
    IMN_SETCONVERSIONMODE: s:= 'IMN_SETCONVERSIONMODE, ';
 
509
    IMN_SETSENTENCEMODE: s:= 'IMN_SETSENTENCEMODE, ';
 
510
    IMN_SETOPENSTATUS: s:= 'IMN_SETOPENSTATUS, ';
 
511
    IMN_SETCANDIDATEPOS: s:= 'IMN_SETCANDIDATEPOS, ';
 
512
    IMN_SETCOMPOSITIONFONT: s:= 'IMN_SETCOMPOSITIONFONT, ';
 
513
    IMN_SETCOMPOSITIONWINDOW: s:= 'IMN_SETCOMPOSITIONWINDOW, ';
 
514
    IMN_SETSTATUSWINDOWPOS: s:= 'IMN_SETSTATUSWINDOWPOS, ';
 
515
    IMN_GUIDELINE: s:= 'IMN_GUIDELINE, ';
 
516
    IMN_PRIVATE: s:= 'IMN_PRIVATE, ';
 
517
  end;
 
518
  debugln(['TCustomSynEdit.WMImeNotify ',s,' ', dbgHex(Msg.lParam), ' ,  ', dbgHex(Msg.wParam)]);
 
519
  {$ENDIF}
 
520
end;
 
521
 
 
522
procedure LazSynImeFull.WMImeComposition(var Msg: TMessage);
 
523
var
 
524
  CWidth: TPhysicalCharWidths;
 
525
 
 
526
  function CharToByte(AStart, AChars: integer): integer;
 
527
  begin
 
528
    if length(CWidth) = 0 then
 
529
      CWidth := ViewedTextBuffer.GetPhysicalCharWidths(FImeBlockSelection.StartLinePos - 1);
 
530
    dec(AStart);
 
531
    Result := AStart;
 
532
    while (AChars > 0) and (Result < length(CWidth)) do begin
 
533
      inc(Result);
 
534
      while (Result < length(CWidth)) and (CWidth[Result] = 0) do
 
535
        inc(Result);
 
536
      dec(AChars);
 
537
    end;
 
538
    Result := Result - AStart + AChars;
 
539
  end;
 
540
var
 
541
  {$IFDEF WinIMEDebug}
 
542
  s: String;
 
543
  {$ENDIF}
 
544
  imc: HIMC;
 
545
  p: PChar;
 
546
  ImeCount: LongWord;
 
547
  x, i: Integer;
 
548
  xy: TPoint;
 
549
begin
 
550
  {$IFDEF WinIMEDebug}
 
551
  s := '';
 
552
  if (Msg.lparam and GCS_COMPREADSTR)<>0 then s := s + 'GCS_COMPREADSTR, ';
 
553
  if (Msg.lparam and GCS_COMPREADATTR)<>0 then s := s + 'GCS_COMPREADATTR, ';
 
554
  if (Msg.lparam and GCS_COMPREADCLAUSE)<>0 then s := s + 'GCS_COMPREADCLAUSE, ';
 
555
  //if (Msg.lparam and GCS_COMPSTR)<>0 then s := s + 'GCS_COMPSTR, ';
 
556
  if (Msg.lparam and GCS_COMPATTR)<>0 then s := s + 'GCS_COMPATTR, ';
 
557
  if (Msg.lparam and GCS_COMPCLAUSE)<>0 then s := s + 'GCS_COMPCLAUSE, ';
 
558
  //if (Msg.lparam and GCS_CURSORPOS)<>0 then s := s + 'GCS_CURSORPOS, ';
 
559
  //if (Msg.lparam and GCS_DELTASTART)<>0 then s := s + 'GCS_DELTASTART, ';
 
560
  if (Msg.lparam and GCS_RESULTREADSTR)<>0 then s := s + 'GCS_RESULTREADSTR, ';
 
561
  if (Msg.lparam and GCS_RESULTREADCLAUSE)<>0 then s := s + 'GCS_RESULTREADCLAUSE, ';
 
562
  //if (Msg.lparam and GCS_RESULTSTR)<>0 then s := s + 'GCS_RESULTSTR, ';
 
563
  if (Msg.lparam and GCS_RESULTCLAUSE)<>0 then s := s + 'GCS_RESULTCLAUSE, ';
 
564
  if (Msg.lparam and CS_INSERTCHAR)<>0 then s := s + ' ** CS_INSERTCHAR, ';
 
565
  if (Msg.lparam and CS_NOMOVECARET)<>0 then s := s + ' ** CS_NOMOVECARET, ';
 
566
  if s <> '' then debugln(['TCustomSynEdit.WMImeComposition ', s]);
 
567
  {$ENDIF}
 
568
 
 
569
  if ((Msg.LParam and (GCS_RESULTSTR or GCS_COMPSTR or GCS_CURSORPOS or GCS_COMPATTR)) = 0) then
 
570
    exit;
 
571
 
 
572
  imc := 0;
 
573
  FInImeMsg := True;
 
574
  SetLength(CWidth, 0);
 
575
  try
 
576
 
 
577
    if ((Msg.LParam and GCS_RESULTSTR) <> 0) then begin
 
578
      if imc = 0 then
 
579
        imc := ImmGetContext(FriendEdit.Handle);
 
580
      ImeCount := ImmGetCompositionStringW(imc, GCS_RESULTSTR, nil, 0);
 
581
      {$IFDEF WinIMEDebug}
 
582
      DebugLn(['--- GCS_RESULTSTR  ', dbgHex(ImeCount)]);
 
583
      {$ENDIF}
 
584
      if ImeCount > 0 then begin
 
585
        GetMem(p, ImeCount + 2);
 
586
        try
 
587
          CaretObj.LineBytePos := FImeBlockSelection.StartLineBytePos;
 
588
          TCustomSynEdit(FriendEdit).BeginUpdate;
 
589
          ImmGetCompositionStringW(imc, GCS_RESULTSTR, p, ImeCount + 2);
 
590
          p[ImeCount] := #0;
 
591
          p[ImeCount+1] := #0;
 
592
          SetImeTempText('');
 
593
          FImeBlockSelection.SelText := UTF16ToUTF8(PWCHAR(p));
 
594
          FImeBlockSelection.StartLineBytePos := FImeBlockSelection.EndLineBytePos;
 
595
          CaretObj.LineBytePos := FImeBlockSelection.StartLineBytePos;
 
596
          Msg.Result := 1;
 
597
        finally
 
598
          TCustomSynEdit(FriendEdit).EndUpdate;
 
599
          FreeMem(p, ImeCount + 2);
 
600
        end;
 
601
      end;
 
602
    end;
 
603
 
 
604
    if ((Msg.LParam and GCS_COMPSTR) <> 0) then begin
 
605
      if imc = 0 then
 
606
        imc := ImmGetContext(FriendEdit.Handle);
 
607
      ImeCount := ImmGetCompositionStringW(imc, GCS_COMPSTR, nil, 0);
 
608
      {$IFDEF WinIMEDebug}
 
609
      DebugLn(['--- GCS_COMPSTR  ', dbgHex(ImeCount)]);
 
610
      {$ENDIF}
 
611
      if ImeCount > 0 then begin
 
612
        GetMem(p, ImeCount + 2);
 
613
        try
 
614
          ImmGetCompositionStringW(imc, GCS_COMPSTR, p, ImeCount + 2);
 
615
          p[ImeCount] := #0;
 
616
          p[ImeCount+1] := #0;
 
617
          SetImeTempText(UTF16ToUTF8(PWCHAR(p)));
 
618
          Msg.Result := 1;
 
619
        finally
 
620
          FreeMem(p, ImeCount + 2);
 
621
        end;
 
622
      end;
 
623
    end;
 
624
 
 
625
    if ((Msg.LParam and GCS_COMPATTR) <> 0) then begin
 
626
      if imc = 0 then
 
627
        imc := ImmGetContext(FriendEdit.Handle);
 
628
      ImeCount := ImmGetCompositionStringW(imc, GCS_COMPATTR, nil, 0);
 
629
      {$IFDEF WinIMEDebug}
 
630
      DebugLn(['***** GCS_COMPATTR  ', dbgHex(ImeCount)]);
 
631
      {$ENDIF}
 
632
      if ImeCount > 0 then begin
 
633
        xy := FImeBlockSelection.StartLineBytePos;
 
634
        FImeBlockSelection2.StartLineBytePos := xy;
 
635
        FImeBlockSelection2.EndLineBytePos := xy;
 
636
        GetMem(p, ImeCount + 2);
 
637
        try
 
638
          ImmGetCompositionStringW(imc, GCS_COMPATTR, p, ImeCount + 2);
 
639
          //DebugLn(dbgMemRange(PByte( p), ImeCount));
 
640
          i := 0;
 
641
          while i < ImeCount do begin
 
642
            if ord(p[i]) = ATTR_TARGET_CONVERTED then begin
 
643
              x := FImeBlockSelection.StartBytePos;
 
644
              xy.x := x + CharToByte(x, i);
 
645
              FImeBlockSelection2.StartLineBytePos := xy;
 
646
              inc(i);
 
647
              while i < ImeCount do begin
 
648
                if (ord(p[i]) <> ATTR_TARGET_CONVERTED) or (i = ImeCount-1) then begin
 
649
                  if (ord(p[i]) = ATTR_TARGET_CONVERTED) then
 
650
                    inc(i);
 
651
                  xy.x := x + CharToByte(x, i);
 
652
                  FImeBlockSelection2.EndLineBytePos := xy;
 
653
                  break;
 
654
                end;
 
655
                inc(i);
 
656
              end;
 
657
              break;
 
658
            end;
 
659
            inc(i);
 
660
          end;
 
661
 
 
662
          Msg.Result := 1;
 
663
        finally
 
664
          FreeMem(p, ImeCount + 2);
 
665
        end;
 
666
      end;
 
667
    end;
 
668
 
 
669
    if ((Msg.LParam and GCS_CURSORPOS) <> 0) then begin
 
670
      if imc = 0 then
 
671
        imc := ImmGetContext(FriendEdit.Handle);
 
672
 
 
673
      ImeCount := ImmGetCompositionStringW(imc, GCS_CURSORPOS, nil, 0);
 
674
      {$IFDEF WinIMEDebug}
 
675
      DebugLn(['--- GCS_CURSORPOS ', dbgs(ImeCount)]);
 
676
      {$ENDIF}
 
677
      if ImeCount >= 0 then begin
 
678
        ImeCount := ImeCount and $ffff;
 
679
        x := FImeBlockSelection.StartBytePos;
 
680
        x := x + CharToByte(x, ImeCount);
 
681
        CaretObj.CharPos := ViewedTextBuffer.LogicalToPhysicalPos(Point(x, FImeBlockSelection.StartLinePos)).x;
 
682
      end;
 
683
    end;
 
684
 
 
685
  finally
 
686
    if imc <> 0 then
 
687
      ImmReleaseContext(FriendEdit.Handle, imc);
 
688
    FInImeMsg := False;
 
689
  end;
 
690
  inherited;
 
691
end;
 
692
 
 
693
procedure LazSynImeFull.WMImeStartComposition(var Msg: TMessage);
 
694
begin
 
695
  //debugln(['TCustomSynEdit.WMImeStartComposition ']);
 
696
  FImeBlockSelection.StartLineBytePos := CaretObj.LineBytePos;
 
697
  FInCompose := True;
 
698
  Msg.Result := 1;
 
699
end;
 
700
 
 
701
procedure LazSynImeFull.WMImeEndComposition(var Msg: TMessage);
 
702
begin
 
703
  //debugln(['TCustomSynEdit.WMImeEndComposition ']);
 
704
  SetImeTempText('');
 
705
  CaretObj.LineBytePos := FImeBlockSelection.LastLineBytePos;
 
706
  FImeBlockSelection.StartLineBytePos := CaretObj.LineBytePos;
 
707
  FImeBlockSelection2.StartLineBytePos := CaretObj.LineBytePos;
 
708
  FInCompose := False;
 
709
  Msg.Result := 1;
 
710
end;
 
711
 
 
712
procedure LazSynImeFull.FocusKilled;
 
713
begin
 
714
  StopIme(True);
 
715
end;
 
716
 
 
717
end.
 
718