What I tried to do was write an Excel SelectionChange handler such that when the user selects a single cell with the mouse I can (a) know that it was the mouse and not the keyboard and (b) find out where in the cell the mouse click occurred. (I would exclude situations in which the user selected more than one cell).
Suppose there were several lines of text in a cell. The idea is to do something different depending on which part of the cell was clicked. (And it doesn't work for my purposes to have multiple cells.)
[Update: I decided that (b) was hopeless and dropped that. But I still wanted to know when a selection changed because of a left mouse click.]
Thanks for any ideas.
EDIT: I found the following resources that led me to a solution that seems to work. I'm also including code for my solution.
Sources:
EngJon noted a problem with their solution because it picked up mouse clicks originating elsewhere. For example, after clicking on the ribbon, using an arrow key to change the selection will still show the left-click in the selection change handler.
I played with this a while and decided (though I could be wrong) that GetAsyncKeyState()
returns True or False for the most recent mouse click and the most recent keypress. The way it handles combination key presses like SHIFT-TAB is to return True for both the shift and tab keys. [Treating 0 as False and all nonzero values as True.]
(You'll note that the keycode constants have no value for combinations like back tab, which is SHIFT-TAB. Similarly, I'll bet, though I didn't test it, that you find combinations like SHIFT-RIGHTCLICK by testing GetAsyncKeyState(vbKeyShift) AND GetAsyncKeyState(vbKeyRButton)
.)
So, in a module (e.g., Module1), I put ...
Option Explicit
#If VBA7 Then
'declare virtual key event listener
Public Declare PtrSafe Function GetAsyncKeyState Lib "user32" _
(ByVal vKey As Long) As Integer
#Else
'declare virtual key event listener
Public Declare Function GetAsyncKeyState Lib "user32" _
(ByVal vKey As Long) As Integer
#End If
In the code for the sheet where I wanted to trap keystrokes and mouse clicks, I put ...
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
'Check whether the left mouse key was recently pressed.
Select Case True
Case GetAsyncKeyState(vbKeyUp) Or GetAsyncKeyState(vbKeyRight) _
Or GetAsyncKeyState(vbKeyDown) Or GetAsyncKeyState(vbKeyLeft) _
Or GetAsyncKeyState(vbKeyTab) Or GetAsyncKeyState(vbKeyLeft) _
Or GetAsyncKeyState(vbKeyHome) Or GetAsyncKeyState(vbKeyReturn)
'One of the cell selection keys was pressed, so do nothing.
' For some reason, PageUp, PageDown, and End don't seem
' to be needed here.
Case GetAsyncKeyState(vbKeyLButton)
'Left mouse key was pressed
<your code here>
End Select
End Sub
You might ask why the first Case statement is there. As EngJon stated, "If you do something that finishes with a click (e.g. a MsgBox), the next selection change with arrow keys will also fire the event and re-execute your stuff." I found that checking for the keystrokes before checking for the mouse click gets rid of this problem.
For me, so far, this has worked flawlessly to pick up solo left-clicks on a cell that I detect in the <your code here>
section.