Handle Enter key from a MiniToolbar

By Adam Nagy

In case of built-in commands like the Extrude command when the user presses the Enter key it has the same effect as if the Apply button was clicked – the changes will be applied and the mini toolbar gets dismissed.

However, when using the MiniToolbar class of the API the Enter key does not dismiss the mini toolbar and there does not seem to be a way to catch the Enter key being pressed either, so that we could dismiss it ourselves. This seems to be an oversight which will be solved in the future, I hope.

In the meantime you can use a keyboard hook to watch out for the Enter key. You could use solutions like this: http://blogs.msdn.com/b/toub/archive/2006/05/03/589423.aspx

I used the MiniToolbar sample from the API Help file and then added the keyboard hook to it:

Imports Inventor
Imports System.Windows.Forms
Imports System.Runtime.InteropServices
 
Public Class InterceptKeys
  Private Const WH_KEYBOARD_LL As Integer = 13
  Private Const WM_KEYDOWN As Integer = &H100
  Private Shared _proc As LowLevelKeyboardProc = 
    New LowLevelKeyboardProc(AddressOf HookCallback)
  Private Shared _hookID As IntPtr = IntPtr.Zero
  Private Shared _mini As MyMiniToolbar
 
  Public Shared Sub SetHook(mini As MyMiniToolbar)
    _mini = mini
    _hookID = SetHook(_proc)
  End Sub
 
  Public Shared Sub UnhookWindowsHookEx()
    UnhookWindowsHookEx(_hookID)
  End Sub
 
  Private Shared Function SetHook(
    proc As LowLevelKeyboardProc) As IntPtr
    Using curProcess As Process = Process.GetCurrentProcess()
      Using curModule As ProcessModule = curProcess.MainModule
        Return SetWindowsHookEx(WH_KEYBOARD_LL, proc, 
          GetModuleHandle(curModule.ModuleName), 0)
      End Using
    End Using
  End Function
 
  Private Delegate Function LowLevelKeyboardProc(
    nCode As Integer, wParam As IntPtr, lParam As IntPtr) As IntPtr
 
  Private Shared Function HookCallback(
    nCode As Integer, wParam As IntPtr, lParam As IntPtr) As IntPtr
    If nCode >= 0 AndAlso wParam = New IntPtr(WM_KEYDOWN) Then
      Dim vkCode As Integer = Marshal.ReadInt32(lParam)
      Dim key As Keys = DirectCast(vkCode, Keys)
      System.Diagnostics.Debug.WriteLine(key)
      If key = Keys.Enter Then
        _mini.m_MiniToolbar_OnOK()
      End If
    End If
    Return CallNextHookEx(_hookID, nCode, wParam, lParam)
  End Function
 
  
  Private Shared Function SetWindowsHookEx(
    idHook As Integer, lpfn As LowLevelKeyboardProc, 
    hMod As IntPtr, dwThreadId As UInteger) As IntPtr
  End Function
 
   
  Private Shared Function UnhookWindowsHookEx(hhk As IntPtr) _
    As  Boolean
  End Function
 
  
  Private Shared Function CallNextHookEx(
    hhk As IntPtr, nCode As Integer, wParam As IntPtr, lParam As IntPtr) _
    As IntPtr
  End Function
 
  
  Private Shared Function GetModuleHandle(lpModuleName As String) As IntPtr
  End Function
End Class
 
Public Class MyMiniToolbar
  '*************************************************************
  ' The declarations and functions below need to be copied into
  ' a class module whose name is "clsMiniToolbarEvents". The name can be
  ' changed but you'll need to change the declaration in the
  ' calling function "CreateSketchSlotSample" to use the new name.
  Private WithEvents m_EndCenterOneX As MiniToolbarValueEditor
  Private WithEvents m_EndCenterOneY As MiniToolbarValueEditor
  Private WithEvents m_EndCenterTwoX As MiniToolbarValueEditor
  Private WithEvents m_EndCenterTwoY As MiniToolbarValueEditor
  Private WithEvents m_Width As MiniToolbarValueEditor
  Private WithEvents m_MiniToolbar As MiniToolbar
  Private m_DisplayCenterline As MiniToolbarCheckBox
  Private m_Sketch As Sketch
  Private bCenterline As Boolean
  Private bStop As Boolean
 
  Private ThisApplication As Inventor.Application
 
  Public Sub Init(app As Inventor.Application)
    ThisApplication = app
 
    Dim oActiveEnv As Environment = 
      ThisApplication.UserInterfaceManager.ActiveEnvironment
 
    If oActiveEnv.InternalName  "PMxPartSketchEnvironment" And 
        oActiveEnv.InternalName  "AMxAssemblySketchEnvironment" And 
        oActiveEnv.InternalName  "DLxDrawingSketchEnvironment" Then
      MsgBox("Please activate a sketch environment first!")
      Exit Sub
    End If
 
    m_MiniToolbar = ThisApplication.CommandManager.CreateMiniToolbar
 
    m_MiniToolbar.ShowOK = True
    m_MiniToolbar.ShowApply = True
    m_MiniToolbar.ShowCancel = True
 
    Dim oControls As MiniToolbarControls
    oControls = m_MiniToolbar.Controls
    oControls.Item("MTB_Options").Visible = False
 
    Dim oDescriptionLabel As MiniToolbarControl
    oDescriptionLabel = oControls.AddLabel(
      "Description", 
      "This toolbar is to create sketch slot:", 
      "MiniToolbar sample to show how to create sketch slot.")
    oControls.AddNewLine()
 
    ' Define the first center position.
    Dim oEndCenterOne As MiniToolbarButton
    oEndCenterOne = oControls.AddButton(
      "FirstCenter: ", 
      "First Center:     ", 
      "Specify the first center of sketch slot")
 
    m_EndCenterOneX = oControls.AddValueEditor(
      "FirstCenterX", "", ValueUnitsTypeEnum.kLengthUnits, "", "X:")
    m_EndCenterOneX.Expression = "0"
    m_EndCenterOneX.SetFocus()
 
    m_EndCenterOneY = oControls.AddValueEditor(
      "FirstCenterY", "", ValueUnitsTypeEnum.kLengthUnits, "", "Y:")
    m_EndCenterOneY.Expression = "0"
    oControls.AddNewLine()
 
    ' Define the second center position.
    Dim oEndCenterTwo As MiniToolbarButton
    oEndCenterTwo = oControls.AddButton(
      "SecondCenter:", "Second Center:", 
      "Specify the second center of sketch slot")
 
    m_EndCenterTwoX = oControls.AddValueEditor(
      "SecondCenterX", "", ValueUnitsTypeEnum.kLengthUnits, "", "X:")
    m_EndCenterTwoX.Expression = "3"
 
 
    m_EndCenterTwoY = oControls.AddValueEditor(
      "SecondCenterY", "", ValueUnitsTypeEnum.kLengthUnits, "", "Y:")
    m_EndCenterTwoY.Expression = "0"
 
    oControls.AddNewLine()
 
    ' Define the width of sketch slot.
 
    m_Width = oControls.AddValueEditor(
      "WidthValue", "", ValueUnitsTypeEnum.kLengthUnits, "", "Width:")
    m_Width.Expression = "1"
 
    ' Define if display the center line of sketch slot.
    m_DisplayCenterline = oControls.AddCheckBox(
      "DisplayCenterline", "Display center line", 
      "Check this to display center line of slot", True)
 
    ' the position of mini-toolbar
    Dim oPosition As Point2d
    oPosition = ThisApplication.TransientGeometry.CreatePoint2d(
      ThisApplication.ActiveView.Left, ThisApplication.ActiveView.Top)
    m_MiniToolbar.Position = oPosition
 
    m_MiniToolbar.Visible = True
 
    m_MiniToolbar = m_MiniToolbar
 
    m_Sketch = ThisApplication.ActiveEditObject
    bStop = False
 
    InterceptKeys.SetHook(Me)
 
    Do
      ThisApplication.UserInterfaceManager.DoEvents()
    Loop Until bStop
 
    InterceptKeys.UnhookWindowsHookEx()
  End Sub
 
  Private Sub m_MiniToolbar_OnApply() Handles m_MiniToolbar.OnApply
    CreateSlot()
  End Sub
 
  Private Sub m_MiniToolbar_OnCancel() Handles m_MiniToolbar.OnCancel
    bStop = True
  End Sub
 
  Public Sub m_MiniToolbar_OnOK() Handles m_MiniToolbar.OnOK
    bStop = True
    CreateSlot()
    m_MiniToolbar.Delete()
  End Sub
 
  Private Sub CreateSlot()
 
    If Not (m_EndCenterOneX.IsExpressionValid And 
            m_EndCenterOneY.IsExpressionValid And 
            m_EndCenterTwoX.IsExpressionValid And 
            m_EndCenterTwoY.IsExpressionValid) Then
      MsgBox("Invalid values for end center positions!")
      Exit Sub
    End If
 
    bCenterline = m_DisplayCenterline.Checked
 
    Dim oTG As TransientGeometry
    oTG = ThisApplication.TransientGeometry
 
    Dim oEndCenterOne As Point2d
    Dim oEndCenterTwo As Point2d
    Dim oEndArcOne As SketchArc
    Dim oEndArcTwo As SketchArc
 
    ' Start transaction for creating slot.
    Dim oTransaction As Transaction = 
      ThisApplication.TransactionManager.StartTransaction(
        ThisApplication.ActiveDocument, "Create slot")
 
    ' If the two centers are vertical
    If Math.Abs(
      m_EndCenterOneX.Value - m_EndCenterTwoX.Value) < 0.000001 Then
      If (m_EndCenterOneY.Value > m_EndCenterTwoY.Value) Then
        oEndCenterOne = oTG.CreatePoint2d(
          m_EndCenterOneX.Value, m_EndCenterOneY.Value)
        oEndCenterTwo = oTG.CreatePoint2d(
          m_EndCenterTwoX.Value, m_EndCenterTwoY.Value)
      Else
        oEndCenterOne = oTG.CreatePoint2d(
          m_EndCenterTwoX.Value, m_EndCenterTwoY.Value)
        oEndCenterTwo = oTG.CreatePoint2d(
          m_EndCenterOneX.Value, m_EndCenterOneY.Value)
      End If
 
      If oEndCenterOne.IsEqualTo(oEndCenterTwo, 0.000001) Then
        MsgBox("The two centers are coincident!")
        Exit Sub
      End If
 
      ' Create the top arc
      oEndArcOne = m_Sketch.SketchArcs.AddByCenterStartEndPoint(
        oEndCenterOne, 
        oTG.CreatePoint2d(oEndCenterOne.X + 0.1, oEndCenterOne.Y), 
        oTG.CreatePoint2d(oEndCenterOne.X - 0.1, oEndCenterOne.Y))
      ' Create the bottom arc
      oEndArcTwo = m_Sketch.SketchArcs.AddByCenterStartEndPoint(
        oEndCenterTwo, 
        oTG.CreatePoint2d(oEndCenterTwo.X - 0.1, oEndCenterTwo.Y), 
        oTG.CreatePoint2d(oEndCenterTwo.X + 0.1, oEndCenterTwo.Y))
      'If the two centers are not vertical
    Else
      If m_EndCenterOneX.Value < m_EndCenterTwoX.Value Then
        oEndCenterOne = oTG.CreatePoint2d(
          m_EndCenterOneX.Value, m_EndCenterOneY.Value)
        oEndCenterTwo = oTG.CreatePoint2d(
          m_EndCenterTwoX.Value, m_EndCenterTwoY.Value)
      ElseIf m_EndCenterOneX.Value > m_EndCenterTwoX.Value Then
        oEndCenterOne = oTG.CreatePoint2d(
          m_EndCenterTwoX.Value, m_EndCenterTwoY.Value)
        oEndCenterTwo = oTG.CreatePoint2d(
          m_EndCenterOneX.Value, m_EndCenterOneY.Value)
      End If
 
      If oEndCenterOne.IsEqualTo(oEndCenterTwo, 0.000001) Then
        MsgBox("The two centers are coincident!")
        Exit Sub
      End If
 
      oEndArcOne = m_Sketch.SketchArcs.AddByCenterStartEndPoint( 
        oEndCenterOne, 
        oTG.CreatePoint2d(
          m_EndCenterOneX.Value, m_EndCenterOneY.Value + 0.1), 
        oTG.CreatePoint2d(
          m_EndCenterOneX.Value, m_EndCenterOneY.Value - 0.1))
      oEndArcTwo = m_Sketch.SketchArcs.AddByCenterStartEndPoint(
        oEndCenterTwo, 
        oTG.CreatePoint2d(
          m_EndCenterTwoX.Value, m_EndCenterTwoY.Value + 0.1), 
        oTG.CreatePoint2d(
          m_EndCenterTwoX.Value, m_EndCenterTwoY.Value - 0.1), 
        False)
    End If
 
    Dim dWidth As Double
    dWidth = m_Width.Value
 
    ' Create center line if required
    If bCenterline Then
      Dim oCenterline As SketchLine
      oCenterline = m_Sketch.SketchLines.AddByTwoPoints(
        oEndArcOne.CenterSketchPoint, oEndArcTwo.CenterSketchPoint)
 
      oCenterline.Construction = True
    End If
 
    Dim oGround1 As GroundConstraint
    Dim oGround2 As GroundConstraint
    oGround1 = m_Sketch.GeometricConstraints.AddGround(
      oEndArcOne.CenterSketchPoint)
    oGround2 = m_Sketch.GeometricConstraints.AddGround(
      oEndArcTwo.CenterSketchPoint)
 
    ' Create sketch lines of slot
    Dim oLine1 As SketchLine
    Dim oLine2 As SketchLine
    oLine1 = m_Sketch.SketchLines.AddByTwoPoints(
      oEndArcOne.StartSketchPoint, oEndArcTwo.EndSketchPoint)
    oLine2 = m_Sketch.SketchLines.AddByTwoPoints(
      oEndArcOne.EndSketchPoint, oEndArcTwo.StartSketchPoint)
 
    ' Add geometric constraints to the sketch entities
    Call m_Sketch.GeometricConstraints.AddEqualRadius(
      oEndArcOne, oEndArcTwo)
    Call m_Sketch.GeometricConstraints.AddTangent(
      oLine1, oEndArcOne)
    Call m_Sketch.GeometricConstraints.AddTangent(
      oLine1, oEndArcTwo)
    Call m_Sketch.GeometricConstraints.AddTangent(
      oLine2, oEndArcOne)
    Call m_Sketch.GeometricConstraints.AddTangent(
      oLine2, oEndArcTwo)
 
    ' Add dimensional constraints to the sketch entities
    Dim oDiameter As DiameterDimConstraint
    oDiameter = m_Sketch.DimensionConstraints.AddDiameter(
      oEndArcOne, oEndArcOne.CenterSketchPoint.Geometry)
    oDiameter.Parameter.Value = dWidth
 
    ThisApplication.ActiveDocument.Update()
    oDiameter.Delete()
    oGround1.Delete()
    oGround2.Delete()
 
    oTransaction.End()
 
  End Sub
 
End Class

And then you can use it like this from your command's event handler:

Protected Overrides Sub ButtonDefinition_OnExecute(  ByVal context As Inventor.NameValueMap)
    Dim mtb As New MyMiniToolbar 
    mtb.Init(InventorApplication) 
End Sub

Comments

Leave a Reply

Discover more from Autodesk Developer Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading