View Issue Details

IDProjectCategoryView StatusLast Update
0033330PackagesLCLpublic2020-04-19 00:28
ReporterToru Takubo Assigned ToMichl  
PrioritynormalSeverityminorReproducibilityalways
Status closedResolutionfixed 
PlatformWindowsOSWinXP SP3 32bit / Win7 SP1 64bit 
Product Version1.8.2 
Target Version1.10 
Summary0033330: Mouse events do not fire properly when MultiSelect = True on TListView of win32/64
DescriptionThe behavior for mouse events of TListView are different when MultiSelect=True or False.

*** In case of MultiSelect=False ***

[On Left Click]
1. OnMouseDown
2. OnClick
3. OnMouseUp

[On Right Click]
1. OnMouseDown
2. OnMouseUp

[On Left Double Click]
1. OnMouseDown
2. OnClick
3. OnMouseUp
4. OnMouseDown
5. OnDoubleClick
6. OnMouseUp

[On Right Double Click]
1. OnMouseDown
2. OnMouseUp
3. OnMouseDown
4. OnMouseUp

*** In case of MultiSelect=True ***

[On Left Click]
1. OnMouseDown

[On Right Click]
1. OnMouseDown

[On Left Double Click]
1. OnMouseDown
2. OnDoubleClick
3. OnClick
4. OnMouseUp

[On Right Double Click]
1. OnMouseDown
3. OnMouseDown
4. OnMouseUp

As you see, some events are missing when MultiSelect is True. Furthermore, the order of OnClick and OnDoubleClick is reversed. Only OnMouseDown seems to work correctly.
Steps To ReproduceSet TListView.Multiselect property to TRUE.
Additional InformationThis problem occurs on Win32/Win64. Not observed on Linux platform.
TagsNo tags attached.
Fixed in Revision57906
LazTarget-
WidgetsetWin32/Win64
Attached Files

Relationships

related to 0027189 closedJuha Manninen Lazarus TListView OnMouseUp called twice 
related to 0033735 closedMichl Lazarus Double click on entry in call stack window opens popup 
related to 0033746 closedMichl Lazarus ListView PopupMenu shown twice 
related to 0033811 resolvedMartin Friebe Lazarus Listview: DragMode dmAutomatic does not function with Multiselect enabled 
related to 0035362 resolvedMartin Friebe Lazarus ListView with MultiSelect incorrectly deselects items on MouseDown 

Activities

Toru Takubo

2018-03-07 01:52

reporter  

Sample_ListView.zip (130,076 bytes)

Toru Takubo

2018-03-07 01:57

reporter   ~0106963

I prepared a sample project to demonstrate this issue. Click or Double Click on the ListView pain, and see what events are fired. Compare cases of MultiSelect is True or False.

Serge Anvarov

2018-03-07 07:41

reporter   ~0106965

Last edited: 2018-03-07 07:47

View 2 revisions

If you look at win32wscustomlistview.inc on the ListViewParentMsgHandler procedure, you will see that this non-standard behavior of Windows is already being processed (processing NM_CLICK, NM_RCLICK), adding the necessary events. But only if the ListView has selected elements.

Serge Anvarov

2018-03-07 09:03

reporter   ~0106967

Patch added

Serge Anvarov

2018-03-07 09:04

reporter  

listview.diff (2,765 bytes)   
Index: lcl/interfaces/win32/win32wscustomlistview.inc
===================================================================
--- lcl/interfaces/win32/win32wscustomlistview.inc	(revision 57460)
+++ lcl/interfaces/win32/win32wscustomlistview.inc	(working copy)
@@ -223,8 +223,28 @@
     Result := Assigned(ListItem);
   end;
 
-var
-  Pos: TSmallPoint;
+  procedure HandleListViewNMClick(LeftButton: Boolean; PInfo: PNMItemActivate);
+  const
+    CMsg: array [Boolean] of UINT = (LM_RBUTTONUP, LM_LBUTTONUP);
+    CMouseFlags: array [Boolean] of Windows.WParam = (MK_RBUTTON, MK_LBUTTON);
+  var
+    MouseFlags: Windows.WParam;
+  begin
+    // A listview doesn't get a WM_LBUTTONUP, WM_RBUTTONUP message,
+    // because it keeps the message in its own event loop,
+    // see msdn article about "Default List-View Message Processing"
+    // therefore we take this notification and create a
+    // LM_LBUTTONUP, LM_RBUTTONUP message out of it
+    MouseFlags := CMouseFlags[LeftButton];
+    if (LVKF_CONTROL and PInfo^.uKeyFlags) <> 0 then
+      MouseFlags := MouseFlags or MK_CONTROL;
+    if (LVKF_SHIFT and PInfo^.uKeyFlags) <> 0 then
+      MouseFlags := MouseFlags or MK_SHIFT;
+    // to make correct event sequence in LCL we should postpone this message
+    // since we are here after call of CallDefaultWindowProc
+    PostMessage(PInfo^.hdr.hwndFrom, CMsg[LeftButton], MouseFlags, MakeLParam(PInfo^.ptAction.x, PInfo^.ptAction.y));
+  end;
+
 begin
   Result := False;
   case Msg of
@@ -232,22 +252,10 @@
     begin
       case PNMHdr(LParam)^.code of
         NM_CLICK, NM_RCLICK:
-          if OwnMouseUpNeeded(TCustomListViewAccess(AWinControl)) then
+          if TCustomListViewAccess(AWinControl).MultiSelect then
           begin
-            // A listview doesn't get a WM_LBUTTONUP, WM_RBUTTONUP message,
-            // because it keeps the message in its own event loop,
-            // see msdn article about "Default List-View Message Processing"
-            // therefore we take this notification and create a
-            // LM_LBUTTONUP, LM_RBUTTONUP message out of it
             WinProcess := False;
-            if PNMHdr(LParam)^.code = NM_CLICK then
-              Msg := LM_LBUTTONUP
-            else
-              Msg := LM_RBUTTONUP;
-            Pos := GetClientCursorPos(PNMHdr(LParam)^.hwndFrom);
-            // to make correct event sequence in LCL we should postpone this message
-            // since we are here after call of CallDefaultWindowProc
-            PostMessage(PNMHdr(LParam)^.hwndFrom, Msg, 0, MakeLParam(Pos.x, Pos.y));
+            HandleListViewNMClick(PNMHdr(LParam)^.code = NM_CLICK, Pointer(LParam));
             Result := True;
           end;
         LVN_GETDISPINFOA, LVN_GETDISPINFOW:
listview.diff (2,765 bytes)   

Toru Takubo

2018-03-08 03:47

reporter   ~0106978

I applied your patch and sample app. come to work fine. Thank you, Serge.

Toru Takubo

2018-03-14 01:32

reporter  

Sample_ListView2.zip (129,436 bytes)

Toru Takubo

2018-03-14 01:33

reporter   ~0107094

I uploaded a modified sample, which has some ListItems on the ListView. I found that OnClick and OnMouseUp do not fire when I click on the ListItems (under MultiSelect=False). I also tested the same sample on Linux, and there is no difference between clicking on the ListItems or out of the ListItems. So I suppose maybe some modification is needed on Serge's patch. I will investigate a little more.

Toru Takubo

2018-03-16 09:26

reporter  

listview2.diff (2,875 bytes)   
Index: lcl/interfaces/win32/win32wscustomlistview.inc
===================================================================
--- lcl/interfaces/win32/win32wscustomlistview.inc	(revision 57460)
+++ lcl/interfaces/win32/win32wscustomlistview.inc	(working copy)
@@ -223,8 +223,28 @@
     Result := Assigned(ListItem);
   end;
 
-var
-  Pos: TSmallPoint;
+  procedure HandleListViewNMClick(LeftButton: Boolean; PInfo: PNMItemActivate);
+  const
+    CMsg: array [Boolean] of UINT = (LM_RBUTTONUP, LM_LBUTTONUP);
+    CMouseFlags: array [Boolean] of Windows.WParam = (MK_RBUTTON, MK_LBUTTON);
+  var
+    MouseFlags: Windows.WParam;
+  begin
+    // A listview doesn't get a WM_LBUTTONUP, WM_RBUTTONUP message,
+    // because it keeps the message in its own event loop,
+    // see msdn article about "Default List-View Message Processing"
+    // therefore we take this notification and create a
+    // LM_LBUTTONUP, LM_RBUTTONUP message out of it
+    MouseFlags := CMouseFlags[LeftButton];
+    if (LVKF_CONTROL and PInfo^.uKeyFlags) <> 0 then
+      MouseFlags := MouseFlags or MK_CONTROL;
+    if (LVKF_SHIFT and PInfo^.uKeyFlags) <> 0 then
+      MouseFlags := MouseFlags or MK_SHIFT;
+    // to make correct event sequence in LCL we should postpone this message
+    // since we are here after call of CallDefaultWindowProc
+    PostMessage(PInfo^.hdr.hwndFrom, CMsg[LeftButton], MouseFlags, MakeLParam(PInfo^.ptAction.x, PInfo^.ptAction.y));
+  end;
+
 begin
   Result := False;
   case Msg of
@@ -232,22 +252,10 @@
     begin
       case PNMHdr(LParam)^.code of
         NM_CLICK, NM_RCLICK:
-          if OwnMouseUpNeeded(TCustomListViewAccess(AWinControl)) then
+          if OwnMouseUpNeeded(TCustomListViewAccess(AWinControl)) or TCustomListViewAccess(AWinControl).MultiSelect then
           begin
-            // A listview doesn't get a WM_LBUTTONUP, WM_RBUTTONUP message,
-            // because it keeps the message in its own event loop,
-            // see msdn article about "Default List-View Message Processing"
-            // therefore we take this notification and create a
-            // LM_LBUTTONUP, LM_RBUTTONUP message out of it
             WinProcess := False;
-            if PNMHdr(LParam)^.code = NM_CLICK then
-              Msg := LM_LBUTTONUP
-            else
-              Msg := LM_RBUTTONUP;
-            Pos := GetClientCursorPos(PNMHdr(LParam)^.hwndFrom);
-            // to make correct event sequence in LCL we should postpone this message
-            // since we are here after call of CallDefaultWindowProc
-            PostMessage(PNMHdr(LParam)^.hwndFrom, Msg, 0, MakeLParam(Pos.x, Pos.y));
+            HandleListViewNMClick(PNMHdr(LParam)^.code = NM_CLICK, Pointer(LParam));
             Result := True;
           end;
         LVN_GETDISPINFOA, LVN_GETDISPINFOW:
listview2.diff (2,875 bytes)   

Toru Takubo

2018-03-16 09:32

reporter   ~0107149

Finally, I found that merging original procedure and Serge's modification result in the solution. I uploaded the patch, listview2.diff. It seems to work fine.

Michl

2018-05-12 22:27

developer  

test.zip (2,378 bytes)

Michl

2018-05-12 22:33

developer   ~0108262

The current workaround (and also the patch) was on a wrong place. Sometimes it doesn't work, e.g. if the listview wasn't focused before.

Fixed in trunk revision 57906. Please test and close if ok.

Toru Takubo

2018-05-16 06:01

reporter   ~0108327

The test project works fine under the trunk revision 57906, so I close this issue. Thank you.

Martin Friebe

2020-04-19 00:28

manager   ~0122236

@Takubo The Listview mouse event handling code has been reworked (again) for more fixes.

Please test again with revision 63012.

See note 0035362:0122233 on issue 0035362

Issue History

Date Modified Username Field Change
2018-03-06 03:35 Toru Takubo New Issue
2018-03-07 01:52 Toru Takubo File Added: Sample_ListView.zip
2018-03-07 01:57 Toru Takubo Note Added: 0106963
2018-03-07 07:41 Serge Anvarov Note Added: 0106965
2018-03-07 07:47 Serge Anvarov Note Edited: 0106965 View Revisions
2018-03-07 09:03 Serge Anvarov Note Added: 0106967
2018-03-07 09:04 Serge Anvarov File Added: listview.diff
2018-03-08 03:47 Toru Takubo Note Added: 0106978
2018-03-11 11:31 Michl Assigned To => Michl
2018-03-11 11:31 Michl Status new => assigned
2018-03-11 12:18 Michl Relationship added related to 0027189
2018-03-14 01:32 Toru Takubo File Added: Sample_ListView2.zip
2018-03-14 01:33 Toru Takubo Note Added: 0107094
2018-03-16 09:26 Toru Takubo File Added: listview2.diff
2018-03-16 09:32 Toru Takubo Note Added: 0107149
2018-05-12 22:27 Michl File Added: test.zip
2018-05-12 22:33 Michl Fixed in Revision => 57906
2018-05-12 22:33 Michl LazTarget => -
2018-05-12 22:33 Michl Note Added: 0108262
2018-05-12 22:33 Michl Status assigned => resolved
2018-05-12 22:33 Michl Resolution open => fixed
2018-05-12 22:33 Michl Target Version => 1.10
2018-05-15 15:36 Michl Relationship added related to 0033735
2018-05-16 06:01 Toru Takubo Note Added: 0108327
2018-05-16 06:01 Toru Takubo Status resolved => closed
2018-05-16 17:47 Ondrej Pokorny Relationship added related to 0033746
2018-05-31 20:19 Michl Relationship added related to 0033811
2019-04-12 10:10 Juha Manninen Relationship added related to 0035362
2020-04-19 00:28 Martin Friebe Note Added: 0122236