找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 1187|回复: 0

[分享] Filtering Windows messages inside AutoCAD using .NET

[复制链接]

已领礼包: 859个

财富等级: 财运亨通

发表于 2017-5-21 10:19:37 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
http://through-the-interface.typ ... iltering-windo.html
                        Back when I joined Autodesk in 1995, I worked in European Developer Support with one of the most talented programmers I've met, Markus Kraus. One of Markus' contributions to the R13 ARX SDK (or maybe it was R14?) was a sample called pretranslate, which remained on the SDK up until ObjectARX 2008, under samples/editor/mfcsamps/pretranslate (it was removed from the 2009 SDK when we archived a number of aging samples).
Anyway, with AutoCAD 2009 the API that makes this sample possible has been added to the .NET API, so in homage to Markus' original sample (which I have fond memories of demoing during a number of events around Europe), I decided to translate the original C++ sample to C#.
Here's the C# code:
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Runtime;
using System.Windows.Interop;
using System;

namespace PreTranslate
{
  public class Commands
  {
    // Keys

    const int MK_SHIFT = 4;
    const int MK_CONTROL = 8;

    // Keyboard messages

    const int WM_KEYDOWN = 256;
    const int WM_KEYUP = 257;
    const int WM_CHAR = 258;
    const int WM_SYSKEYDOWN = 260;
    const int WM_SYSKEYUP = 261;

    // Mouse messages

    const int WM_MOUSEMOVE = 512;
    const int WM_LBUTTONDOWN = 513;
    const int WM_LBUTTONUP = 514;

    static long MakeLong(int LoWord, int HiWord)
    {
      return (HiWord << 16) | (LoWord & 0xffff);
    }
    static IntPtr MakeLParam(int LoWord, int HiWord)
    {
      return (IntPtr)MakeLong(LoWord,HiWord);
    }
    static int HiWord(int Number)
    {
      return (Number >> 16) & 0xffff;
    }
    static int LoWord(int Number)
    {
      return Number & 0xffff;
    }

    // State used by the VhmouseHandler to filter on
    // the vertical or the horizontal

    bool vMode;
    bool hMode;
    int ptx;
    int pty;

    // Commands to add/remove message handlers

    [CommandMethod("caps")]
    public void Caps()
    {
      Application.PreTranslateMessage +=
        new PreTranslateMessageEventHandler(CapsHandler);
    }
    [CommandMethod("uncaps")]
    public void UnCaps()
    {
      Application.PreTranslateMessage -=
        new PreTranslateMessageEventHandler(CapsHandler);
    }
    [CommandMethod("vhmouse")]
    public void Vhmouse()
    {
      Application.PreTranslateMessage +=
        new PreTranslateMessageEventHandler(VhmouseHandler);
    }
    [CommandMethod("unvhmouse")]
    public void UnVhmouse()
    {
      Application.PreTranslateMessage -=
        new PreTranslateMessageEventHandler(VhmouseHandler);
    }
    [CommandMethod("watchCC")]
    public void WatchCC()
    {
      Application.PreTranslateMessage +=
        new PreTranslateMessageEventHandler(WatchCCHandler);
    }
    [CommandMethod("unwatchCC")]
    public void UnWatchCC()
    {
      Application.PreTranslateMessage -=
        new PreTranslateMessageEventHandler(WatchCCHandler);
    }
    [CommandMethod("noX")]
    public void NoX()
    {
      Application.PreTranslateMessage +=
        new PreTranslateMessageEventHandler(NoXHandler);
    }
    [CommandMethod("yes")]
    public void YesX()
    {
      Application.PreTranslateMessage -=
        new PreTranslateMessageEventHandler(NoXHandler);
    }

    // The event handlers themselves...

    // Force alphabetic character entry to uppercase

    void CapsHandler(
      object sender,
      PreTranslateMessageEventArgs e
    )
    {
      // For every lowercase character message,
      // reduce it my 32 (which forces it to
      // uppercase in ASCII)

      if (e.Message.message == WM_CHAR &&
          (e.Message.wParam.ToInt32() >= 97 &&
          e.Message.wParam.ToInt32() <= 122))
      {
        MSG msg = e.Message;
        msg.wParam =
          (IntPtr)(e.Message.wParam.ToInt32() - 32);
        e.Message = msg;
      }
    }

    // Force mouse movement to either horizontal or
    // vertical

    void VhmouseHandler(
      object sender,
      PreTranslateMessageEventArgs e
    )
    {
      // Only look at mouse messages

      if (e.Message.message == WM_MOUSEMOVE ||
          e.Message.message == WM_LBUTTONDOWN ||
          e.Message.message == WM_LBUTTONUP)
      {
        // If the left mousebutton is pressed and we are
        // filtering horizontal or vertical movement,
        // make the position the one we're storing

        if ((e.Message.message == WM_LBUTTONDOWN ||
            e.Message.message == WM_LBUTTONUP)
            && (vMode ||  hMode))
        {
          MSG msg = e.Message;
          msg.lParam = MakeLParam(ptx, pty);
          e.Message = msg;
          return;
        }

        // If the Control key is pressed

        if (e.Message.wParam.ToInt32() == MK_CONTROL)
        {
          // If we're already in "vertical" mode,
          // set the horizontal component of our location
          // to the one we've stored

          // Otherwise we set the internal "x" value
          // (as this is the first time through)

          if (vMode)
          {
            MSG msg = e.Message;
            msg.lParam =
              MakeLParam(
                ptx,
                HiWord(e.Message.lParam.ToInt32())
              );
            e.Message = msg;
            pty = HiWord(e.Message.lParam.ToInt32());
          }
          else
            ptx = LoWord(e.Message.lParam.ToInt32());

          vMode = true;
          hMode = false;
        }

        // If the Shift key is pressed

        else if (e.Message.wParam.ToInt32() == MK_SHIFT)
        {
          // If we're already in "horizontal" mode,
          // set the vertical component of our location
          // to the one we've stored

          // Otherwise we set the internal "y" value
          // (as this is the first time through)

          if (hMode)
          {
            MSG msg = e.Message;
            msg.lParam =
              MakeLParam(
                LoWord(e.Message.lParam.ToInt32()),
                pty
              );
            e.Message = msg;
            ptx = LoWord(e.Message.lParam.ToInt32());
          }
          else
            pty = HiWord(e.Message.lParam.ToInt32());
          hMode = true;
          vMode = false;
        }
        else
          // Something else was pressed,
          // so cancel our filtering

          vMode = hMode = false;
      }
    }

    // Watch for Ctrl-C, and display a message

    void WatchCCHandler(
      object sender,
      PreTranslateMessageEventArgs e
    )
    {
      // Check for the Ctrl-C Windows message

      if (e.Message.message == WM_CHAR &&
          e.Message.wParam.ToInt32() == 3)
      {
        Document doc =
          Application.DocumentManager.MdiActiveDocument;
        doc.Editor.WriteMessage(
          "\nCtrl-C is pressed"
        );
      }
    }

    // Filter out use of the letter x/X

    void NoXHandler(
      object sender,
      PreTranslateMessageEventArgs e
    )
    {
      // If lowercase or uppercase x is pressed,
      // filter the message by setting the
      // Handled property to true

      if (e.Message.message == WM_CHAR &&
          (e.Message.wParam.ToInt32() == 120 ||
          e.Message.wParam.ToInt32() == 88))
        e.Handled = true;
    }
  }
}

To be able to use the System.Windows.Interop namespace, you'll need to add a project reference to WindowsBase.dll. Strangely this can take some finding - at least on my system it wasn't included in the base assembly list. To find it, I browsed to:
C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\WindowsBase.dll
The application defines a number of commands, which are described in this text from the original sample's ReadMe:
This sample shows how to pretranslate AutoCAD messages
before they're processed by AutoCAD.
In order to pre-processe AutoCAD messages, a hook function
needs to be installed. The following commands install
different hook functions.

- vhmouse/unvhmouse
  Installs/uninstalls a hook that makes the mouse move only in a
  vertical direction if <CTRL> key is pressed, and only in a
  horizontal direction if the <SHIFT> key is pressed.

- caps/uncaps
  Installs/uninstalls a hook that capitalizes all
  letters typed in the command window.

- noX/yes
  Installs/uninstalls a hook that filters out the
  letters 'x' or 'X'.

- watchCC/unwatchCC
  Installs/uninstalls a hook that watchs
  for <CTRL>+C key combination to be pressed.

Here's what happens when we run the various commands:
Command: caps
Command: UNCAPS
Command: vhmouse
Command: unvhmouse
Command: watchcc
Command:
Ctrl-C is pressed
Command:
Command: _copyclip
Select objects: *Cancel*
Command: nox
Command: yes

While you can't see all the effects of the various commands from this dump of the command-line, here are some comments and pointers, should you try this sample:
  • The Shift or Caps Lock keys was not used at all during entry of the command-names
  • During the vhmouse command, move the mouse around and use the Shift and Ctrl keys to force the movement to horizontal or vertical
    • The Ctrl key now shows an entity selection cursor in AutoCAD, so I should probably have changed to another key for this, but anyway
  • Ctrl-C now launches COPYCLIP, but we see the message first
  • The yes command should obviously be called yesx, but then we can't enter the "x" character after running the nox command. :-)
As a final note: I don't recommend filtering commonly-used keystrokes in your application - your users really won't thank you - but this fun little sample at least shows you the capabilities of the PreTranslate mechanism.
               

论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|申请友链|Archiver|手机版|小黑屋|辽公网安备|晓东CAD家园 ( 辽ICP备15016793号 )

GMT+8, 2024-4-29 05:41 , Processed in 0.331179 second(s), 29 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表