View Issue Details

IDProjectCategoryView StatusLast Update
0019716LazarusLCLpublic2014-08-13 12:50
ReportergitspielenAssigned ToBart Broersma 
PrioritynormalSeverityminorReproducibilityalways
Status resolvedResolutionfixed 
Product Version0.9.30Product Build 
Target Version1.2.6Fixed in Version 
Summary0019716: TCustomEdit.SelectAll is wrongly implemented
Descriptionin TCustomEdit.SelectAll in customedit.inc

'SetSelLength(UTF8Length(Text));' should be replaced by
'SetSelLength(Length(Text));'

because UTF8Length function returns not the whole length of 'Text' but the count of UTF8 characters.
TagsNo tags attached.
Fixed in Revisionr46041
LazTarget1.2.6
WidgetsetWin32/Win64
Attached Files
  • TEdit.Selection.7z (60,636 bytes)
  • win32.edit.sellength.diff (3,232 bytes)
    Index: lcl/interfaces/win32/win32wsstdctrls.pp
    ===================================================================
    --- lcl/interfaces/win32/win32wsstdctrls.pp	(revision 31484)
    +++ lcl/interfaces/win32/win32wsstdctrls.pp	(working copy)
    @@ -1083,31 +1083,83 @@
     
     function EditGetSelStart(WinHandle: HWND): integer;
     begin
    +  {$ifdef WindowsUnicodeSupport}
    +  if UnicodeEnabledOS then
    +  begin
    +    Windows.SendMessageW(WinHandle, EM_GETSEL, Windows.WPARAM(@Result), 0);
    +  end
    +  else
    +  begin
    +    Windows.SendMessage(WinHandle, EM_GETSEL, Windows.WPARAM(@Result), 0);
    +  end;
    +  {$else}
       Windows.SendMessage(WinHandle, EM_GETSEL, Windows.WPARAM(@Result), 0);
    +  {$endif}
     end;
     
     function EditGetSelLength(WinHandle: HWND): integer;
     var
       startpos, endpos: integer;
     begin
    +  {$ifdef WindowsUnicodeSupport}
    +  if UnicodeEnabledOS then
    +  begin
    +    Windows.SendMessageW(WinHandle, EM_GETSEL, Windows.WPARAM(@startpos), Windows.LPARAM(@endpos));
    +  end
    +  else
    +  begin
    +    Windows.SendMessage(WinHandle, EM_GETSEL, Windows.WPARAM(@startpos), Windows.LPARAM(@endpos));
    +  end;
    +  {$else}
       Windows.SendMessage(WinHandle, EM_GETSEL, Windows.WPARAM(@startpos), Windows.LPARAM(@endpos));
    +  {$endif}
       Result := endpos - startpos;
     end;
     
     procedure EditSetSelStart(WinHandle: HWND; NewStart: integer);
     begin
    +  {$ifdef WindowsUnicodeSupport}
    +  if UnicodeEnabledOS then
    +  begin
    +    Windows.SendMessageW(WinHandle, EM_SETSEL, Windows.WParam(NewStart), Windows.LParam(NewStart));
    +    // scroll caret into view
    +    Windows.SendMessageW(WinHandle, EM_SCROLLCARET, 0, 0);
    +  end
    +  else
    +  begin
    +    Windows.SendMessage(WinHandle, EM_SETSEL, Windows.WParam(NewStart), Windows.LParam(NewStart));
    +    // scroll caret into view
    +    Windows.SendMessage(WinHandle, EM_SCROLLCARET, 0, 0);
    +  end;
    +  {$else}
       Windows.SendMessage(WinHandle, EM_SETSEL, Windows.WParam(NewStart), Windows.LParam(NewStart));
       // scroll caret into view
       Windows.SendMessage(WinHandle, EM_SCROLLCARET, 0, 0);
    +  {$endif}
     end;
     
     procedure EditSetSelLength(WinHandle: HWND; NewLength: integer);
     var
       startpos, endpos: integer;
     begin
    -  Windows.SendMessage(WinHandle, EM_GETSEL, Windows.WParam(@startpos), Windows.LParam(@endpos));
    -  endpos := startpos + NewLength;
    -  Windows.SendMessage(WinHandle, EM_SETSEL, Windows.WParam(startpos), Windows.LParam(endpos));
    +  {$ifdef WindowsUnicodeSupport}
    +   if UnicodeEnabledOS then
    +   begin
    +     Windows.SendMessageW(WinHandle, EM_GETSEL, Windows.WParam(@startpos), Windows.LParam(@endpos));
    +     endpos := startpos + NewLength;
    +     Windows.SendMessageW(WinHandle, EM_SETSEL, Windows.WParam(startpos), Windows.LParam(endpos));
    +   end
    +   else
    +   begin
    +     Windows.SendMessage(WinHandle, EM_GETSEL, Windows.WParam(@startpos), Windows.LParam(@endpos));
    +     endpos := startpos + NewLength;
    +     Windows.SendMessage(WinHandle, EM_SETSEL, Windows.WParam(startpos), Windows.LParam(endpos));
    +   end;
    +   {$else}
    +   Windows.SendMessage(WinHandle, EM_GETSEL, Windows.WParam(@startpos), Windows.LParam(@endpos));
    +   endpos := startpos + NewLength;
    +   Windows.SendMessage(WinHandle, EM_SETSEL, Windows.WParam(startpos), Windows.LParam(endpos));
    +   {$endif}
     end;
     
     { TWin32WSCustomEdit }
    
  • seltest.zip (2,633 bytes)
  • ANSI_and_UTF8.7z (2,186 bytes)
  • edit-sellength.png (8,813 bytes)
    edit-sellength.png (8,813 bytes)

Relationships

related to 0023232 resolvedBart Broersma Wrong position happens when append to a multibyte charset string in TMemo 

Activities

Zeljan Rikalo

2011-07-12 14:59

developer   ~0049903

Why it must be so ? Isn't UTF8Length() length of selected characters (length of selection) ... with pure Qt app selection length = UTF8Length().
Probably win32 problem only.

Bart Broersma

2011-07-13 00:03

developer   ~0049920

Why do you think so: SelLength is the number of visible characters selected in the control.

Tested on Lazarus 0.9.31 r31473M FPC 2.4.4 i386-win32-win32/win64 on WinME

Edit1.Text := 'aäëïöü';
Edit1.setfocus;
Edit1.sellength := 0;
Edit1.selstart := 1;
Edit1.sellength := 4;

This will correctly select the text "äëïö"

Edit1.SelectAll also correctly selects the entire text in the control
(Utf8Length(Edit1.Text) = 6, Length(Edit1.Text) = 11)

gitspielen

2011-07-13 07:33

reporter   ~0049924

Bart, your example worked correctly but not mine with Korean characters.


procedure TForm1.Button1Click(Sender: TObject);
begin
  Edit1.Text := 'aäëïöü';
  Edit1.setfocus;
  Edit1.sellength := 0;
  Edit1.selstart := 1;
  Edit1.sellength := 4; // "äëïö" is selected.
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  Edit1.Text:='가나다라마바';
  // UTF8Length(Edit1.Text) = 6, Length(Edit1.Text) = 18
  Edit1.SetFocus;
  Edit1.SelLength:=0;
  Edit1.SelStart:=1;
  Edit1.SelLength:=4; // expected "나다라마" but "나다"
end;

Bart Broersma

2011-07-13 11:38

developer   ~0049934

Last edited: 2011-07-13 13:57

Strange: UTF8Length() returns correct number of characters.
In any case, using Length() will be wrong too, so that's not the solution.
I cannot test with Korean characters here (also in th example above, in my browser they show up as question marks).

I tested with Arabic characters on WinXP (3-byte codepoints) and it still works OK

Can you attach an example (make sure the source code is UTF-8), so some other devel can test this (I have only Win9x, which has almost no support for MBC languages at all).

Bart Broersma

2011-07-13 12:51

developer   ~0049937

Last edited: 2011-07-13 13:25

Basically the Win32 implementatiof of SetSelLength does this:

Windows.SendMessage(WinHandle, EM_SETSEL, Windows.WParam(startpos), Windows.LParam(endpos));

This is exactly as described by MS in http://msdn.microsoft.com/en-us/library/bb761661(v=vs.85).aspx

@gitspielen:
1. in your example, what is the value of SelLength after you manually select e.g. 4 characters in the control?

2. If you use SendMessageW instead of SendMessage, does it work correctly

In Win32WSStdCtrls.pp

Change EditSetSelLength() to something like this:

procedure EditSetSelLength(WinHandle: HWND; NewLength: integer);
var
  startpos, endpos: integer;
begin
  {$ifdef WindowsUnicodeSupport}
   if UnicodeEnabledOS then
   begin
     Windows.SendMessageW(WinHandle, EM_GETSEL, Windows.WParam(@startpos), Windows.LParam(@endpos));
     endpos := startpos + NewLength;
     Windows.SendMessageW(WinHandle, EM_SETSEL, Windows.WParam(startpos), Windows.LParam(endpos));
   end
   else
   begin
     Windows.SendMessage(WinHandle, EM_GETSEL, Windows.WParam(@startpos), Windows.LParam(@endpos));
     endpos := startpos + NewLength;
     Windows.SendMessage(WinHandle, EM_SETSEL, Windows.WParam(startpos), Windows.LParam(endpos));
   end;
   {$else}
   Windows.SendMessage(WinHandle, EM_GETSEL, Windows.WParam(@startpos), Windows.LParam(@endpos));
   endpos := startpos + NewLength;
   Windows.SendMessage(WinHandle, EM_SETSEL, Windows.WParam(startpos), Windows.LParam(endpos));
   {$endif}
end;

Bart Broersma

2011-07-13 13:00

developer   ~0049939

Shouldn't this issue be moved from Packages to WidgetSet?

gitspielen

2011-07-14 07:25

reporter   ~0049967

Thanks, Bart.
I agree with you that this issue is more involved in WidgetSet but I've got no idea to move it :(

1.
procedure TForm1.Edit1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  Button1.Caption:=IntToStr(Edit1.SelLength);
end; // manually selected 4 characters and the result was 8


2. Great Job, Bart! I applied your revision and it worked perfectly ;) And I think EditGetSelLength also needs to be changed because the above 0000001 example still shows 8 as a result(Korean characters are traditionally implemented by 2-byte codes(EUC-KR) and Windows might use both standards, EUR-KR and UTF-8 for them).

gitspielen

2011-07-14 07:27

reporter   ~0049968

Oops I wrote 'the above sharp(#)-1 example' but the page automatically converted it to a link.

2011-07-14 07:36

 

TEdit.Selection.7z (60,636 bytes)

2011-07-14 13:44

 

win32.edit.sellength.diff (3,232 bytes)
Index: lcl/interfaces/win32/win32wsstdctrls.pp
===================================================================
--- lcl/interfaces/win32/win32wsstdctrls.pp	(revision 31484)
+++ lcl/interfaces/win32/win32wsstdctrls.pp	(working copy)
@@ -1083,31 +1083,83 @@
 
 function EditGetSelStart(WinHandle: HWND): integer;
 begin
+  {$ifdef WindowsUnicodeSupport}
+  if UnicodeEnabledOS then
+  begin
+    Windows.SendMessageW(WinHandle, EM_GETSEL, Windows.WPARAM(@Result), 0);
+  end
+  else
+  begin
+    Windows.SendMessage(WinHandle, EM_GETSEL, Windows.WPARAM(@Result), 0);
+  end;
+  {$else}
   Windows.SendMessage(WinHandle, EM_GETSEL, Windows.WPARAM(@Result), 0);
+  {$endif}
 end;
 
 function EditGetSelLength(WinHandle: HWND): integer;
 var
   startpos, endpos: integer;
 begin
+  {$ifdef WindowsUnicodeSupport}
+  if UnicodeEnabledOS then
+  begin
+    Windows.SendMessageW(WinHandle, EM_GETSEL, Windows.WPARAM(@startpos), Windows.LPARAM(@endpos));
+  end
+  else
+  begin
+    Windows.SendMessage(WinHandle, EM_GETSEL, Windows.WPARAM(@startpos), Windows.LPARAM(@endpos));
+  end;
+  {$else}
   Windows.SendMessage(WinHandle, EM_GETSEL, Windows.WPARAM(@startpos), Windows.LPARAM(@endpos));
+  {$endif}
   Result := endpos - startpos;
 end;
 
 procedure EditSetSelStart(WinHandle: HWND; NewStart: integer);
 begin
+  {$ifdef WindowsUnicodeSupport}
+  if UnicodeEnabledOS then
+  begin
+    Windows.SendMessageW(WinHandle, EM_SETSEL, Windows.WParam(NewStart), Windows.LParam(NewStart));
+    // scroll caret into view
+    Windows.SendMessageW(WinHandle, EM_SCROLLCARET, 0, 0);
+  end
+  else
+  begin
+    Windows.SendMessage(WinHandle, EM_SETSEL, Windows.WParam(NewStart), Windows.LParam(NewStart));
+    // scroll caret into view
+    Windows.SendMessage(WinHandle, EM_SCROLLCARET, 0, 0);
+  end;
+  {$else}
   Windows.SendMessage(WinHandle, EM_SETSEL, Windows.WParam(NewStart), Windows.LParam(NewStart));
   // scroll caret into view
   Windows.SendMessage(WinHandle, EM_SCROLLCARET, 0, 0);
+  {$endif}
 end;
 
 procedure EditSetSelLength(WinHandle: HWND; NewLength: integer);
 var
   startpos, endpos: integer;
 begin
-  Windows.SendMessage(WinHandle, EM_GETSEL, Windows.WParam(@startpos), Windows.LParam(@endpos));
-  endpos := startpos + NewLength;
-  Windows.SendMessage(WinHandle, EM_SETSEL, Windows.WParam(startpos), Windows.LParam(endpos));
+  {$ifdef WindowsUnicodeSupport}
+   if UnicodeEnabledOS then
+   begin
+     Windows.SendMessageW(WinHandle, EM_GETSEL, Windows.WParam(@startpos), Windows.LParam(@endpos));
+     endpos := startpos + NewLength;
+     Windows.SendMessageW(WinHandle, EM_SETSEL, Windows.WParam(startpos), Windows.LParam(endpos));
+   end
+   else
+   begin
+     Windows.SendMessage(WinHandle, EM_GETSEL, Windows.WParam(@startpos), Windows.LParam(@endpos));
+     endpos := startpos + NewLength;
+     Windows.SendMessage(WinHandle, EM_SETSEL, Windows.WParam(startpos), Windows.LParam(endpos));
+   end;
+   {$else}
+   Windows.SendMessage(WinHandle, EM_GETSEL, Windows.WParam(@startpos), Windows.LParam(@endpos));
+   endpos := startpos + NewLength;
+   Windows.SendMessage(WinHandle, EM_SETSEL, Windows.WParam(startpos), Windows.LParam(endpos));
+   {$endif}
 end;
 
 { TWin32WSCustomEdit }

2011-07-14 13:45

 

seltest.zip (2,633 bytes)

Bart Broersma

2011-07-14 13:48

developer   ~0049977

I attached a possible fix (win32.edit.sellength.diff) and a testprogram I used to test it (seltest.zip).
I tested it on WinMe and Win7 and it seems to work correctly.

@Gitspielen: can you test the patch with EUC-KR characters and report back?

gitspielen

2011-07-15 03:39

reporter   ~0049997

Lazarus doesn't support EUC-KR(CP949 to be exact and that's a kind of ANSI codepages).

I don't know how to put those characters directly from a keyboard to an Edit control of Lazarus. Because Windows internally implements all characters by UTF-16LE. Only the interface layer distinguishes it. All that Lazarus accepts is UTF-8 characters. Therefore every input from standard I/O automatically converted into UTF-8.

I could test them with text file I/O.

And I found that something is wrong with SelStart on UTF-8 texts. It should be zero-based but acts like one-based.
Hopeless, but look at the attachment.

2011-07-15 03:40

 

ANSI_and_UTF8.7z (2,186 bytes)

Bart Broersma

2011-07-16 20:17

developer   ~0050027

Myabe Paul Ishenin has some insight, he seems to have more knowledge of win32 widgetset than I have.

gitspielen

2011-07-17 17:16

reporter   ~0050033

I really appreciate your help anyway, Bart!

Bart Broersma

2013-07-25 22:29

developer  

edit-sellength.png (8,813 bytes)
edit-sellength.png (8,813 bytes)

Bart Broersma

2013-07-25 22:33

developer   ~0069114

@gitspielen. See attached edit-sellength.png screenshot.
It is the result of executing the code in note 0049924, and it looks OK to me (I cannot read what it says).
Lazarus 1.1 r41901 FPC 2.6.2 (32-bit) on Win7 (64-bit).

gitspielen

2013-07-28 09:54

reporter   ~0069131

Last edited: 2013-07-28 09:55

View 2 revisions

I'm in the mandatory military service now so I can't test it in person but it seems to work perfectly on the screenshot.

Bart Broersma

2013-07-28 15:18

developer   ~0069136

The screenshot is taken without any patches...

Bart Broersma

2014-08-13 12:16

developer   ~0076590

Please test and close if OK.

Issue History

Date Modified Username Field Change
2011-07-12 02:40 gitspielen New Issue
2011-07-12 02:40 gitspielen Status new => assigned
2011-07-12 02:40 gitspielen Assigned To => Felipe Monteiro de Carvalho
2011-07-12 02:40 gitspielen Widgetset => Win32/Win64
2011-07-12 14:59 Zeljan Rikalo Note Added: 0049903
2011-07-13 00:03 Bart Broersma Note Added: 0049920
2011-07-13 07:33 gitspielen Note Added: 0049924
2011-07-13 11:38 Bart Broersma Note Added: 0049934
2011-07-13 12:51 Bart Broersma Note Added: 0049937
2011-07-13 13:00 Bart Broersma Note Added: 0049939
2011-07-13 13:25 Bart Broersma Note Edited: 0049937
2011-07-13 13:57 Bart Broersma Note Edited: 0049934
2011-07-14 07:25 gitspielen Note Added: 0049967
2011-07-14 07:27 gitspielen Note Added: 0049968
2011-07-14 07:36 gitspielen File Added: TEdit.Selection.7z
2011-07-14 13:44 Bart Broersma File Added: win32.edit.sellength.diff
2011-07-14 13:45 Bart Broersma File Added: seltest.zip
2011-07-14 13:48 Bart Broersma Note Added: 0049977
2011-07-15 03:39 gitspielen Note Added: 0049997
2011-07-15 03:40 gitspielen File Added: ANSI_and_UTF8.7z
2011-07-16 20:17 Bart Broersma Note Added: 0050027
2011-07-17 17:16 gitspielen Note Added: 0050033
2012-11-23 23:35 Bart Broersma Relationship added related to 0023232
2013-07-25 22:19 Bart Broersma LazTarget => -
2013-07-25 22:19 Bart Broersma Category Custom Drawn => LCL
2013-07-25 22:19 Bart Broersma Project Packages => Lazarus
2013-07-25 22:29 Bart Broersma File Added: edit-sellength.png
2013-07-25 22:33 Bart Broersma Note Added: 0069114
2013-07-25 22:33 Bart Broersma Status assigned => feedback
2013-07-27 23:03 Bart Broersma Assigned To Felipe Monteiro de Carvalho => Bart Broersma
2013-07-27 23:03 Bart Broersma Status feedback => assigned
2013-07-27 23:03 Bart Broersma Status assigned => feedback
2013-07-28 09:54 gitspielen Note Added: 0069131
2013-07-28 09:54 gitspielen Status feedback => assigned
2013-07-28 09:55 gitspielen Note Edited: 0069131 View Revisions
2013-07-28 15:18 Bart Broersma Note Added: 0069136
2013-09-18 16:23 Bart Broersma LazTarget - => 1.4
2013-09-18 16:23 Bart Broersma Target Version => 1.4
2014-08-13 12:16 Bart Broersma Fixed in Revision => r46041
2014-08-13 12:16 Bart Broersma LazTarget 1.4 => 1.2.6
2014-08-13 12:16 Bart Broersma Note Added: 0076590
2014-08-13 12:16 Bart Broersma Status assigned => resolved
2014-08-13 12:16 Bart Broersma Resolution open => fixed
2014-08-13 12:16 Bart Broersma Target Version 1.4 => 1.2.6