From: Rich007 on
D'oh! DO EVENTS!!!!!!
If I include Do Events after the Call MySendKeys line it works.

Thanks for your time Karl. You and the other experts on here are great!

Cheers
Rich

"Rich007" wrote:

> Thanks so much Karl,
> I can now get the code to run using either Call MySendKeys("{ENTER}") or
> Call MySendKeys("{~}").
>
> However, I have noticed a very strange situation. Let me give you the
> background (but if you are short of time, just jump to the very end of this
> post).
>
> I have a macro called "OnReturn" which is bound to the return key, i.e. it
> runs everytime the return key is pressed. It is assigned in design time via
> a macro called "AssignReturnKey", using the code"
> KeyBindings.Add KeyCode:=BuildKeyCode(wdKeyReturn), KeyCategory:= _
> wdKeyCategoryMacro, Command:="OnReturn"
>
> All of these macros live in a global addin.
>
> Now the OnReturn macro needs to do some stuff, then perform the return
> keystroke as if the return key had never been assigned to a macro at all. To
> do this, I came up with the following code for OnReturn:
>
> Sub OnReturn()
> 'DO OTHER STUFF HERE...
> UnAssignReturnKey
> Call MySendKeys("{ENTER}", True)
> AssignReturnKey
> End Sub
>
> The logic is this; first unassign the return key via a macro that runs the
> line:
> KeyBindings.Key(KeyCode:=BuildKeyCode(wdKeyReturn)).Clear
> to unassign the return key binding.
>
> Second, this is where I need to perform the unadulterated Return key-stroke.
>
> Third, I reassign the key-binding using the AssignReturnKey macro that was
> run during design time.
>
> Both AssignReturnKey and UnassignReturnKey macros have code to catch errors
> which is why I haven't included the full code for now.
>
> So I have tried using various different methods for calling the "pure"
> return key-stroke ( Selection.TypeParagraph or SendKeys "~", True )
> and these worked ok, but I was looking for a bullet-proof way that would work
> for all international key-boards and language settings.
>
> Now when I use your MySendKeys("{ENTER}") the code jumps into a loop. It
> hangs until I either click the mouse or press a keyboard button. If I hit
> one of the extended keys, the Enter "executes" in combination with that
> extended key. So the code hangs, until say I hit Ctrl, then I get a
> pagebreak!
>
> What I think is happening here is that when I hit Enter, the OnReturn macro
> fires, this calls the UnAssignReturnKey macro to clear the keybinding, then
> the MySendKeys("{ENTER}") is called which effectively re-hits the return key
> and this then tries to run the OnReturn macro! This is my theory, I have no
> way to prove it yet, but the MySendKeys("{ENTER}") shouldn't call OnReturn,
> since the key was unbound in the previous line of code. Could there be some
> kind of lag? The strangest thing is that if you replace the line:
> Call MySendKeys("{ENTER}", True)
> in OnReturn, with just:
> SendKeys "~", True
> (so using the original SendKeys rather than the API version) it works
> perfectly!
>
> Any ideas why the MySendKeys macro doesn't recognise that the return key has
> just been unbound? Thanks again (especially if you've read this far!).
>
> Cheers
> Rich
> PS. Having re-read that I can see this could be quite confusing, so here is
> the full code that I think is runable (if you have the MSendInput.bas
> imported from your site):
>
> Sub AssignReturnKey()
> 'Assigns a macro to intercept the Return key
> '
> Dim AddinPath As String
>
> AddinPath = AddIns("test.dot").Path
> CustomizationContext = Templates(AddinPath & "\test.dot")
> KeyBindings.Add KeyCode:=BuildKeyCode(wdKeyReturn), KeyCategory:= _
> wdKeyCategoryMacro, Command:="OnReturn"
> End Sub
>
> Sub UnAssignReturnKey()
> 'Clears any assignment to the Return key
> '
> Dim lngCode As Long
> Dim kbLoop As KeyBinding
> Dim KeyInUSe As Boolean
> Dim AddinPath As String
>
> AddinPath = AddIns("test.dot").Path
> CustomizationContext = Templates(AddinPath & "\test.dot")
>
> lngCode = BuildKeyCode(wdKeyReturn)
> For Each kbLoop In KeyBindings
> If lngCode = kbLoop.KeyCode Then
> KeyInUSe = True
> End If
> Next kbLoop
>
> If KeyInUSe = True Then
> KeyBindings.Key(KeyCode:=BuildKeyCode(wdKeyReturn)).Clear
> Else
> MsgBox "The Return key was not bound!"
> End If
> End Sub
>
> Sub OnReturn()
> UnAssignReturnKey
> MsgBox "Hello" 'Will show repeatedly - Ctrl+Break to exit
> Call MySendKeys("{ENTER}", True)
> AssignReturnKey
> End Sub
>
>
> PPS. What setting should I have for the Const VBA = True/False line? I had
> to set it to True to get it to run (otherwise there are undeclared varibales).
>
> PPPS. OK, had a thought an I think I have some more evidence to bring to the
> table (please bear with me!). On your website, you say "My routine accepts,
> but ignores, [the wait] parameter". Well that would explain it. If my
> OnReturn code continues to run, the return key is reassigned before the API
> code has done it's stuff, so by the time the API code performs the return
> key-stroke, the key has been reassigned and the OnReturn code runs again!
> Did you ever figure out how to make your code WAIT before continuing?
From: Karl E. Peterson on
Rich007 wrote:
> D'oh! DO EVENTS!!!!!!
> If I include Do Events after the Call MySendKeys line it works.

:-)

> Thanks for your time Karl. You and the other experts on here are great!

I'm glad you got going, but wanted to comment on a couple of your other points...

>> PPS. What setting should I have for the Const VBA = True/False line? I had
>> to set it to True to get it to run (otherwise there are undeclared varibales).

Set it to True if you're running in VBA, False if you're using VB5/6.

>> PPPS. OK, had a thought an I think I have some more evidence to bring to the
>> table (please bear with me!). On your website, you say "My routine accepts,
>> but ignores, [the wait] parameter". Well that would explain it. If my
>> OnReturn code continues to run, the return key is reassigned before the API
>> code has done it's stuff, so by the time the API code performs the return
>> key-stroke, the key has been reassigned and the OnReturn code runs again!
>> Did you ever figure out how to make your code WAIT before continuing?

Sounds like what you're saying is the OnReturn routine is re-entering itself?
That's a natural hazard in an event-based programming model, when you're twidding
the user-interface with code. You can avoid that problem "very simply" by setting a
static flag within the routine, to prevent re-entrancy...

Sub PotentiallyReentrant()
Static Busy As Boolean
If Not Busy Then
Busy = True
' Do the work that potentially triggers a re-entry.
Busy = False
End If
End Sub

Make sense?
--
..NET: It's About Trust!
http://vfred.mvps.org