📄 menucontrol.cs
字号:
_popupMenu.TrackPopup(screenPos,
aboveScreenPos,
_direction,
dc.MenuCommand.MenuCommands,
borderGap,
selectFirst,
this,
ref returnDir);
// Generate event so that caller has chance to modify MenuCommand contents
OnPopupEnd(dc.MenuCommand);
}
// Remove unwanted object
_popupMenu = null;
// Was arrow key used to dismiss the submenu?
if (returnDir != 0)
{
// Using keyboard movements means we should have the focus
if (!_manualFocus)
{
_manualFocus = true;
GrabTheFocus();
}
if (returnDir < 0)
{
// Shift selection left one
ProcessMoveLeft(true);
}
else
{
// Shift selection right one
ProcessMoveRight(true);
}
// A WM_MOUSEMOVE is generated when we open up the new submenu for
// display, ignore this as it causes the selection to move
_ignoreMouseMove = true;
}
else
{
// Only if the submenu was dismissed at the request of the submenu
// should the selection mode be cancelled, otherwise keep selection mode
if (!_dismissTransfer)
{
// This item is no longer selected
_selected = false;
_drawUpwards = false;
// Should we stop tracking this item
if (trackRemove)
{
ReturnTheFocus();
// Unselect the current item
_trackItem = SwitchTrackingItem(_trackItem, -1);
}
else
{
// Repaint the item
DrawCommand(_trackItem, true);
}
}
else
{
// Do not change _selected status
_dismissTransfer = false;
}
}
}
protected void GrabTheFocus()
{
// Remember the current focus location
_oldFocus = WindowsAPI.GetFocus();
// Grab the focus
this.Focus();
}
protected void ReturnTheFocus()
{
// Do we remember where it came from?
if (_oldFocus != IntPtr.Zero)
{
// Send the focus back
WindowsAPI.SetFocus(_oldFocus);
// No need to remember old focus anymore
_oldFocus = IntPtr.Zero;
}
// We lost the focus
_manualFocus = false;
}
protected override void OnLostFocus(EventArgs e)
{
// We lost the focus
_manualFocus = false;
// Remove tracking of any item
_trackItem = SwitchTrackingItem(_trackItem, -1);
// No need to remember old focus anymore
_oldFocus = IntPtr.Zero;
// When we lose focus we sometimes miss the WM_MOUSELEAVE message
_mouseOver = false;
base.OnLostFocus(e);
}
protected override void OnPaint(PaintEventArgs e)
{
DrawAllCommands(e.Graphics);
base.OnPaint(e);
}
protected override void OnKeyDown(KeyEventArgs e)
{
switch(e.KeyCode)
{
case Keys.Escape:
// Is an item being tracked
if (_trackItem != -1)
{
// Is that item also selected
if (_selected)
{
// Is it also showing a submenu
if (_popupMenu == null)
{
// Deselect the item
_selected = false;
_drawUpwards = false;
// Repaint the item
DrawCommand(_trackItem, true);
ReturnTheFocus();
// Key has been processed
e.Handled = true;
}
else
{
// The popup menu will swallow the escape
_ignoreEscapeUp = true;
}
}
}
break;
case Keys.Left:
if (_direction == Direction.Horizontal)
ProcessMoveLeft(false);
if (_selected)
_ignoreMouseMove = true;
break;
case Keys.Right:
if (_direction == Direction.Horizontal)
ProcessMoveRight(false);
else
ProcessMoveDown();
if (_selected)
_ignoreMouseMove = true;
break;
case Keys.Down:
if (_direction == Direction.Horizontal)
ProcessMoveDown();
else
ProcessMoveRight(false);
break;
case Keys.Up:
if (_direction == Direction.Vertical)
ProcessMoveLeft(false);
break;
}
base.OnKeyDown(e);
}
protected override void OnKeyUp(KeyEventArgs e)
{
switch(e.KeyCode)
{
case Keys.Escape:
if (_manualFocus)
{
if (!_selected)
{
// Did we see the key down for escape? If not then the
// escape must have been used to dismiss a popup menu
if (!_ignoreEscapeUp)
{
// No longer in manual focus mode
_manualFocus = false;
// Remove tracking of any item
_trackItem = SwitchTrackingItem(_trackItem, -1);
// Send the focus back to origin
ReturnTheFocus();
}
}
}
_ignoreEscapeUp = false;
break;
default:
ProcessMnemonicKey((char)e.KeyValue);
if (_selected)
_ignoreMouseMove = true;
break;
}
base.OnKeyUp(e);
}
protected void ProcessMoveLeft(bool select)
{
if (_popupMenu == null)
{
int newItem = _trackItem;
int startItem = newItem;
for(int i=0; i<_drawCommands.Count; i++)
{
// Move to previous item
newItem--;
// Have we looped all the way around all choices
if (newItem == startItem)
return;
// Check limits
if (newItem < 0)
newItem = _drawCommands.Count - 1;
DrawCommand dc = _drawCommands[newItem] as DrawCommand;
// Can we select this item?
if (!dc.Separator && (dc.Chevron || dc.MenuCommand.Enabled))
{
// If a change has occured
if (newItem != _trackItem)
{
// Modify the display of the two items
_trackItem = SwitchTrackingItem(_trackItem, newItem);
if (_selected)
{
if (dc.Chevron || (dc.MenuCommand.MenuCommands.Count > 0))
WindowsAPI.PostMessage(this.Handle, WM_OPERATEMENU, 0, 1);
}
break;
}
}
}
}
}
protected void ProcessMoveRight(bool select)
{
if (_popupMenu == null)
{
int newItem = _trackItem;
int startItem = newItem;
for(int i=0; i<_drawCommands.Count; i++)
{
// Move to previous item
newItem++;
// Check limits
if (newItem >= _drawCommands.Count)
newItem = 0;
DrawCommand dc = _drawCommands[newItem] as DrawCommand;
// Can we select this item?
if (!dc.Separator && (dc.Chevron || dc.MenuCommand.Enabled))
{
// If a change has occured
if (newItem != _trackItem)
{
// Modify the display of the two items
_trackItem = SwitchTrackingItem(_trackItem, newItem);
if (_selected)
{
if (dc.Chevron || (dc.MenuCommand.MenuCommands.Count > 0))
WindowsAPI.PostMessage(this.Handle, WM_OPERATEMENU, 0, 1);
}
break;
}
}
}
}
}
protected void ProcessMoveDown()
{
if (_popupMenu == null)
{
// Are we tracking an item?
if (_trackItem != -1)
{
// The item must not already be selected
if (!_selected)
{
DrawCommand dc = _drawCommands[_trackItem] as DrawCommand;
// Is there a submenu to show?
if (dc.Chevron || (dc.MenuCommand.MenuCommands.Count > 0))
{
// Select the tracked item
_selected = true;
_drawUpwards = false;
// Update display to show as selected
DrawCommand(_trackItem, true);
// Show the submenu
WindowsAPI.PostMessage(this.Handle, WM_OPERATEMENU, 0, 1);
}
}
}
}
}
protected bool ProcessMnemonicKey(char key)
{
// We should always gain focus
if (!_manualFocus)
{
// We keep the focus until they move it
_manualFocus = true;
GrabTheFocus();
}
// No current selection
if (!_selected)
{
// Search for an item that matches
for(int i=0; i<_drawCommands.Count; i++)
{
DrawCommand dc = _drawCommands[i] as DrawCommand;
// Only interested in enabled items
if ((dc.MenuCommand != null) && dc.MenuCommand.Enabled)
{
// Does the character match?
if (key == dc.Mnemonic)
{
// Select the tracked item
_selected = true;
_drawUpwards = false;
// Is there a change in tracking?
if (_trackItem != i)
{
// Modify the display of the two items
_trackItem = SwitchTrackingItem(_trackItem, i);
}
else
{
// Update display to show as selected
DrawCommand(_trackItem, true);
}
// Is there a submenu to show?
if (dc.Chevron || (dc.MenuCommand.MenuCommands.Count > 0))
WindowsAPI.PostMessage(this.Handle, WM_OPERATEMENU, 0, 1);
else
{
// No, pulse the Click event for the command
dc.MenuCommand.OnClick(EventArgs.Empty);
}
return true;
}
}
}
}
return false;
}
public bool PreFilterMessage(ref Message msg)
{
Form parentForm = this.FindForm();
// Only interested if the Form we are on is activate (i.e. contains focus)
if ((parentForm != null) && parentForm.ContainsFocus)
{
switch(msg.Msg)
{
case (int)Win32.Msg.WM_MDISETMENU:
case (int)Win32.Msg.WM_MDIREFRESHMENU:
return true;
case (int)Win32.Msg.WM_KEYUP:
{
// Find up/down state of shift and control keys
ushort shiftKey = WindowsAPI.GetKeyState((int)Win32.VirtualKeys.VK_SHIFT);
ushort controlKey = WindowsAPI.GetKeyState((int)Win32.VirtualKeys.VK_CONTROL);
// Basic code we are looking for is the key pressed...
int code = (int)msg.WParam;
// ...plus the modifier for SHIFT...
if (((int)shiftKey & 0x00008000) != 0)
code += 0x00010000;
// ...plus the modifier for CONTROL
if (((int)controlKey & 0x00008000) != 0)
code += 0x00020000;
// Construct shortcut from keystate and keychar
Shortcut sc = (Shortcut)(code);
// Search for a matching command
return GenerateShortcut(sc, _menuCommands);
}
case (int)Win32.Msg.WM_SYSKEYUP:
if ((int)msg.WParam == (int)Win32.VirtualKeys.VK_MENU)
{
// If not already in manual focus mode
if (!_manualFocus)
{
// Are there any menu commands?
if (_drawCommands.Count > 0)
{
// If no item is currently tracked then...
if (_trackItem == -1)
{
// ...start tracking the first valid command
for(int i=0; i<_drawCommands.Count; i++)
{
DrawCommand dc = _drawCommands[i] as DrawCommand;
if (!dc.Separator && (dc.Chevron || dc.MenuCommand.Enabled))
{
_trackItem = SwitchTrackingItem(-1, i);
break;
}
}
}
// We keep the focus until they move it
_manualFocus = true;
// Grab the focus for key events
GrabTheFocus();
}
return true;
}
}
else
{
// Construct shortcut from ALT + keychar
Shortcut sc = (Shortcut)(0x00040000 + (int)msg.WParam);
if (GenerateShortcut(sc, _menuCommands))
return true;
// Last resort is treat as a potential mnemonic
return ProcessMnemonicKey((char)msg.WParam);
}
break;
default:
break;
}
}
return false;
}
protected bool GenerateShortcut(Shortcut sc, MenuCommandCollection mcc)
{
foreach(MenuCommand mc in mcc)
{
// Does the command match?
if (mc.Enabled && (mc.Shortcut == sc))
{
// Generate event for command
mc.OnClick(EventArgs.Empty);
return true;
}
else
{
// Any child items to test?
if (mc.MenuCommands.Count > 0)
{
// Recursive descent of all collections
if (GenerateShortcut(sc, mc.MenuCommands))
return true;
}
}
}
return false;
}
protected void OnWM_OPERATEMENU(ref Message m)
{
// Is there a valid item being tracted?
if (_trackItem != -1)
{
DrawCommand dc = _drawCommands[_trackItem] as DrawCommand;
OperateSubMenu(dc, (m.LParam != IntPtr.Zero), (m.WParam != IntPtr.Zero));
}
}
protected void OnWM_GETDLGCODE(ref Message m)
{
// We want to the Form to provide all keyboard input to us
m.Result = (IntPtr)Win32.DialogCodes.DLGC_WANTALLKEYS;
}
protected override void WndProc(ref Message m)
{
// WM_OPERATEMENU is not a constant and so cannot be in a switch
if (m.Msg == WM_OPERATEMENU)
OnWM_OPERATEMENU(ref m);
else
{
switch(m.Msg)
{
case (int)Win32.Msg.WM_GETDLGCODE:
OnWM_GETDLGCODE(ref m);
return;
}
}
base.WndProc(ref m);
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -