mirror of
https://github.com/babalae/better-genshin-impact.git
synced 2026-05-29 10:25:50 +08:00
new mouse key hook
This commit is contained in:
108
Common/MouseKeyHook/KeyCombinationExtensions.cs
Normal file
108
Common/MouseKeyHook/KeyCombinationExtensions.cs
Normal file
@@ -0,0 +1,108 @@
|
||||
// This code is distributed under MIT license.
|
||||
// Copyright (c) 2010-2018 George Mamaladze
|
||||
// See license.txt or https://mit-license.org/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Gma.System.MouseKeyHook.Implementation;
|
||||
|
||||
namespace Gma.System.MouseKeyHook
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension methods to detect key combinations
|
||||
/// </summary>
|
||||
public static class KeyCombinationExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Detects a key or key combination and triggers the corresponding action.
|
||||
/// </summary>
|
||||
/// <param name="source">
|
||||
/// An instance of Global or Application hook. Use <see cref="Hook.GlobalEvents" /> or <see cref="Hook.AppEvents" /> to
|
||||
/// create it.
|
||||
/// </param>
|
||||
/// <param name="map">
|
||||
/// This map contains the list of key combinations mapped to corresponding actions. You can use a dictionary initilizer
|
||||
/// to easily create it.
|
||||
/// Whenever a listed combination will be detected a corresponding action will be triggered.
|
||||
/// </param>
|
||||
/// <param name="reset">
|
||||
/// This optional action will be executed when some key was pressed but it was not part of any wanted combinations.
|
||||
/// </param>
|
||||
public static void OnCombination(this IKeyboardEvents source,
|
||||
IEnumerable<KeyValuePair<Combination, Action>> map, Action reset = null)
|
||||
{
|
||||
var watchlists = map.GroupBy(k => k.Key.TriggerKey)
|
||||
.ToDictionary(g => g.Key, g => g.ToArray());
|
||||
source.KeyDown += (sender, e) =>
|
||||
{
|
||||
KeyValuePair<Combination, Action>[] element;
|
||||
var found = watchlists.TryGetValue(e.KeyCode.Normalize(), out element);
|
||||
if (!found)
|
||||
{
|
||||
reset?.Invoke();
|
||||
return;
|
||||
}
|
||||
var state = KeyboardState.GetCurrent();
|
||||
var action = reset;
|
||||
var maxLength = 0;
|
||||
foreach (var current in element)
|
||||
{
|
||||
var matches = current.Key.Chord.All(state.IsDown);
|
||||
if (!matches) continue;
|
||||
if (maxLength > current.Key.ChordLength) continue;
|
||||
maxLength = current.Key.ChordLength;
|
||||
action = current.Value;
|
||||
}
|
||||
action?.Invoke();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Detects a key or key combination sequence and triggers the corresponding action.
|
||||
/// </summary>
|
||||
/// <param name="source">
|
||||
/// An instance of Global or Application hook. Use <see cref="Hook.GlobalEvents" /> or
|
||||
/// <see cref="Hook.AppEvents" /> to create it.
|
||||
/// </param>
|
||||
/// <param name="map">
|
||||
/// This map contains the list of sequences mapped to corresponding actions. You can use a dictionary initilizer to
|
||||
/// easily create it.
|
||||
/// Whenever a listed sequnce will be detected a corresponding action will be triggered. If two or more sequences match
|
||||
/// the longest one will be used.
|
||||
/// Example: sequences may A,B,C and B,C might be detected simultanously if user pressed first A then B then C. In this
|
||||
/// case only action corresponding
|
||||
/// to 'A,B,C' will be triggered.
|
||||
/// </param>
|
||||
public static void OnSequence(this IKeyboardEvents source, IEnumerable<KeyValuePair<Sequence, Action>> map)
|
||||
{
|
||||
var actBySeq = map.ToArray();
|
||||
var endsWith = new Func<Queue<Combination>, Sequence, bool>((chords, sequence) =>
|
||||
{
|
||||
var skipCount = chords.Count - sequence.Length;
|
||||
return skipCount >= 0 && chords.Skip(skipCount).SequenceEqual(sequence);
|
||||
});
|
||||
|
||||
var max = actBySeq.Select(p => p.Key).Max(c => c.Length);
|
||||
var min = actBySeq.Select(p => p.Key).Min(c => c.Length);
|
||||
var buffer = new Queue<Combination>(max);
|
||||
|
||||
var wrapMap = actBySeq.SelectMany(p => p.Key).Select(c => new KeyValuePair<Combination, Action>(c, () =>
|
||||
{
|
||||
buffer.Enqueue(c);
|
||||
if (buffer.Count > max) buffer.Dequeue();
|
||||
if (buffer.Count < min) return;
|
||||
//Invoke action corresponding to the longest matching sequence
|
||||
actBySeq
|
||||
.Where(pair => endsWith(buffer, pair.Key))
|
||||
.OrderBy(pair => pair.Key.Length)
|
||||
.Select(pair => pair.Value)
|
||||
.LastOrDefault()
|
||||
?.Invoke();
|
||||
}));
|
||||
|
||||
OnCombination(source, wrapMap, buffer.Clear);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user