I want my add-in to be able to respond to a mouse wheel event while a document is active in the Visual Studio text editor. My immediate goal is to bind Ctrl+WheelUp to PgUp and Ctrl+WheelDn to PgDn, but it would be nice to have this adjustable. I just don't know how to respond to a mouse wheel event.
Thanks,
Sam

Adaptation
Stijn V
I'm actually using my implementation of this in an open-source plugin I made for VS 2005. I haven't had any problems with it at all. Here's a link to the plugin's homepage:
http://djss.dynalias.net/trac/SamTools
Here's a link to the classes that provide mouse support:
http://djss.dynalias.net/trac/SamTools/browser/trunk/SamTools/MouseActions.cs
http://djss.dynalias.net/trac/SamTools/browser/trunk/SamTools/MouseHook.cs
Keep the first 17 lines of those files in mind, I don't want you to run into any problems later. :)
Dagaen
When the .NET framework fails you, there lies the Platform SDK waiting to save you.
Bare bones class to provide a MouseWheel event in the IDE:
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace SomeNamespace
{
public delegate IntPtr MouseProc( int code, UIntPtr wParam, ref MOUSEHOOKSTRUCTEX lParam );
public struct tagPoint
{
public int X;
public int Y;
}
public struct MOUSEHOOKSTRUCT
{
public tagPoint pt;
public IntPtr WindowHandle;
public uint wHitTestCode;
public UIntPtr dwExtraInfo;
}
public struct MOUSEHOOKSTRUCTEX
{
public MOUSEHOOKSTRUCT mstruct;
public uint mouseData;
}
class MouseHook
{
public event MouseEventHandler MouseWheel;
private void OnMouseWheel( MouseEventArgs e )
{
MouseEventHandler t = MouseWheel;
if (t != null)
t( this, e );
}
private IntPtr mouseHandle;
private bool enterHook;
private MouseProc callback;
private const int WH_MOUSE = 7;
private const int WM_MOUSEMOVE = 0x200;
private const int WHEEL_DELTA = 120;
#region Imported Windows system calls
[DllImport( "user32.dll" )]
private extern static int UnhookWindowsHookEx( IntPtr hHook );
[DllImport( "user32.dll" )]
private extern static IntPtr SetWindowsHookEx( int idHook, MouseProc lpfn, IntPtr hmod, uint dwThreadId );
[DllImport( "user32.dll" )]
private extern static IntPtr CallNextHookEx( IntPtr hHook, int nCode, UIntPtr wParam, ref MOUSEHOOKSTRUCTEX lParam );
[DllImport( "kernel32.dll" )]
private extern static uint GetCurrentThreadId( );
#endregion
public MouseHook( )
{
mouseHandle = IntPtr.Zero;
enterHook = true;
}
~MouseHook( )
{
if (mouseHandle != IntPtr.Zero)
{
UnHook( );
}
}
public bool Hooked
{
get
{
return mouseHandle != IntPtr.Zero;
}
}
ushort HIWORD( uint val )
{
return (ushort)(val >> 16);
}
public void Hook( )
{
if (mouseHandle != IntPtr.Zero)
return;
callback = MouseCallback;
uint threadId = GetCurrentThreadId( );
mouseHandle = SetWindowsHookEx( WH_MOUSE, callback, IntPtr.Zero, threadId );
}
public void UnHook( )
{
if (mouseHandle == IntPtr.Zero)
return;
UnhookWindowsHookEx( mouseHandle );
mouseHandle = IntPtr.Zero;
}
private IntPtr MouseCallback( int code, UIntPtr wParam, ref MOUSEHOOKSTRUCTEX lParam )
{
try
{
if (enterHook)
{
enterHook = false;
if (code >= 0)
{
int x = lParam.mstruct.pt.X;
int y = lParam.mstruct.pt.Y;
switch (wParam.ToUInt32())
{
case WM_MOUSEWHEEL:
OnMouseWheel( new MouseEventArgs( MouseButtons.None, 0, x, y, ((short)HIWORD( lParam.mouseData )) / WHEEL_DELTA ) );
break;
/* feel free to add other events... i did... */
default:
/* don't do anything special */
break;
}
}
}
else
{
enterHook = true;
}
}
catch
{
/* can't let an exception get through to the kernel */
}
return CallNextHookEx( mouseHandle, code, wParam, ref lParam );
}
}
}
// For some reason if you start a comment with "//" on this forum it turns
the whole rest of the code block green
And here is pretty much how to use it:
MouseHook mouse_enhancer;
...
mouse_enhancer = new MouseHook( );
mouse_enhancer.MouseWheel += new MouseEventHandler( mouse_enhancer_MouseWheel );
mouse_enhancer.Hook();
...
void mouse_enhancer_MouseWheel( object sender, System.Windows.Forms.MouseEventArgs e )
{
try
{
if (Keyboard.GetKeyState( System.Windows.Forms.Keys.ControlKey ).IsDown &&
applicationObject.ActiveWindow.Type == vsWindowType.vsWindowTypeDocument)
{
int clicks = e.Delta;
if (e.Delta < 0)
{
applicationObject.ExecuteCommand( "Edit.ScrollPageDown", "" );
}
else
{
applicationObject.ExecuteCommand( "Edit.ScrollPageUp", "" );
}
}
}
catch (Exception exc)
{
MessageBox.Show( exc.ToString( ), "An exception occurred in mouse_enhancer_MouseWheel()" );
}
}
oasisman
I have adapted the preceding code to pick up WM_LBUTTONDOWN messages. It works. However the mouse click event handler is executing twice. Which really doesn't work for what I am trying to do.
Steven I.
Hai Sam,
If your question is for VS.NET 2003, then I 'm afraid there is no events available that can help you to capture those Key Events. The available events with the DTE are as follows;
windowsEvents = (EnvDTE.WindowEvents)events.get_WindowEvents(null);
textEditorEvents = (EnvDTE.TextEditorEvents)events.get_TextEditorEvents(null);
taskListEvents = (EnvDTE.TaskListEvents)events.get_TaskListEvents("");
solutionEvents = (EnvDTE.SolutionEvents)events.SolutionEvents;
selectionEvents = (EnvDTE.SelectionEvents)events.SelectionEvents;
outputWindowEvents = (EnvDTE.OutputWindowEvents)events.get_OutputWindowEvents("");
findEvents = (EnvDTE.FindEvents)events.FindEvents;
dteEvents = (EnvDTE.DTEEvents)events.DTEEvents;
documentEvents = (EnvDTE.DocumentEvents)events.get_DocumentEvents(null);
debuggerEvents = (EnvDTE.DebuggerEvents)events.DebuggerEvents;
commandEvents = (EnvDTE.CommandEvents)events.get_CommandEvents("{00000000-0000-0000-0000-000000000000}", 0);
buildEvents = (EnvDTE.BuildEvents)events.BuildEvents;
miscFilesEvents = (EnvDTE.ProjectItemsEvents)events.MiscFilesEvents;
solutionItemsEvents = (EnvDTE.ProjectItemsEvents)events.SolutionItemsEvents;
windowsEvents.WindowActivated += new _dispWindowEvents_WindowActivatedEventHandler(this.WindowActivated);
windowsEvents.WindowClosing += new _dispWindowEvents_WindowClosingEventHandler(this.WindowClosing);
windowsEvents.WindowCreated += new _dispWindowEvents_WindowCreatedEventHandler(this.WindowCreated);
windowsEvents.WindowMoved += new _dispWindowEvents_WindowMovedEventHandler(this.WindowMoved);
textEditorEvents.LineChanged += new _dispTextEditorEvents_LineChangedEventHandler(this.LineChanged);
taskListEvents.TaskAdded += new _dispTaskListEvents_TaskAddedEventHandler(this.TaskAdded);
taskListEvents.TaskModified += new _dispTaskListEvents_TaskModifiedEventHandler(this.TaskModified);
taskListEvents.TaskNavigated += new _dispTaskListEvents_TaskNavigatedEventHandler(this.TaskNavigated);
taskListEvents.TaskRemoved += new _dispTaskListEvents_TaskRemovedEventHandler(this.TaskRemoved);
solutionEvents.AfterClosing += new _dispSolutionEvents_AfterClosingEventHandler(this.AfterClosing);
solutionEvents.BeforeClosing += new _dispSolutionEvents_BeforeClosingEventHandler(this.BeforeClosing);
solutionEvents.Opened += new _dispSolutionEvents_OpenedEventHandler(this.Opened);
solutionEvents.ProjectAdded += new _dispSolutionEvents_ProjectAddedEventHandler(this.ProjectAdded);
solutionEvents.ProjectRemoved += new _dispSolutionEvents_ProjectRemovedEventHandler(this.ProjectRemoved);
solutionEvents.ProjectRenamed += new _dispSolutionEvents_ProjectRenamedEventHandler(this.ProjectRenamed);
solutionEvents.QueryCloseSolution += new _dispSolutionEvents_QueryCloseSolutionEventHandler(this.QueryCloseSolution);
solutionEvents.Renamed += new _dispSolutionEvents_RenamedEventHandler(this.Renamed);
selectionEvents.OnChange += new _dispSelectionEvents_OnChangeEventHandler(this.OnChange);
outputWindowEvents.PaneAdded += new _dispOutputWindowEvents_PaneAddedEventHandler(this.PaneAdded);
outputWindowEvents.PaneClearing += new _dispOutputWindowEvents_PaneClearingEventHandler(this.PaneClearing);
outputWindowEvents.PaneUpdated += new _dispOutputWindowEvents_PaneUpdatedEventHandler(this.PaneUpdated);
findEvents.FindDone += new _dispFindEvents_FindDoneEventHandler(this.FindDone);
dteEvents.ModeChanged += new _dispDTEEvents_ModeChangedEventHandler(this.ModeChanged);
dteEvents.OnBeginShutdown += new _dispDTEEvents_OnBeginShutdownEventHandler(this.OnBeginShutdown);
dteEvents.OnMacrosRuntimeReset += new _dispDTEEvents_OnMacrosRuntimeResetEventHandler(this.OnMacrosRuntimeReset);
dteEvents.OnStartupComplete += new _dispDTEEvents_OnStartupCompleteEventHandler(this.OnStartupComplete);
documentEvents.DocumentClosing += new _dispDocumentEvents_DocumentClosingEventHandler(this.DocumentClosing);
documentEvents.DocumentOpened += new _dispDocumentEvents_DocumentOpenedEventHandler(this.DocumentOpened);
documentEvents.DocumentOpening += new _dispDocumentEvents_DocumentOpeningEventHandler(this.DocumentOpening);
documentEvents.DocumentSaved += new _dispDocumentEvents_DocumentSavedEventHandler(this.DocumentSaved);
debuggerEvents.OnContextChanged += new _dispDebuggerEvents_OnContextChangedEventHandler(this.OnContextChanged);
debuggerEvents.OnEnterBreakMode += new _dispDebuggerEvents_OnEnterBreakModeEventHandler(this.OnEnterBreakMode);
debuggerEvents.OnEnterDesignMode += new _dispDebuggerEvents_OnEnterDesignModeEventHandler(this.OnEnterDesignMode);
debuggerEvents.OnEnterRunMode += new _dispDebuggerEvents_OnEnterRunModeEventHandler(this.OnEnterRunMode);
debuggerEvents.OnExceptionNotHandled += new _dispDebuggerEvents_OnExceptionNotHandledEventHandler(this.OnExceptionNotHandled);
debuggerEvents.OnExceptionThrown += new _dispDebuggerEvents_OnExceptionThrownEventHandler(this.OnExceptionThrown);
commandEvents.AfterExecute += new _dispCommandEvents_AfterExecuteEventHandler(this.AfterExecute);
commandEvents.BeforeExecute += new _dispCommandEvents_BeforeExecuteEventHandler(this.BeforeExecute);
buildEvents.OnBuildBegin += new _dispBuildEvents_OnBuildBeginEventHandler(this.OnBuildBegin);
buildEvents.OnBuildDone += new _dispBuildEvents_OnBuildDoneEventHandler(this.OnBuildDone);
buildEvents.OnBuildProjConfigBegin += new _dispBuildEvents_OnBuildProjConfigBeginEventHandler(this.OnBuildProjConfigBegin);
buildEvents.OnBuildProjConfigDone += new _dispBuildEvents_OnBuildProjConfigDoneEventHandler(this.OnBuildProjConfigDone);
miscFilesEvents.ItemAdded += new _dispProjectItemsEvents_ItemAddedEventHandler(this.MiscFilesEvents_ItemAdded);
miscFilesEvents.ItemRemoved += new _dispProjectItemsEvents_ItemRemovedEventHandler(this.MiscFilesEvents_ItemRemoved);
miscFilesEvents.ItemRenamed += new _dispProjectItemsEvents_ItemRenamedEventHandler(this.MiscFilesEvents_ItemRenamed);
solutionItemsEvents.ItemAdded += new _dispProjectItemsEvents_ItemAddedEventHandler(this.SolutionItemsEvents_ItemAdded);
solutionItemsEvents.ItemRemoved += new _dispProjectItemsEvents_ItemRemovedEventHandler(this.SolutionItemsEvents_ItemRemoved);
solutionItemsEvents.ItemRenamed += new _dispProjectItemsEvents_ItemRenamedEventHandler(this.SolutionItemsEvents_ItemRenamed);
sorry.... or may be try to Google for KeyEvents with the DTE