Capturing keystroke to cancel during commandmanager.pick operation

Capturing keystroke to cancel during commandmanager.pick operation

josh.nieman
Advocate Advocate
1,614 Views
7 Replies
Message 1 of 8

Capturing keystroke to cancel during commandmanager.pick operation

josh.nieman
Advocate
Advocate

I am having exceptions thrown that I can't figure out the problem of.

From a form, a user clicks a button to begin a sub that adds model annotation leaders one at a time.

It loops until a certain boolean is set True.

The boolean is set to True when another sub, running on a timer-tick, detects any of a few keys are pressed.  The sub to add the leaders is perfectly fine and works without error, when not being looped as I am trying to do.

When I press "esc" though, I get this error:

 

+ $exception {"The parameter is incorrect. (Exception from HRESULT: 0x80070057 (E_INVALIDARG))"} System.ArgumentException

 

Here's what I have:

 

Calling the sub:

 


Private Sub button_Click(sender As Object, e As EventArgs) Handles button.Click

While Trip = False 'Do the thing until the user doesn't want to do the thing anymore
AddLeader()
End While

 

 

Here's the while loop:

 

 

Private Declare Function GetAsyncKeyState Lib "user32" (ByVal vkey As Integer) As Short

'Timer 'enable' and 'interval' are set in the form code where the form is instantiated
Private Sub Timer1_tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
Dim KeySpace As Boolean
Dim KeyEnter As Boolean
Dim KeyEsc As Boolean
Dim KeyCancel As Boolean
KeySpace = GetAsyncKeyState(Keys.Space)
KeyEnter = GetAsyncKeyState(Keys.Enter)
KeyEsc = GetAsyncKeyState(Keys.Escape)
KeyCancel = GetAsyncKeyState(Keys.Cancel)

If KeySpace Or KeyEnter Or KeyEsc Or KeyCancel = True Then
Trip = True
Else
Trip = False
End If
End Sub

Additionally, nothing happens when I hit spacebar or enter.

 

Can anyone spot my mistake and give me some pointers, please?

 

0 Likes
Accepted solutions (2)
1,615 Views
7 Replies
Replies (7)
Message 2 of 8

philip1009
Advisor
Advisor

My first question is if you're trying to achieve this through iLogic or through an Add-In?  iLogic doesn't support WithEvents tracking through keyboard or mouse like a typical VB rule.  The best workaround I've found is by making an External Rule to go with a Global Form that has a Cancel button in it, it's not the best or most stable workaround, but I can provide that if you want to try it.  Other than that, if you're just looking for a way to escape an infinite loop, before the loop starts put in an On Error Goto then you can use that error to your advantage to get out of the loop.

0 Likes
Message 3 of 8

josh.nieman
Advocate
Advocate

This is indeed a VB add-in.  Not iLogic.

 

I've come across a few solutions using a cancel button, but unless I can tie that to keyboard input, I don't know that I care for it as being better than default performance.

 

I just figure that a users natural instincts, when done selecting points, is to hit one of the typical "I'M DONE!" or "STOP" or "CANCEL" keys, to end or move past that particular step of the process, and wanted to have my add-in react to that input intuitively.

 

I'm obviously not having much luck.

 

I wouldn't mind seeing what you have for the cancel, though.  I may have misunderstood, initially, and it may do what I want, or similar to it.

 

Thanks for the quick response!

0 Likes
Message 4 of 8

philip1009
Advisor
Advisor
Accepted solution

For Inventor Add-Ins, mouse and keyboard interaction can be achieved through the CommandManager.CreateInteractionEvents As InteractionEvents, then keyboard/mouse and other Events can be tracked with a bunch of subs.  However I rarely code Add-Ins so I'm not a good reference for that.

 

For the Cancel button I use this External Rule called Cancel:

SyntaxEditor Code Snippet

Public Class CancelButton
	Dim Cancel As Boolean = False
	Sub Main
		SharedVariable("Cancel") = True
	End Sub
End Class

Make a form in Global Forms called Cancel, just drag the Cancel rule from the dialog on the left of the Form Editor to make a button, then save the form and close editor.

Cancel_edited.jpg

 

Then to use that button in any rule you first have to use these lines toward the beginning of the rule:

SyntaxEditor Code Snippet

iLogicVb.RunExternalRule("Cancel")
If SharedVariable("Cancel") = True Then SharedVariable("Cancel") = False
iLogicForm.ShowGlobal("Cancel", FormMode.NonModal)

The first line will run the rule so it will create the SharedVariable("Cancel") which is similar to a public variable.  Then the second line will change the variable to False.  Then the third line will make the Form with the Cancel button pop up.  Anytime the rule is run again by clicking the Cancel button in the form, the variable will change to False.  I've mainly used this for long running operations like a mass export of PDF drawings or flat pattern DXFs, I just check if the shared variable Cancel is True at the right points to exit long loops.

 

EDIT: The only thing I forgot to mention is there's no way to close a form with an iLogic rule, so you have to manually close the form yourself.

0 Likes
Message 5 of 8

josh.nieman
Advocate
Advocate

Thanks for the contribution!

 

It DOES look like you are correct.  I had not come across this in the API and apparently my google-fu was weak this morning and yesterday, as I never came across this:

https://knowledge.autodesk.com/search-result/caas/CloudHelp/cloudhelp/2018/ENU/Inventor-API/files/In...


Which APPEARS to have what I'll need to get it done.  I think I was too focused in trying to make a particular method work, and needed to broaden my search.  Thanks again!  After I finish up my current task, I'll be sure to get on this, and try to post my results when I have something working. 

Message 6 of 8

fredform
Advocate
Advocate

Hi,

I had a similar problem myself (using iLogic) and the following solution seems to work:

	Dim oSelOcc As ComponentOccurrence
	oSelOcc = ThisApplication.CommandManager.Pick(SelectionFilterEnum.kAssemblyOccurrenceFilter, "Select a component to delete")
	
	'Exit rule if nothing is selected
	If oSelOcc Is Nothing Then
		Return
	End If

 

Pressing escape moves the program past the CommandManager line and the variable is subsequently nothing so program exits.

 

/Fredrik

 

0 Likes
Message 7 of 8

josh.nieman
Advocate
Advocate
Accepted solution

Good sample, @fredform !

Your method is (imo) the easiest and smoothest when using built-in Inventor UI commands such as Pick because it's inheriting the built-in behaviors Autodesk devs built in to that User Command by means of using the Application.CommandManager 

Since I apparently failed to follow up, those years ago, here's what I've done since:

For any add-ins that are firing off custom functions/commands/subs/methods/whatever, you may find yourself having to build something like that from scratch. If that's the case, I found that using the other Interaction/Command manager objects - pertinent to this thread topic is:


Use the CommandManger.InteractionEvents (object)

---created via Application.CommandManager.CreateInteractionEvents (method)

It lets you start, stop the events, or even create a native MiniToolbar while the InteractionEvents is active. Part of the properties of the InteractionEvents object is KeyboardEvents, MouseEvents, MeasureEvents, SelectEvents objects amongst more. KeyboardEvents has the typical OnKeyDownOnKeyPressOnKeyUp event listeners, for example.

 

...and until now, I didn't know (or since forgot) that there's a ShiftStateEnum property attached to the KeyboardEvents object, which returns the corresponding constant for the state of the SHIFT, CTRL, ALT keys.  Handy.

 

You can wrap your command in an InteractionEvents object's Start/Stop and inherit all the cool stuff that comes with it, and know what a user's doing, and handle their inputs appropriately - or inappropriately if you're into that kind of evil.

Bonus factoid: You can also use the Application.TransactionManager object to improve tangential UX things like wrapping up a lot of steps up into a single undo entry.

(Example, if your code "places" 20 different components into the assembly, and you end up with 20 "Undo Place Component" in the undo button drop-down, you can wrap it up into a single Undo My Cool Components Macro entry that undoes them all in one go.)

Message 8 of 8

fredform
Advocate
Advocate

Really good information there @josh.nieman! Thanks for sharing!

0 Likes