mirror of
https://github.com/Hofknecht/SystemTrayMenu.git
synced 2024-09-30 09:06:32 +13:00
bugfixes related to fast open closes of stm, refactor KeyboardInput, refactor explorer sort, other minor refactor, version 254
This commit is contained in:
parent
0023079bb1
commit
120bb1274d
11 changed files with 512 additions and 472 deletions
4
Controls/Menu.Designer.cs
generated
4
Controls/Menu.Designer.cs
generated
|
@ -34,7 +34,7 @@ namespace SystemTrayMenu
|
||||||
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle3 = new System.Windows.Forms.DataGridViewCellStyle();
|
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle3 = new System.Windows.Forms.DataGridViewCellStyle();
|
||||||
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle();
|
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle();
|
||||||
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle2 = new System.Windows.Forms.DataGridViewCellStyle();
|
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle2 = new System.Windows.Forms.DataGridViewCellStyle();
|
||||||
this.labelTitle = new SystemTrayMenu.LabelNoCopy();
|
this.labelTitle = new global::SystemTrayMenu.LabelNoCopy();
|
||||||
this.dgv = new System.Windows.Forms.DataGridView();
|
this.dgv = new System.Windows.Forms.DataGridView();
|
||||||
this.ColumnIcon = new System.Windows.Forms.DataGridViewImageColumn();
|
this.ColumnIcon = new System.Windows.Forms.DataGridViewImageColumn();
|
||||||
this.ColumnText = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
this.ColumnText = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||||
|
@ -174,7 +174,7 @@ namespace SystemTrayMenu
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
private SystemTrayMenu.LabelNoCopy labelTitle;
|
private global::SystemTrayMenu.LabelNoCopy labelTitle;
|
||||||
private System.Windows.Forms.DataGridView dgv;
|
private System.Windows.Forms.DataGridView dgv;
|
||||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel;
|
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel;
|
||||||
private System.Windows.Forms.DataGridViewImageColumn ColumnIcon;
|
private System.Windows.Forms.DataGridViewImageColumn ColumnIcon;
|
||||||
|
|
|
@ -11,6 +11,7 @@ using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
using SystemTrayMenu.Handler;
|
||||||
using SystemTrayMenu.Helper;
|
using SystemTrayMenu.Helper;
|
||||||
using TAFactory.IconPack;
|
using TAFactory.IconPack;
|
||||||
|
|
||||||
|
|
422
Handler/KeyboardInput.cs
Normal file
422
Handler/KeyboardInput.cs
Normal file
|
@ -0,0 +1,422 @@
|
||||||
|
using Clearcove.Logging;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using SystemTrayMenu.Controls;
|
||||||
|
using SystemTrayMenu.Helper;
|
||||||
|
|
||||||
|
namespace SystemTrayMenu.Handler
|
||||||
|
{
|
||||||
|
class KeyboardInput : IDisposable
|
||||||
|
{
|
||||||
|
public event EventHandler HotKeyPressed;
|
||||||
|
public event EventHandler ClosePressed;
|
||||||
|
public Action<DataGridView, int> RowSelected;
|
||||||
|
public Action<int, int, DataGridView> RowDeselected;
|
||||||
|
public event EventHandler Cleared;
|
||||||
|
|
||||||
|
Logger log = new Logger(nameof(KeyboardInput));
|
||||||
|
private Menu[] menus;
|
||||||
|
|
||||||
|
KeyboardHook hook = new KeyboardHook();
|
||||||
|
Timer timerKeySearch = new Timer();
|
||||||
|
public int iRowKey = -1;
|
||||||
|
public int iMenuKey = 0;
|
||||||
|
string KeySearchString = string.Empty;
|
||||||
|
|
||||||
|
public KeyboardInput(Menu[] menus)
|
||||||
|
{
|
||||||
|
this.menus = menus;
|
||||||
|
|
||||||
|
timerKeySearch.Interval = MenuDefines.KeySearchInterval;
|
||||||
|
timerKeySearch.Tick += TimerKeySearch_Tick;
|
||||||
|
void TimerKeySearch_Tick(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
// this search has expired, reset search
|
||||||
|
timerKeySearch.Stop();
|
||||||
|
KeySearchString = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
hook.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void RegisterHotKey()
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(Properties.Settings.Default.HotKey))
|
||||||
|
{
|
||||||
|
var cvt = new KeysConverter();
|
||||||
|
var key = (Keys)cvt.ConvertFrom(
|
||||||
|
Properties.Settings.Default.HotKey);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
hook.RegisterHotKey(
|
||||||
|
KeyboardHookModifierKeys.Control |
|
||||||
|
KeyboardHookModifierKeys.Alt,
|
||||||
|
key);
|
||||||
|
hook.KeyPressed += hook_KeyPressed;
|
||||||
|
void hook_KeyPressed(object sender, KeyPressedEventArgs e)
|
||||||
|
{
|
||||||
|
HotKeyPressed?.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
log.Info($"key:'{key.ToString()}'");
|
||||||
|
log.Error($"{ex.ToString()}");
|
||||||
|
Properties.Settings.Default.HotKey = string.Empty;
|
||||||
|
Properties.Settings.Default.Save();
|
||||||
|
MessageBox.Show(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void ResetSelectedByKey()
|
||||||
|
{
|
||||||
|
iRowKey = -1;
|
||||||
|
iMenuKey = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void CmdKeyProcessed(Keys keys)
|
||||||
|
{
|
||||||
|
SelectByKey(keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// While menu is open user presses a key to search for specific entries.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender">not used</param>
|
||||||
|
/// <param name="e">Key data of the pressed key</param>
|
||||||
|
internal void KeyPress(object sender, KeyPressEventArgs e)
|
||||||
|
{
|
||||||
|
if (char.IsLetterOrDigit(e.KeyChar) ||
|
||||||
|
char.IsPunctuation(e.KeyChar) ||
|
||||||
|
char.IsWhiteSpace(e.KeyChar) ||
|
||||||
|
char.IsSeparator(e.KeyChar))
|
||||||
|
{
|
||||||
|
string letter = e.KeyChar.ToString();
|
||||||
|
|
||||||
|
timerKeySearch.Stop();
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(KeySearchString))
|
||||||
|
{
|
||||||
|
// no search string set, start new search with initial letter
|
||||||
|
KeySearchString += letter;
|
||||||
|
SelectByKey(Keys.None, KeySearchString);
|
||||||
|
}
|
||||||
|
else if (KeySearchString.Length == 1 && KeySearchString.LastOrDefault().ToString() == letter)
|
||||||
|
{
|
||||||
|
// initial letter pressed again, jump to next element
|
||||||
|
SelectByKey(Keys.None, letter);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// new character for the search string, narrow down the search
|
||||||
|
KeySearchString += letter;
|
||||||
|
SelectByKey(Keys.None, KeySearchString, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// give user some time to continue with this search
|
||||||
|
timerKeySearch.Start();
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool IsAnyMenuSelectedByKey()
|
||||||
|
{
|
||||||
|
Menu menu = null;
|
||||||
|
DataGridView dgv = null;
|
||||||
|
string textselected = string.Empty;
|
||||||
|
return IsAnyMenuSelectedByKey(ref dgv, ref menu, ref textselected);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsAnyMenuSelectedByKey(
|
||||||
|
ref DataGridView dgv,
|
||||||
|
ref Menu menuFromSelected,
|
||||||
|
ref string textselected)
|
||||||
|
{
|
||||||
|
Menu menu = menus[iMenuKey];
|
||||||
|
bool isStillSelected = false;
|
||||||
|
if (menu != null &&
|
||||||
|
iRowKey > -1)
|
||||||
|
{
|
||||||
|
dgv = menu.GetDataGridView();
|
||||||
|
if (dgv.Rows.Count > iRowKey)
|
||||||
|
{
|
||||||
|
RowData rowData = (RowData)dgv.
|
||||||
|
Rows[iRowKey].Tag;
|
||||||
|
if (rowData.IsSelectedByKeyboard)
|
||||||
|
{
|
||||||
|
isStillSelected = true;
|
||||||
|
menuFromSelected = rowData.SubMenu;
|
||||||
|
#warning refactor datagridviewrow get
|
||||||
|
textselected = dgv.Rows[iRowKey].
|
||||||
|
Cells[1].Value.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return isStillSelected;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SelectByKey(Keys keys, string keyInput = "", bool KeepSelection = false)
|
||||||
|
{
|
||||||
|
int iRowBefore = iRowKey;
|
||||||
|
int iMenuBefore = iMenuKey;
|
||||||
|
|
||||||
|
Menu menu = menus[iMenuKey];
|
||||||
|
DataGridView dgv = null;
|
||||||
|
DataGridView dgvBefore = null;
|
||||||
|
Menu menuFromSelected = null;
|
||||||
|
string textselected = string.Empty;
|
||||||
|
bool isStillSelected = IsAnyMenuSelectedByKey(ref dgv, ref menuFromSelected, ref textselected);
|
||||||
|
if (isStillSelected)
|
||||||
|
{
|
||||||
|
if (KeepSelection)
|
||||||
|
{
|
||||||
|
// Is current selection is still valid for this search then skip selecting different item
|
||||||
|
if (textselected.ToLower().StartsWith(keyInput.ToLower()))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dgvBefore = dgv;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ResetSelectedByKey();
|
||||||
|
menu = menus[iMenuKey];
|
||||||
|
dgv = menu.GetDataGridView();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool toClear = false;
|
||||||
|
switch (keys)
|
||||||
|
{
|
||||||
|
case Keys.Enter:
|
||||||
|
if (iRowKey > -1 &&
|
||||||
|
dgv.Rows.Count > iRowKey)
|
||||||
|
{
|
||||||
|
RowData trigger = (RowData)dgv.Rows[iRowKey].Tag;
|
||||||
|
trigger.MouseDown(dgv, null);
|
||||||
|
//trigger.DoubleClick();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Keys.Up:
|
||||||
|
if (SelectMatchedReverse(dgv, iRowKey) ||
|
||||||
|
SelectMatchedReverse(dgv, dgv.Rows.Count - 1))
|
||||||
|
{
|
||||||
|
RowDeselected(iMenuBefore, iRowBefore, dgvBefore);
|
||||||
|
RowSelected(dgv, iRowKey);
|
||||||
|
toClear = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Keys.Down:
|
||||||
|
if (SelectMatched(dgv, iRowKey) ||
|
||||||
|
SelectMatched(dgv, 0))
|
||||||
|
{
|
||||||
|
RowDeselected(iMenuBefore, iRowBefore, dgvBefore);
|
||||||
|
RowSelected(dgv, iRowKey);
|
||||||
|
toClear = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Keys.Left:
|
||||||
|
int iMenuKeyNext = iMenuKey + 1;
|
||||||
|
if (isStillSelected)
|
||||||
|
{
|
||||||
|
if (menuFromSelected != null &&
|
||||||
|
menuFromSelected == menus[iMenuKeyNext])
|
||||||
|
{
|
||||||
|
dgv = menuFromSelected.GetDataGridView();
|
||||||
|
if (dgv.Rows.Count > 0)
|
||||||
|
{
|
||||||
|
iMenuKey += 1;
|
||||||
|
iRowKey = -1;
|
||||||
|
if (SelectMatched(dgv, iRowKey) ||
|
||||||
|
SelectMatched(dgv, 0))
|
||||||
|
{
|
||||||
|
RowDeselected(iMenuBefore,
|
||||||
|
iRowBefore, dgvBefore);
|
||||||
|
RowSelected(dgv, iRowKey);
|
||||||
|
toClear = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
iRowKey = -1;
|
||||||
|
iMenuKey = menus.Where(m => m != null).Count() - 1;
|
||||||
|
if (menus[iMenuKey] != null)
|
||||||
|
{
|
||||||
|
dgv = menus[iMenuKey].GetDataGridView();
|
||||||
|
if (SelectMatched(dgv, iRowKey) ||
|
||||||
|
SelectMatched(dgv, 0))
|
||||||
|
{
|
||||||
|
RowDeselected(iMenuBefore, iRowBefore, dgvBefore);
|
||||||
|
RowSelected(dgv, iRowKey);
|
||||||
|
toClear = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log.Info("indexMenuByKey = menus.Where(m => m != null).Count()" +
|
||||||
|
"=> menus[iMenuKey] == null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Keys.Right:
|
||||||
|
if (iMenuKey > 0)
|
||||||
|
{
|
||||||
|
if (menus[iMenuKey - 1] != null)
|
||||||
|
{
|
||||||
|
iMenuKey -= 1;
|
||||||
|
iRowKey = -1;
|
||||||
|
menu = menus[iMenuKey];
|
||||||
|
dgv = menu.GetDataGridView();
|
||||||
|
if (SelectMatched(dgv, dgv.SelectedRows[0].Index) ||
|
||||||
|
SelectMatched(dgv, 0))
|
||||||
|
{
|
||||||
|
RowDeselected(iMenuBefore, iRowBefore, dgvBefore);
|
||||||
|
RowSelected(dgv, iRowKey);
|
||||||
|
toClear = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RowDeselected(iMenuBefore, iRowBefore, dgvBefore);
|
||||||
|
iMenuKey = 0;
|
||||||
|
iRowKey = -1;
|
||||||
|
toClear = true;
|
||||||
|
Cleared?.Invoke();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Keys.Escape:
|
||||||
|
RowDeselected(iMenuBefore, iRowBefore, dgvBefore);
|
||||||
|
iMenuKey = 0;
|
||||||
|
iRowKey = -1;
|
||||||
|
toClear = true;
|
||||||
|
ClosePressed?.Invoke();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (!string.IsNullOrEmpty(keyInput))
|
||||||
|
{
|
||||||
|
if (SelectMatched(dgv, iRowKey, keyInput) ||
|
||||||
|
SelectMatched(dgv, 0, keyInput))
|
||||||
|
{
|
||||||
|
RowDeselected(iMenuBefore, iRowBefore, null);
|
||||||
|
RowSelected(dgv, iRowKey);
|
||||||
|
toClear = true;
|
||||||
|
}
|
||||||
|
else if (isStillSelected)
|
||||||
|
{
|
||||||
|
iRowKey = iRowBefore - 1;
|
||||||
|
if (SelectMatched(dgv, iRowKey, keyInput) ||
|
||||||
|
SelectMatched(dgv, 0, keyInput))
|
||||||
|
{
|
||||||
|
RowDeselected(iMenuBefore, iRowBefore, null);
|
||||||
|
RowSelected(dgv, iRowKey);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
iRowKey = iRowBefore;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (isStillSelected && toClear)
|
||||||
|
{
|
||||||
|
ClearIsSelectedByKey(iMenuBefore, iRowBefore);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool SelectMatched(DataGridView dgv,
|
||||||
|
int indexStart, string keyInput = "")
|
||||||
|
{
|
||||||
|
bool found = false;
|
||||||
|
for (int i = indexStart; i < dgv.Rows.Count; i++)
|
||||||
|
{
|
||||||
|
if (Select(dgv, i, keyInput))
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool SelectMatchedReverse(DataGridView dgv,
|
||||||
|
int indexStart, string keyInput = "")
|
||||||
|
{
|
||||||
|
bool found = false;
|
||||||
|
for (int i = indexStart; i > -1; i--)
|
||||||
|
{
|
||||||
|
if (Select(dgv, i, keyInput))
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool Select(DataGridView dgv, int i,
|
||||||
|
string keyInput = "")
|
||||||
|
{
|
||||||
|
bool found = false;
|
||||||
|
if (i > -1 &&
|
||||||
|
i != iRowKey &&
|
||||||
|
dgv.Rows.Count > i)
|
||||||
|
{
|
||||||
|
DataGridViewRow row = dgv.Rows[i];
|
||||||
|
RowData rowData = (RowData)row.Tag;
|
||||||
|
string text = row.Cells[1].Value.ToString();
|
||||||
|
if (text.ToLower().StartsWith(keyInput.ToLower()))
|
||||||
|
{
|
||||||
|
iRowKey = rowData.RowIndex;
|
||||||
|
rowData.IsSelectedByKeyboard = true;
|
||||||
|
row.Selected = false; //event trigger
|
||||||
|
row.Selected = true; //event trigger
|
||||||
|
if (row.Index < dgv.FirstDisplayedScrollingRowIndex)
|
||||||
|
{
|
||||||
|
dgv.FirstDisplayedScrollingRowIndex = row.Index;
|
||||||
|
}
|
||||||
|
else if (row.Index >=
|
||||||
|
dgv.FirstDisplayedScrollingRowIndex +
|
||||||
|
dgv.DisplayedRowCount(false))
|
||||||
|
{
|
||||||
|
dgv.FirstDisplayedScrollingRowIndex = row.Index -
|
||||||
|
dgv.DisplayedRowCount(false) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void ClearIsSelectedByKey()
|
||||||
|
{
|
||||||
|
ClearIsSelectedByKey(iMenuKey, iRowKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ClearIsSelectedByKey(int menuIndex, int rowIndex)
|
||||||
|
{
|
||||||
|
Menu menu = menus[menuIndex];
|
||||||
|
if (menu != null && rowIndex > -1)
|
||||||
|
{
|
||||||
|
DataGridView dgv = menu.GetDataGridView();
|
||||||
|
if (dgv.Rows.Count > rowIndex)
|
||||||
|
{
|
||||||
|
DataGridViewRow row = dgv.Rows[rowIndex];
|
||||||
|
RowData rowData = (RowData)row.Tag;
|
||||||
|
rowData.IsSelectedByKeyboard = false;
|
||||||
|
row.Selected = false; //event trigger
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using Timer = System.Windows.Forms.Timer;
|
using Timer = System.Windows.Forms.Timer;
|
||||||
|
|
||||||
namespace SystemTrayMenu.Helper
|
namespace SystemTrayMenu.Handler
|
||||||
{
|
{
|
||||||
class WaitFastLeave : IDisposable
|
class WaitFastLeave : IDisposable
|
||||||
{
|
{
|
|
@ -1,7 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using Timer = System.Windows.Forms.Timer;
|
using Timer = System.Windows.Forms.Timer;
|
||||||
|
|
||||||
namespace SystemTrayMenu.Helper
|
namespace SystemTrayMenu.Handler
|
||||||
{
|
{
|
||||||
class WaitMenuOpen : IDisposable
|
class WaitMenuOpen : IDisposable
|
||||||
{
|
{
|
|
@ -1,29 +0,0 @@
|
||||||
using System.Windows.Forms;
|
|
||||||
|
|
||||||
namespace SystemTrayMenu.Helper
|
|
||||||
{
|
|
||||||
public class ScreenMouse
|
|
||||||
{
|
|
||||||
public static Screen GetScreen()
|
|
||||||
{
|
|
||||||
return Screen.PrimaryScreen;
|
|
||||||
// Maybe we need for later feature
|
|
||||||
// Show on mouse position
|
|
||||||
//return GetScreenFromMousePosition(
|
|
||||||
// Cursor.Position.X, Cursor.Position.Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
//public static Screen GetScreenFromMousePosition(int x, int y)
|
|
||||||
//{
|
|
||||||
// Screen clickedScreen = null;
|
|
||||||
// foreach (Screen screen in Screen.AllScreens)
|
|
||||||
// {
|
|
||||||
// if (screen.Bounds.Contains(new Point(x, y)))
|
|
||||||
// {
|
|
||||||
// clickedScreen = screen;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return clickedScreen;
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
}
|
|
17
Helper/WindowsExplorerSort.cs
Normal file
17
Helper/WindowsExplorerSort.cs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace SystemTrayMenu.Helper
|
||||||
|
{
|
||||||
|
class WindowsExplorerSort : IComparer<string>
|
||||||
|
{
|
||||||
|
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
|
||||||
|
static extern int StrCmpLogicalW(String x, String y);
|
||||||
|
|
||||||
|
public int Compare(string x, string y)
|
||||||
|
{
|
||||||
|
return StrCmpLogicalW(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -55,8 +55,7 @@ namespace SystemTrayMenu
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
bool cancelAppRun = false;
|
bool cancelAppRun = false;
|
||||||
using (SystemTrayMenuHandler stm =
|
using (new SystemTrayMenu(ref cancelAppRun))
|
||||||
new SystemTrayMenuHandler(ref cancelAppRun))
|
|
||||||
{
|
{
|
||||||
if (!cancelAppRun)
|
if (!cancelAppRun)
|
||||||
{
|
{
|
||||||
|
|
|
@ -31,5 +31,5 @@ using System.Runtime.InteropServices;
|
||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
// by using the '*' as shown below:
|
// by using the '*' as shown below:
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
[assembly: AssemblyVersion("0.9.1.253")]
|
[assembly: AssemblyVersion("0.9.1.254")]
|
||||||
[assembly: AssemblyFileVersion("0.9.1.253")]
|
[assembly: AssemblyFileVersion("0.9.1.254")]
|
||||||
|
|
|
@ -8,9 +8,9 @@ using System.Drawing;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using SystemTrayMenu.Controls;
|
using SystemTrayMenu.Controls;
|
||||||
|
using SystemTrayMenu.Handler;
|
||||||
using SystemTrayMenu.Helper;
|
using SystemTrayMenu.Helper;
|
||||||
|
|
||||||
namespace SystemTrayMenu
|
namespace SystemTrayMenu
|
||||||
|
@ -19,21 +19,19 @@ namespace SystemTrayMenu
|
||||||
//MethodBase m = MethodBase.GetCurrentMethod();
|
//MethodBase m = MethodBase.GetCurrentMethod();
|
||||||
//log.Debug($"Executing {m.ReflectedType.Name}, {m.Name}");
|
//log.Debug($"Executing {m.ReflectedType.Name}, {m.Name}");
|
||||||
#endregion
|
#endregion
|
||||||
class SystemTrayMenuHandler : IDisposable
|
class SystemTrayMenu : IDisposable
|
||||||
{
|
{
|
||||||
Logger log = new Logger(nameof(SystemTrayMenuHandler));
|
Logger log = new Logger(nameof(SystemTrayMenu));
|
||||||
|
|
||||||
IShellDispatch4 iShellDispatch4 = null;
|
IShellDispatch4 iShellDispatch4 = null;
|
||||||
|
|
||||||
KeyboardHook hook = new KeyboardHook();
|
MessageFilter messageFilter = new MessageFilter();
|
||||||
Timer timerKeySearch = new Timer();
|
bool messageFilterAdded = false;
|
||||||
int iRowKey = -1;
|
|
||||||
int iMenuKey = 0;
|
|
||||||
string KeySearchString = string.Empty;
|
|
||||||
|
|
||||||
MenuNotifyIcon menuNotifyIcon = null;
|
MenuNotifyIcon menuNotifyIcon = null;
|
||||||
WaitFastLeave fastLeave = new WaitFastLeave();
|
WaitFastLeave fastLeave = new WaitFastLeave();
|
||||||
Menu[] menus = new Menu[MenuDefines.MenusMax];
|
Menu[] menus = new Menu[MenuDefines.MenusMax];
|
||||||
|
KeyboardInput keyboardInput;
|
||||||
|
|
||||||
enum OpenCloseState { Default, Opening, Closing };
|
enum OpenCloseState { Default, Opening, Closing };
|
||||||
OpenCloseState openCloseState = OpenCloseState.Default;
|
OpenCloseState openCloseState = OpenCloseState.Default;
|
||||||
|
@ -41,7 +39,7 @@ namespace SystemTrayMenu
|
||||||
BackgroundWorker worker = new BackgroundWorker();
|
BackgroundWorker worker = new BackgroundWorker();
|
||||||
Screen screen = null;
|
Screen screen = null;
|
||||||
|
|
||||||
public SystemTrayMenuHandler(ref bool cancelAppRun)
|
public SystemTrayMenu(ref bool cancelAppRun)
|
||||||
{
|
{
|
||||||
log.Info("Application Start " +
|
log.Info("Application Start " +
|
||||||
Assembly.GetExecutingAssembly().
|
Assembly.GetExecutingAssembly().
|
||||||
|
@ -58,42 +56,23 @@ namespace SystemTrayMenu
|
||||||
}
|
}
|
||||||
|
|
||||||
Config.UpgradeIfNotUpgraded();
|
Config.UpgradeIfNotUpgraded();
|
||||||
|
keyboardInput = new KeyboardInput(menus);
|
||||||
if (!string.IsNullOrEmpty(Properties.Settings.Default.HotKey))
|
keyboardInput.RegisterHotKey();
|
||||||
|
keyboardInput.HotKeyPressed += SwitchOpenClose;
|
||||||
|
keyboardInput.ClosePressed += MenusFadeOut;
|
||||||
|
keyboardInput.RowSelected += KeyboardInputRowSelected;
|
||||||
|
void KeyboardInputRowSelected(DataGridView dgv, int rowIndex)
|
||||||
{
|
{
|
||||||
var cvt = new KeysConverter();
|
FadeInIfNeeded();
|
||||||
var key = (Keys)cvt.ConvertFrom(
|
CheckMenuOpenerStart(dgv, rowIndex);
|
||||||
Properties.Settings.Default.HotKey);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
hook.RegisterHotKey(
|
|
||||||
KeyboardHookModifierKeys.Control |
|
|
||||||
KeyboardHookModifierKeys.Alt,
|
|
||||||
key);
|
|
||||||
hook.KeyPressed += hook_KeyPressed;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
log.Info($"key:'{key.ToString()}'");
|
|
||||||
log.Error($"{ex.ToString()}");
|
|
||||||
Properties.Settings.Default.HotKey = string.Empty;
|
|
||||||
Properties.Settings.Default.Save();
|
|
||||||
MessageBox.Show(ex.Message);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
keyboardInput.RowDeselected += CheckMenuOpenerStop;
|
||||||
|
keyboardInput.Cleared += FadeHalfOrOutIfNeeded;
|
||||||
|
|
||||||
menuNotifyIcon = new MenuNotifyIcon();
|
menuNotifyIcon = new MenuNotifyIcon();
|
||||||
|
|
||||||
void hook_KeyPressed(object sender, KeyPressedEventArgs e)
|
|
||||||
{
|
|
||||||
SwitchOpenClose();
|
|
||||||
}
|
|
||||||
|
|
||||||
timerKeySearch.Interval = MenuDefines.KeySearchInterval;
|
|
||||||
timerKeySearch.Tick += TimerKeySearch_Tick;
|
|
||||||
menus[0] = new Menu();
|
menus[0] = new Menu();
|
||||||
menus[0].Dispose();
|
menus[0].Dispose();
|
||||||
MessageFilter messageFilter = new MessageFilter();
|
|
||||||
Application.AddMessageFilter(messageFilter);
|
|
||||||
menuNotifyIcon.Exit += Application.Exit;
|
menuNotifyIcon.Exit += Application.Exit;
|
||||||
|
|
||||||
menuNotifyIcon.HandleClick += SwitchOpenClose;
|
menuNotifyIcon.HandleClick += SwitchOpenClose;
|
||||||
|
@ -113,15 +92,12 @@ namespace SystemTrayMenu
|
||||||
worker.CancelAsync();
|
worker.CancelAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (menus[0].Visible)
|
|
||||||
{
|
|
||||||
openCloseState = OpenCloseState.Default;
|
|
||||||
ActivateMenu();
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
openCloseState = OpenCloseState.Opening;
|
#region NotifyIconIsInteededToBeOutside
|
||||||
screen = ScreenMouse.GetScreen();
|
// Idea is either to show always outside like dropbox
|
||||||
|
// (is nok due to windows rules, maybe only allowed when asking user?)
|
||||||
|
// (or to give at least a hint that drag drop possible?)
|
||||||
//bool IsNotifyIconInTaskbar()
|
//bool IsNotifyIconInTaskbar()
|
||||||
//{
|
//{
|
||||||
// bool isNotifyIconInTaskbar = false;
|
// bool isNotifyIconInTaskbar = false;
|
||||||
|
@ -141,11 +117,18 @@ namespace SystemTrayMenu
|
||||||
// // Program.Translate("buttonOk"));
|
// // Program.Translate("buttonOk"));
|
||||||
// //hintForm.Show();
|
// //hintForm.Show();
|
||||||
//}
|
//}
|
||||||
while (!menus[0].IsDisposed)
|
#endregion
|
||||||
|
|
||||||
|
while (menus[0].Visible &&
|
||||||
|
!menus[0].IsDisposed &&
|
||||||
|
worker.IsBusy)
|
||||||
{
|
{
|
||||||
Application.DoEvents();
|
Application.DoEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openCloseState = OpenCloseState.Opening;
|
||||||
|
screen = Screen.PrimaryScreen;
|
||||||
|
|
||||||
menuNotifyIcon.LoadingStart();
|
menuNotifyIcon.LoadingStart();
|
||||||
worker.RunWorkerAsync();
|
worker.RunWorkerAsync();
|
||||||
}
|
}
|
||||||
|
@ -165,7 +148,7 @@ namespace SystemTrayMenu
|
||||||
void Worker_RunWorkerCompleted(object sender,
|
void Worker_RunWorkerCompleted(object sender,
|
||||||
RunWorkerCompletedEventArgs e)
|
RunWorkerCompletedEventArgs e)
|
||||||
{
|
{
|
||||||
ResetSelectedByKey();
|
keyboardInput.ResetSelectedByKey();
|
||||||
menuNotifyIcon.LoadingStop();
|
menuNotifyIcon.LoadingStop();
|
||||||
MenuData menuData = (MenuData)e.Result;
|
MenuData menuData = (MenuData)e.Result;
|
||||||
if (menuData.Validity == MenuDataValidity.Valid)
|
if (menuData.Validity == MenuDataValidity.Valid)
|
||||||
|
@ -174,6 +157,11 @@ namespace SystemTrayMenu
|
||||||
menus[0].AdjustLocationAndSize(screen);
|
menus[0].AdjustLocationAndSize(screen);
|
||||||
ActivateMenu();
|
ActivateMenu();
|
||||||
menus[0].AdjustLocationAndSize(screen);
|
menus[0].AdjustLocationAndSize(screen);
|
||||||
|
if (!messageFilterAdded)
|
||||||
|
{
|
||||||
|
Application.AddMessageFilter(messageFilter);
|
||||||
|
messageFilterAdded = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,6 +218,7 @@ namespace SystemTrayMenu
|
||||||
cancelAppRun = true;
|
cancelAppRun = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FadeInIfNeeded()
|
void FadeInIfNeeded()
|
||||||
{
|
{
|
||||||
if (menus[0].Visible &&
|
if (menus[0].Visible &&
|
||||||
|
@ -250,12 +239,13 @@ namespace SystemTrayMenu
|
||||||
!Menus().Any(m => m.IsMouseOn(mousePosition));
|
!Menus().Any(m => m.IsMouseOn(mousePosition));
|
||||||
bool isAnyMenuActive = IsAnyMenuActive();
|
bool isAnyMenuActive = IsAnyMenuActive();
|
||||||
|
|
||||||
if (isMouseOnAnyMenu)
|
if (menus[0].Visible &&
|
||||||
|
isMouseOnAnyMenu)
|
||||||
{
|
{
|
||||||
if (isAnyMenuActive &&
|
if (isAnyMenuActive &&
|
||||||
!(openCloseState == OpenCloseState.Closing))
|
!(openCloseState == OpenCloseState.Closing))
|
||||||
{
|
{
|
||||||
if (!IsAnyMenuSelectedByKey())
|
if (!keyboardInput.IsAnyMenuSelectedByKey())
|
||||||
{
|
{
|
||||||
Menus().ToList().ForEach(menu => menu.FadeHalf());
|
Menus().ToList().ForEach(menu => menu.FadeHalf());
|
||||||
}
|
}
|
||||||
|
@ -267,15 +257,9 @@ namespace SystemTrayMenu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ResetSelectedByKey()
|
|
||||||
{
|
|
||||||
iRowKey = -1;
|
|
||||||
iMenuKey = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
hook.Dispose();
|
keyboardInput.Dispose();
|
||||||
menuNotifyIcon.Dispose();
|
menuNotifyIcon.Dispose();
|
||||||
fastLeave.Dispose();
|
fastLeave.Dispose();
|
||||||
DisposeMenu(menus[0]);
|
DisposeMenu(menus[0]);
|
||||||
|
@ -313,7 +297,6 @@ namespace SystemTrayMenu
|
||||||
|
|
||||||
void AdjustSubMenusLocationAndSize()
|
void AdjustSubMenusLocationAndSize()
|
||||||
{
|
{
|
||||||
Screen screen = ScreenMouse.GetScreen();
|
|
||||||
int heightMax = screen.Bounds.Height -
|
int heightMax = screen.Bounds.Height -
|
||||||
new Taskbar().Size.Height;
|
new Taskbar().Size.Height;
|
||||||
Menu menuPredecessor = menus[0];
|
Menu menuPredecessor = menus[0];
|
||||||
|
@ -336,7 +319,7 @@ namespace SystemTrayMenu
|
||||||
widthPredecessors -= newWith;
|
widthPredecessors -= newWith;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (screen.Bounds.Width <
|
else if (Screen.PrimaryScreen.Bounds.Width <
|
||||||
widthPredecessors + menuPredecessor.Width + menu.Width)
|
widthPredecessors + menuPredecessor.Width + menu.Width)
|
||||||
{
|
{
|
||||||
directionToRight = true;
|
directionToRight = true;
|
||||||
|
@ -385,24 +368,15 @@ namespace SystemTrayMenu
|
||||||
IsAnyMenuActive();
|
IsAnyMenuActive();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Activated(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
Menu triggeredMenu = (Menu)sender;
|
|
||||||
menus[0].SetTitleColorActive();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsAnyMenuActive()
|
bool IsAnyMenuActive()
|
||||||
{
|
{
|
||||||
bool isAnyMenuActive;
|
bool isAnyMenuActive = Form.ActiveForm is Menu;
|
||||||
Form activeForm = Form.ActiveForm;
|
|
||||||
//isAnyMenuActive = Menus().Any(m => m.IsActive(activeForm));
|
|
||||||
isAnyMenuActive = activeForm is Menu;
|
|
||||||
if (!isAnyMenuActive)
|
if (!isAnyMenuActive)
|
||||||
{
|
{
|
||||||
menus[0].SetTitleColorDeactive();
|
menus[0].SetTitleColorDeactive();
|
||||||
CheckMenuOpenerStop(iMenuKey, iRowKey);
|
CheckMenuOpenerStop(keyboardInput.iMenuKey,
|
||||||
ClearIsSelectedByKey(iMenuKey, iRowKey);
|
keyboardInput.iRowKey);
|
||||||
ResetSelectedByKey();
|
keyboardInput.ClearIsSelectedByKey();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -720,6 +694,12 @@ namespace SystemTrayMenu
|
||||||
|
|
||||||
void MenusFadeOut()
|
void MenusFadeOut()
|
||||||
{
|
{
|
||||||
|
if (messageFilterAdded)
|
||||||
|
{
|
||||||
|
Application.RemoveMessageFilter(messageFilter);
|
||||||
|
messageFilterAdded = false;
|
||||||
|
}
|
||||||
|
|
||||||
Menus().ToList().ForEach(menu =>
|
Menus().ToList().ForEach(menu =>
|
||||||
{
|
{
|
||||||
if (menu.Level > 0)
|
if (menu.Level > 0)
|
||||||
|
@ -755,361 +735,20 @@ namespace SystemTrayMenu
|
||||||
dgv.MouseDoubleClick += Dgv_MouseDoubleClick;
|
dgv.MouseDoubleClick += Dgv_MouseDoubleClick;
|
||||||
dgv.MouseDown += Dgv_MouseDown;
|
dgv.MouseDown += Dgv_MouseDown;
|
||||||
dgv.SelectionChanged += Dgv_SelectionChanged;
|
dgv.SelectionChanged += Dgv_SelectionChanged;
|
||||||
menu.KeyPress += KeyPress;
|
menu.KeyPress += keyboardInput.KeyPress;
|
||||||
menu.CmdKeyProcessed += CmdKeyProcessed;
|
menu.CmdKeyProcessed += keyboardInput.CmdKeyProcessed;
|
||||||
menu.Activated += Activated;
|
menu.Activated += Activated;
|
||||||
|
void Activated(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
menus[0].SetTitleColorActive();
|
||||||
|
}
|
||||||
menu.Deactivated += fastLeave.Start;
|
menu.Deactivated += fastLeave.Start;
|
||||||
menu.VisibleChanged += DisposeWhenHidden;
|
menu.VisibleChanged += DisposeWhenHidden;
|
||||||
AddItemsToMenu(menuData.RowDatas, menu);
|
AddItemsToMenu(menuData.RowDatas, menu);
|
||||||
return menu;
|
return menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// While menu is open user presses a key to search for specific entries.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="sender">not used</param>
|
|
||||||
/// <param name="e">Key data of the pressed key</param>
|
|
||||||
private void KeyPress(object sender, KeyPressEventArgs e)
|
|
||||||
{
|
|
||||||
if (char.IsLetterOrDigit(e.KeyChar) ||
|
|
||||||
char.IsPunctuation(e.KeyChar) ||
|
|
||||||
char.IsWhiteSpace(e.KeyChar) ||
|
|
||||||
char.IsSeparator(e.KeyChar))
|
|
||||||
{
|
|
||||||
string letter = e.KeyChar.ToString();
|
|
||||||
|
|
||||||
timerKeySearch.Stop();
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(KeySearchString))
|
|
||||||
{
|
|
||||||
// no search string set, start new search with initial letter
|
|
||||||
KeySearchString += letter;
|
|
||||||
SelectByKey(Keys.None, KeySearchString);
|
|
||||||
}
|
|
||||||
else if (KeySearchString.Length == 1 && KeySearchString.LastOrDefault().ToString() == letter)
|
|
||||||
{
|
|
||||||
// initial letter pressed again, jump to next element
|
|
||||||
SelectByKey(Keys.None, letter);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// new character for the search string, narrow down the search
|
|
||||||
KeySearchString += letter;
|
|
||||||
SelectByKey(Keys.None, KeySearchString, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// give user some time to continue with this search
|
|
||||||
timerKeySearch.Start();
|
|
||||||
e.Handled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void TimerKeySearch_Tick(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
// this search has expired, reset search
|
|
||||||
timerKeySearch.Stop();
|
|
||||||
KeySearchString = string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CmdKeyProcessed(Keys keys)
|
|
||||||
{
|
|
||||||
SelectByKey(keys);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool IsAnyMenuSelectedByKey()
|
|
||||||
{
|
|
||||||
Menu menu = null;
|
|
||||||
DataGridView dgv = null;
|
|
||||||
string textselected = string.Empty;
|
|
||||||
return IsAnyMenuSelectedByKey(ref dgv, ref menu, ref textselected);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool IsAnyMenuSelectedByKey(
|
|
||||||
ref DataGridView dgv,
|
|
||||||
ref Menu menuFromSelected,
|
|
||||||
ref string textselected)
|
|
||||||
{
|
|
||||||
Menu menu = menus[iMenuKey];
|
|
||||||
bool isStillSelected = false;
|
|
||||||
if (menu != null &&
|
|
||||||
iRowKey > -1)
|
|
||||||
{
|
|
||||||
dgv = menu.GetDataGridView();
|
|
||||||
if (dgv.Rows.Count > iRowKey)
|
|
||||||
{
|
|
||||||
RowData rowData = (RowData)dgv.
|
|
||||||
Rows[iRowKey].Tag;
|
|
||||||
if (rowData.IsSelectedByKeyboard)
|
|
||||||
{
|
|
||||||
isStillSelected = true;
|
|
||||||
menuFromSelected = rowData.SubMenu;
|
|
||||||
#warning refactor datagridviewrow get
|
|
||||||
textselected = dgv.Rows[iRowKey].
|
|
||||||
Cells[1].Value.ToString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return isStillSelected;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SelectByKey(Keys keys, string keyInput = "", bool KeepSelection = false)
|
|
||||||
{
|
|
||||||
int iRowBefore = iRowKey;
|
|
||||||
int iMenuBefore = iMenuKey;
|
|
||||||
|
|
||||||
Menu menu = menus[iMenuKey];
|
|
||||||
DataGridView dgv = null;
|
|
||||||
DataGridView dgvBefore = null;
|
|
||||||
Menu menuFromSelected = null;
|
|
||||||
string textselected = string.Empty;
|
|
||||||
bool isStillSelected = IsAnyMenuSelectedByKey(ref dgv, ref menuFromSelected, ref textselected);
|
|
||||||
if (isStillSelected)
|
|
||||||
{
|
|
||||||
if (KeepSelection)
|
|
||||||
{
|
|
||||||
// Is current selection is still valid for this search then skip selecting different item
|
|
||||||
if (textselected.ToLower().StartsWith(keyInput.ToLower()))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dgvBefore = dgv;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ResetSelectedByKey();
|
|
||||||
menu = menus[iMenuKey];
|
|
||||||
dgv = menu.GetDataGridView();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool toClear = false;
|
|
||||||
switch (keys)
|
|
||||||
{
|
|
||||||
case Keys.Enter:
|
|
||||||
if (iRowKey > -1 &&
|
|
||||||
dgv.Rows.Count > iRowKey)
|
|
||||||
{
|
|
||||||
RowData trigger = (RowData)dgv.Rows[iRowKey].Tag;
|
|
||||||
trigger.MouseDown(dgv, null);
|
|
||||||
//trigger.DoubleClick();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Keys.Up:
|
|
||||||
FadeInIfNeeded();
|
|
||||||
if (SelectMatchedReverse(dgv, iRowKey) ||
|
|
||||||
SelectMatchedReverse(dgv, dgv.Rows.Count - 1))
|
|
||||||
{
|
|
||||||
CheckMenuOpenerStop(iMenuBefore, iRowBefore, dgvBefore);
|
|
||||||
CheckMenuOpenerStart(dgv, iRowKey);
|
|
||||||
toClear = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Keys.Down:
|
|
||||||
FadeInIfNeeded();
|
|
||||||
if (SelectMatched(dgv, iRowKey) ||
|
|
||||||
SelectMatched(dgv, 0))
|
|
||||||
{
|
|
||||||
CheckMenuOpenerStop(iMenuBefore, iRowBefore, dgvBefore);
|
|
||||||
CheckMenuOpenerStart(dgv, iRowKey);
|
|
||||||
toClear = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Keys.Left:
|
|
||||||
FadeInIfNeeded();
|
|
||||||
int iMenuKeyNext = iMenuKey + 1;
|
|
||||||
if (isStillSelected)
|
|
||||||
{
|
|
||||||
if (menuFromSelected != null &&
|
|
||||||
menuFromSelected == menus[iMenuKeyNext])
|
|
||||||
{
|
|
||||||
dgv = menuFromSelected.GetDataGridView();
|
|
||||||
if (dgv.Rows.Count > 0)
|
|
||||||
{
|
|
||||||
iMenuKey += 1;
|
|
||||||
iRowKey = -1;
|
|
||||||
if (SelectMatched(dgv, iRowKey) ||
|
|
||||||
SelectMatched(dgv, 0))
|
|
||||||
{
|
|
||||||
CheckMenuOpenerStop(iMenuBefore,
|
|
||||||
iRowBefore, dgvBefore);
|
|
||||||
CheckMenuOpenerStart(dgv, iRowKey);
|
|
||||||
toClear = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
iRowKey = -1;
|
|
||||||
iMenuKey = menus.Where(m => m != null).Count() - 1;
|
|
||||||
if (menus[iMenuKey] != null)
|
|
||||||
{
|
|
||||||
dgv = menus[iMenuKey].GetDataGridView();
|
|
||||||
if (SelectMatched(dgv, iRowKey) ||
|
|
||||||
SelectMatched(dgv, 0))
|
|
||||||
{
|
|
||||||
CheckMenuOpenerStop(iMenuBefore, iRowBefore, dgvBefore);
|
|
||||||
CheckMenuOpenerStart(dgv, iRowKey);
|
|
||||||
toClear = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
log.Info("indexMenuByKey = menus.Where(m => m != null).Count()" +
|
|
||||||
"=> menus[iMenuKey] == null");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Keys.Right:
|
|
||||||
if (iMenuKey > 0)
|
|
||||||
{
|
|
||||||
if (menus[iMenuKey - 1] != null)
|
|
||||||
{
|
|
||||||
iMenuKey -= 1;
|
|
||||||
iRowKey = -1;
|
|
||||||
menu = menus[iMenuKey];
|
|
||||||
dgv = menu.GetDataGridView();
|
|
||||||
if (SelectMatched(dgv, dgv.SelectedRows[0].Index) ||
|
|
||||||
SelectMatched(dgv, 0))
|
|
||||||
{
|
|
||||||
CheckMenuOpenerStop(iMenuBefore, iRowBefore, dgvBefore);
|
|
||||||
CheckMenuOpenerStart(dgv, iRowKey);
|
|
||||||
toClear = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CheckMenuOpenerStop(iMenuBefore, iRowBefore, dgvBefore);
|
|
||||||
iMenuKey = 0;
|
|
||||||
iRowKey = -1;
|
|
||||||
toClear = true;
|
|
||||||
FadeHalfOrOutIfNeeded();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Keys.Escape:
|
|
||||||
CheckMenuOpenerStop(iMenuBefore, iRowBefore, dgvBefore);
|
|
||||||
iMenuKey = 0;
|
|
||||||
iRowKey = -1;
|
|
||||||
toClear = true;
|
|
||||||
MenusFadeOut();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (!string.IsNullOrEmpty(keyInput))
|
|
||||||
{
|
|
||||||
if (SelectMatched(dgv, iRowKey, keyInput) ||
|
|
||||||
SelectMatched(dgv, 0, keyInput))
|
|
||||||
{
|
|
||||||
FadeInIfNeeded();
|
|
||||||
CheckMenuOpenerStop(iMenuBefore, iRowBefore);
|
|
||||||
CheckMenuOpenerStart(dgv, iRowKey);
|
|
||||||
toClear = true;
|
|
||||||
}
|
|
||||||
else if (isStillSelected)
|
|
||||||
{
|
|
||||||
iRowKey = iRowBefore - 1;
|
|
||||||
if (SelectMatched(dgv, iRowKey, keyInput) ||
|
|
||||||
SelectMatched(dgv, 0, keyInput))
|
|
||||||
{
|
|
||||||
FadeInIfNeeded();
|
|
||||||
CheckMenuOpenerStop(iMenuBefore, iRowBefore);
|
|
||||||
CheckMenuOpenerStart(dgv, iRowKey);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
iRowKey = iRowBefore;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (isStillSelected && toClear)
|
|
||||||
{
|
|
||||||
ClearIsSelectedByKey(iMenuBefore, iRowBefore);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool SelectMatched(DataGridView dgv,
|
|
||||||
int indexStart, string keyInput = "")
|
|
||||||
{
|
|
||||||
bool found = false;
|
|
||||||
for (int i = indexStart; i < dgv.Rows.Count; i++)
|
|
||||||
{
|
|
||||||
if (Select(dgv, i, keyInput))
|
|
||||||
{
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool SelectMatchedReverse(DataGridView dgv,
|
|
||||||
int indexStart, string keyInput = "")
|
|
||||||
{
|
|
||||||
bool found = false;
|
|
||||||
for (int i = indexStart; i > -1; i--)
|
|
||||||
{
|
|
||||||
if (Select(dgv, i, keyInput))
|
|
||||||
{
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool Select(DataGridView dgv, int i,
|
|
||||||
string keyInput = "")
|
|
||||||
{
|
|
||||||
bool found = false;
|
|
||||||
if (i > -1 &&
|
|
||||||
i != iRowKey &&
|
|
||||||
dgv.Rows.Count > i)
|
|
||||||
{
|
|
||||||
DataGridViewRow row = dgv.Rows[i];
|
|
||||||
RowData rowData = (RowData)row.Tag;
|
|
||||||
string text = row.Cells[1].Value.ToString();
|
|
||||||
if (text.ToLower().StartsWith(keyInput.ToLower()))
|
|
||||||
{
|
|
||||||
iRowKey = rowData.RowIndex;
|
|
||||||
rowData.IsSelectedByKeyboard = true;
|
|
||||||
row.Selected = false; //event trigger
|
|
||||||
row.Selected = true; //event trigger
|
|
||||||
if (row.Index < dgv.FirstDisplayedScrollingRowIndex)
|
|
||||||
{
|
|
||||||
dgv.FirstDisplayedScrollingRowIndex = row.Index;
|
|
||||||
}
|
|
||||||
else if (row.Index >=
|
|
||||||
dgv.FirstDisplayedScrollingRowIndex +
|
|
||||||
dgv.DisplayedRowCount(false))
|
|
||||||
{
|
|
||||||
dgv.FirstDisplayedScrollingRowIndex = row.Index -
|
|
||||||
dgv.DisplayedRowCount(false) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ClearIsSelectedByKey(int menuIndex, int rowIndex)
|
|
||||||
{
|
|
||||||
Menu menu = menus[menuIndex];
|
|
||||||
if (menu != null && rowIndex > -1)
|
|
||||||
{
|
|
||||||
DataGridView dgv = menu.GetDataGridView();
|
|
||||||
if (dgv.Rows.Count > rowIndex)
|
|
||||||
{
|
|
||||||
DataGridViewRow row = dgv.Rows[rowIndex];
|
|
||||||
RowData rowData = (RowData)row.Tag;
|
|
||||||
rowData.IsSelectedByKeyboard = false;
|
|
||||||
row.Selected = false; //event trigger
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddItemsToMenu(List<RowData> data, Menu menu)
|
private void AddItemsToMenu(List<RowData> data, Menu menu)
|
||||||
{
|
{
|
||||||
|
@ -1171,15 +810,4 @@ namespace SystemTrayMenu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class WindowsExplorerSort : IComparer<string>
|
|
||||||
{
|
|
||||||
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
|
|
||||||
static extern int StrCmpLogicalW(String x, String y);
|
|
||||||
|
|
||||||
public int Compare(string x, string y)
|
|
||||||
{
|
|
||||||
return StrCmpLogicalW(x, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -167,8 +167,9 @@
|
||||||
<Compile Include="Helper\MessageFilter.cs" />
|
<Compile Include="Helper\MessageFilter.cs" />
|
||||||
<Compile Include="Helper\ShellContextMenu.cs" />
|
<Compile Include="Helper\ShellContextMenu.cs" />
|
||||||
<Compile Include="Helper\File\FileUrl.cs" />
|
<Compile Include="Helper\File\FileUrl.cs" />
|
||||||
<Compile Include="Helper\WaitFastLeave.cs" />
|
<Compile Include="Handler\WaitFastLeave.cs" />
|
||||||
<Compile Include="Helper\WaitMenuOpen.cs" />
|
<Compile Include="Handler\WaitMenuOpen.cs" />
|
||||||
|
<Compile Include="Helper\WindowsExplorerSort.cs" />
|
||||||
<Compile Include="Properties\Resources.Designer.cs">
|
<Compile Include="Properties\Resources.Designer.cs">
|
||||||
<AutoGen>True</AutoGen>
|
<AutoGen>True</AutoGen>
|
||||||
<DesignTime>True</DesignTime>
|
<DesignTime>True</DesignTime>
|
||||||
|
@ -196,8 +197,8 @@
|
||||||
<Compile Include="Controls\AppNotifyIcon.cs" />
|
<Compile Include="Controls\AppNotifyIcon.cs" />
|
||||||
<Compile Include="Program.cs" />
|
<Compile Include="Program.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="Helper\ScreenMouse.cs" />
|
<Compile Include="Handler\KeyboardInput.cs" />
|
||||||
<Compile Include="SystemTrayMenuHandler.cs" />
|
<Compile Include="SystemTrayMenu.cs" />
|
||||||
<EmbeddedResource Include="Controls\AboutBox.resx">
|
<EmbeddedResource Include="Controls\AboutBox.resx">
|
||||||
<DependentUpon>AboutBox.cs</DependentUpon>
|
<DependentUpon>AboutBox.cs</DependentUpon>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
|
@ -296,6 +297,7 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<WCFMetadata Include="Connected Services\" />
|
<WCFMetadata Include="Connected Services\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup />
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
Other similar extension points exist, see Microsoft.Common.targets.
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
|
Loading…
Reference in a new issue