Sdk Escape
Last changed: dale@mcneel.com-204.177.179.144

.
DeveloperC++

Overview

When writing commands that contain long, time-consuming tasks, you might want to allow the user to cancel the process or command. An easy way to do this is periodically test to see if the user pressed the ESC key. A fool-proof way for check to see if the ESC key has been pressed is to hook the Windows keyboard.

Example

The following sample class demonstrates how to hook the Windows keyboard from a Rhino plug-in and check for the ESC key.

  //
  // rhinoEscapeKey.h
  //


  class CRhinoEscapeKey
  {
  public:
    CRhinoEscapeKey( bool bHookNow = false );
    ~CRhinoEscapeKey();
    bool Start();
    void Stop();
    bool EscapeKeyPressed() const;
    void ClearEscapeKeyPressedFlag();
  protected:
    static LRESULT CALLBACK HookProc( int code, WPARAM wParam, LPARAM lParam );
    static HHOOK m_KeyboardHookProc;
    static bool m_escape_pressed;
  };
  //
  // rhinoEscapeKey.cpp
  //


  bool CRhinoEscapeKey::m_escape_pressed = false;
  HHOOK CRhinoEscapeKey::m_KeyboardHookProc = NULL;


  CRhinoEscapeKey::CRhinoEscapeKey( bool bStartNow )
  {
    if( bStartNow )
      Start();
  }


  CRhinoEscapeKey::~CRhinoEscapeKey()
  {
    Stop();
  }


  bool CRhinoEscapeKey::Start()
  {
    if( NULL == m_KeyboardHookProc )
      m_KeyboardHookProc = ::SetWindowsHookEx( 
                                WH_KEYBOARD, 
                                CRhinoEscapeKey::HookProc, 
                                RhinoApp().RhinoInstanceHandle(), 
                                ::AfxGetThread()->m_nThreadID 
                                );
    ClearEscapeKeyPressedFlag();
    return( NULL != m_KeyboardHookProc );
  }


  void CRhinoEscapeKey::Stop()
  {
    if( m_KeyboardHookProc )
      UnhookWindowsHookEx( m_KeyboardHookProc );
    m_KeyboardHookProc = NULL;
  }


  bool CRhinoEscapeKey::EscapeKeyPressed() const
  {
    RhinoApp().Wait(0);
    return m_escape_pressed;
  }


  void CRhinoEscapeKey::ClearEscapeKeyPressedFlag()
  {
    m_escape_pressed = false;
  }


  LRESULT CALLBACK CRhinoEscapeKey::HookProc( int code, WPARAM wParam, LPARAM lParam )
  {
    // On escape key down....
    if( code == HC_ACTION && wParam == VK_ESCAPE && !(lParam & 0x80000000) )
    {
      m_escape_pressed = true;
      UnhookWindowsHookEx( m_KeyboardHookProc );
      m_KeyboardHookProc = NULL;
      return 0; // Eat the escape key
    }
    // call next hook proc including standard windows proc.
    return CallNextHookEx( m_KeyboardHookProc, code, wParam, lParam );
  }

Usage

The following sample code demonstrates using the CRhinoEscapeKey class within a Rhino command.

  CRhinoCommand::result CCommandTest::RunCommand( const CRhinoCommandContext& context )
  {
    CRhinoEscapeKey escape;
    escape.Start();


    int i = 0;
    while( true )
    {
      if( escape.EscapeKeyPressed() )
      {
        escape.Stop();
        RhinoApp().Print( L"Command canceled.\n" );
        break;
      }
      RhinoApp().Print( L"Count = %d.\n", ++i );
    }


    return success;
  }