Rehber C# Lowlevel input hook kütüphanesi Winhook nasıl kullanılır?

Windows'taki user32.dll kütüphanesinden yararlanarak C# ile kernel level hook yapabilmemizi sağlayan Winhook artık public! Bütün eventleri, change'leri ve inputları izleyebilmenin yanında girişleri engellemenizi, kaydetmenizi, özelleştirmenizi, state durumlarını öğrenmenize yarar.

Nasıl kullanılır?​

GitHub - BayramReisbirligi/Winhook: Winhook Adresinden Winhook'u indiriyoruz.
Ben size göstermek amaçlı .NET 9 C# WinUI 3 oluşturuyorum.
Öncelikle bu projenin .NET 9 ve Minimum Windows 19041 sürümü gerektiğini size bildirmek isterim. İsterseniz kendiniz fork atıp eski versiyonlara da uyumlu hâle getirebilirsiniz. Ben yenilikçi olduğumdan .NET 9'u tercih ettim. Bazı özellikler 19041 ve .NET 9 altında da çalışabilir.
1756322612332.png

Winhook kütüphanesini ekliyoruz:
1756322689726.png

NOT: Mouse Down ve Up arasındaki event tetiklenmesi (Hold) için Windelay kütüphanesi gerekebilir. İlgili rehber için: Rehber: C#: Hassas bekleme kütüphanesi Windelay nasıl kullanılır?
Sonuç:
1759345902172.png

MainWindow.xaml kodları:
XML:
<Window
    x:Class="DllTester.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:DllTester"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d" Title="Winhook WinUI 3 Test">
    <Window.SystemBackdrop>
        <MicaBackdrop />
    </Window.SystemBackdrop>
    <Grid>
        <ListBox x:Name="MyListBox" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
    </Grid>
</Window>
MainWindow.xaml.cs kodları:
C#:
using static ReisProduction.Windelay.Models.DelayExecutor;
using ReisProduction.Windelay.Utilities.Enums;
using ReisProduction.Winhook.Utilities.Enums;
using ReisProduction.Windelay.Utilities;
using ReisProduction.Winhook.Utilities;
using System.Runtime.InteropServices;
using ReisProduction.Winhook.Models;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
using System.Threading.Tasks;
using System.Diagnostics;
using Microsoft.UI.Xaml;
using System.Threading;
using Windows.System;
using WinRT.Interop;
using System;
namespace DllTester;
public sealed partial class MainWindow : Window
{
    private readonly Winhook _winhook = new();
    public MainWindow()
    {
        InitializeComponent();
        MakeWindowAlwaysOnTop();
        InitializeInputHook();
        Task.Run(StartTest);
    }
    private static async void StartTest()
    {
        Random rnd = new();
        CancellationTokenSource cts = new();
        Debug.WriteLine("HybridDelay Test Başladı\n");
        //SpinWaitIterations = 10; // İsterseniz daha hassas yapabilirsiniz fakat gereksiz olur. Zaten 25 çok agresif bir hassaslık.
        // SpinWait için iterasyon sayısı (Varsayılan: İşlemci çekirdeğine göre değişir.)
        // public static int SpinWaitIterations { get; set; } = Math.Clamp(200 / Environment.ProcessorCount, 25, 100);
        //SpinAheadMilisecond = 500; // İsterseniz daha hassas yapabilirsiniz fakat iyi bilgisayarlar için gereksiz olur. Kötü bilgisayarlar için ise max 500ms yeterlidir.
        // HybridDelay için SpinAhead süresi (Varsayılan: 200ms)
        //public static int SpinAheadMilisecond { get; set; } = 200;
        for (int i = 0; i < 20; i++)
        {
            int ms = rnd.Next(200, 2000); // 200ms - 1000ms arası random süre
            DelayAction delay = new
            (
                ms,
                cts.Token, // İptal edebilmek için
                DelayType.HybridDelay // Delay türü (Burada HybridDelay kullanıldı) Sistemi en az yorarak en doğru sonucu verir.
                                      // Ancak DelayType vermek, sadece HandleDelay() methodunda geçerlidir.
            );

            Stopwatch sw = Stopwatch.StartNew();
            //HandleDelay(delay); // DelayType parametresi verilmezse, default olarak HybridDelay kullanılır.
            await HybridDelay(delay); // En sağlıklı ve önerilen yöntem budur.
            sw.Stop();

            double elapsed = sw.Elapsed.TotalMilliseconds,
                      diff = elapsed - ms;

            Debug.WriteLine($"Hedef: {ms,4:0000} MS | Beklenen: {elapsed,8:0000.00} MS | Sapma: {diff,8:+0000.00;-0000.00;+0000.00} MS");
        }
        Debug.WriteLine("\nTest Bitti.\nHighResSpin Test Başladı");
        for (int i = 0; i < 20; i++)
        {
            int ms = rnd.Next(10, 1000); // 10ms - 1000ms arası random süre
            DelayAction delay = new
            (
                ms,
                cts.Token, // İptal edebilmek için
                DelayType.HybridDelay // Delay türü (Burada HybridDelay kullanıldı) Sistemi en az yorarak en doğru sonucu verir.
                                      // Ancak DelayType vermek, sadece HandleDelay() methodunda geçerlidir.
            );

            Stopwatch sw = Stopwatch.StartNew();
            //HandleDelay(delay); // DelayType parametresi verilmezse, default olarak HybridDelay kullanılır.
            HighResSpin(delay); // En sağlıklı ve önerilen yöntem budur.
            sw.Stop();

            double elapsed = sw.Elapsed.TotalMilliseconds,
                      diff = elapsed - ms;

            Debug.WriteLine($"Hedef: {ms,4:0000} MS | Beklenen: {elapsed,8:0000.00} MS | Sapma: {diff,8:+0000.00;-0000.00;+0000.00} MS");
        }
        Debug.WriteLine("\nTest Bitti.");
    }
    [DllImport("user32.dll")]
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Interoperability", "SYSLIB1054:Use 'LibraryImportAttribute' instead of 'DllImportAttribute' to generate P/Invoke marshalling code at compile time", Justification = "<Pending>")]
    [System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0079:Remove unnecessary suppression", Justification = "<Pending>")]
    private static extern bool SetWindowPos(nint hWnd, nint hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
    private static readonly nint HWND_TOPMOST = new(-1);
    private const uint
        SWP_NOSIZE = 0x0001,
        SWP_NOMOVE = 0x0002;
    private void MakeWindowAlwaysOnTop()
    {
        var hWnd = WindowNative.GetWindowHandle(this);
        SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
    }
    private void InitializeInputHook()
    {
        _winhook.FileCreated += (args) => AddMessage($"[FileCreated] Name: {args.Name}   |   Path:{args.FullPath}   |  Change Type: {args.ChangeType}");
        _winhook.FileDeleted += (args) => AddMessage($"[FileDeleted] Name: {args.Name}   |   Path:{args.FullPath}   |  Change Type: {args.ChangeType}");
        _winhook.FileRenamed += (args) => AddMessage($"[FileRenamed] Name: {args.Name}   |   Path:{args.FullPath}   |  Change Type: {args.ChangeType}");
        _winhook.FileChanged += (args) => AddMessage($"[FileChanged] Name: {args.Name}   |   Path:{args.FullPath}   |  Change Type: {args.ChangeType}");
        _winhook.FileWatcherError += (ex) => AddMessage($"[FileWatcherError] {ex.GetException().Message}");
        _winhook.MovementThreshold = 500; // Fare hareketi için eşik değeri (Move eventi tetiklenmesi için) (Varsayılan: 1)
        _winhook.AcceptNoneInput = true; // Klavye ve fareden gelen tüm girdileri kabul et (Varsayılan: false) (Yani sadece InputType enumunda olanlar) IsValid mantığı.
        _winhook.FilterKeys // Engellemek istediğiniz tuşları buraya ekleyin.
        (
            VirtualKey.V,
            VirtualKey.W,
            VirtualKey.E,
            VirtualKey.C,
            VirtualKey.Tab,
            VirtualKey.RightWindows,
            VirtualKey.Escape,
            VirtualKey.Space,
            VirtualKey.Left,
            VirtualKey.Up,
            VirtualKey.Right,
            VirtualKey.Down
        );
        _winhook.FilterMice // Engellemek istediğiniz fare tiplerini buraya ekleyin.
        (
            MouseType.MiddleButton,
            MouseType.XButton1,
            MouseType.XButton2,
            MouseType.MouseScrollLeft,
            MouseType.MouseScrollRight,
            MouseType.MouseScrollUp,
            MouseType.MouseScrollDown
        );
        _winhook.InputDown += k => AddMessage($"[InputDown] {k} (0x{(int)k:X})");
        _winhook.MouseHold += (k) => AddMessage($"[MouseHold] {k} (0x{(int)k:X})");
        _winhook.InputUp += k => AddMessage($"[InputUp] {k} (0x{(int)k:X})");
        _winhook.MouseMove += (x, y) =>
        {
            var pos = ReisProduction.Winhook.Services.Interop.GetCursorPos();
            AddMessage($"[MouseMove] X: {x}, Y: {y} - Mouse POS: ({pos.X}x{pos.Y})");
        };
        // Başlatmak için:
        _winhook.StartOrStopHooks([new KeyboardHook(true), new MouseHook(true), new FileHook(Paths: Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\Technopat")]);
        AddMessage("Winhook initialized and running...");
        // Sonlandırmak için:
        //_winhook.StartOrStopHooks([new KeyboardHook(false), new MouseHook(false), new FileHook(false, Paths: Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\Technopat")]);
    }
    private void AddMessage(string msg)
    {
        DispatcherQueue.TryEnqueue(() => // Main (UI) thread üzerinde çalıştır
        {
            MyListBox.Items.Add(msg);
            if (FindScrollViewer(MyListBox) is ScrollViewer sv)
                sv.ChangeView(null, sv.ExtentHeight, null);
        });
    }
    private static ScrollViewer? FindScrollViewer(DependencyObject obj)
    {
        if (obj is ScrollViewer sv) return sv;
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
            if (FindScrollViewer(VisualTreeHelper.GetChild(obj, i)) is ScrollViewer found) return found;
        return null;
    }
}

Bir sürü olduğundan sadece InputHook ve FileHook'u gösterebildim. Siz kendiniz inceleyip kullanabilirsiniz veya sorabilirsiniz. Ekstradan fork atıp 'Alt GR' ile gelen oem karakterleri ayıran sistemi biri yapsa çok mutlu olurum. Ben daha da ayrıntıya girmeye üşendim. (Daha ne kadar girebilirdim ki :D)

Girdiğim ayrıntılar :D

Eventler:​

C#:
using ReisProduction.Winhook.Utilities.Enums;
using System.Management;
using Windows.System;
namespace ReisProduction.Winhook.Models;
public partial class Winhook
{
    public event Action<EventArrivedEventArgs>
        ProcessStarted = delegate { },
        ProcessStopped = delegate { },
        ServiceStarted = delegate { },
        ServiceStopped = delegate { },
        ThreadStarted = delegate { },
        ThreadStopped = delegate { },
        ModuleLoaded = delegate { },
        ModuleUnloaded = delegate { },
        SessionChanged = delegate { },
        DeviceChanged = delegate { },
        VolumeChanged = delegate { },
        PowerChanged = delegate { },
        SystemConfigChanged = delegate { },
        TimeChanged = delegate { },
        SystemTrace = delegate { },
        IP4RouteChanged = delegate { },
        IP6RouteChanged = delegate { },
        NetworkAdapterConfigChanged = delegate { },
        ProcessTrace = delegate { },
        ProcessTraceStarted = delegate { },
        ProcessTraceStopped = delegate { },
        ThreadTrace = delegate { },
        ModuleTrace = delegate { },
        BatchJobStarted = delegate { },
        BatchJobStopped = delegate { };
    public event Action<nint>
        WindowSound = delegate { },
        WindowAlert = delegate { } ,
        WindowForegroundChanged = delegate { },
        WindowMenuStart = delegate { },
        WindowMenuEnd = delegate { },
        WindowMenuPopupStart = delegate { },
        WindowMenuPopupEnd = delegate { },
        WindowCaptureStart = delegate { },
        WindowCaptureEnd = delegate { },
        WindowMoveSizeStart = delegate { },
        WindowMoveSizeEnd = delegate { },
        WindowContextHelpStart = delegate { },
        WindowContextHelpEnd = delegate { },
        WindowDragDropStart = delegate { },
        WindowDragDropEnd = delegate { },
        WindowDialogStart = delegate { },
        WindowDialogEnd = delegate { },
        WindowScrollingStart = delegate { },
        WindowScrollingEnd = delegate { },
        WindowSwitchStart = delegate { },
        WindowSwitchEnd = delegate { },
        WindowMinimizeStart = delegate { },
        WindowMinimizeEnd = delegate { },
        WindowDesktopSwitch = delegate { },
        ConsoleCaret = delegate { },
        ConsoleUpdateRegion = delegate { },
        ConsoleUpdateSimple = delegate { },
        ConsoleUpdateScroll = delegate { },
        ConsoleLayout = delegate { },
        ConsoleStartApplication = delegate { },
        ConsoleEndApplication = delegate { },
        UiaPropertyChange = delegate { },
        UiaPatternChange = delegate { },
        UiaStructureChange = delegate { },
        UiaEventIdStart = delegate { },
        UiaEventIdEnd = delegate { },
        ObjectCreate = delegate { },
        ObjectDestroy = delegate { },
        ObjectShow = delegate { },
        ObjectHide = delegate { },
        ObjectReorder = delegate { },
        ObjectFocus = delegate { },
        ObjectSelection = delegate { },
        ObjectSelectionAdd = delegate { },
        ObjectSelectionRemove = delegate { },
        ObjectSelectionWithin = delegate { },
        ObjectStateChange = delegate { },
        ObjectLocationChange = delegate { },
        ObjectNameChange = delegate { },
        ObjectDescriptionChange = delegate { },
        ObjectValueChange = delegate { },
        ObjectParentChange = delegate { },
        ObjectHelpChange = delegate { },
        ObjectDefActionChange = delegate { },
        ObjectAcceleratorChange = delegate { },
        ObjectInvoked = delegate { },
        ObjectTextSelectionChanged = delegate { },
        ObjectContentScrolled = delegate { },
        ObjectArrangementPreview = delegate { },
        ObjectCloaked = delegate { },
        ObjectUncloaked = delegate { },
        ObjectLiveRegionChanged = delegate { },
        ObjectHostedObjectsInvalidated = delegate { },
        ObjectDragStart = delegate { },
        ObjectDragCancel = delegate { },
        ObjectDragComplete = delegate { },
        ObjectDragEnter = delegate { },
        ObjectDragLeave = delegate { },
        ObjectDragDropped = delegate { },
        ObjectImeShow = delegate { },
        ObjectImeHide = delegate { },
        ObjectImeChange = delegate { },
        ObjectTextEditConversionTargetChanged = delegate { };
    public event Action<FileSystemEventArgs>
        FileCreated = delegate { },
        FileChanged = delegate { },
        FileDeleted = delegate { },
        FileRenamed = delegate { };
    public event Action<ErrorEventArgs>
        FileWatcherError = delegate { };
    public event Action<InputType>
        InputDown = delegate { },
        InputHold = delegate { },
        InputPress = delegate { },
        InputDoublePress = delegate { },
        InputUp = delegate { };
    public event Action<VirtualKey>
        KeyDown = delegate { },
        KeyHold = delegate { },
        KeyPress = delegate { },
        KeyDoublePress = delegate { },
        KeyUp = delegate { };
    public event Action<ButtonType>
        MouseDown = delegate { },
        MouseClick = delegate { },
        MouseHold = delegate { },
        MouseDoubleClick = delegate { },
        MouseUp = delegate { };
    public event Action<ScrollType>
        MouseScroll = delegate { },
        MouseScrollLeft = delegate { },
        MouseScrollRight = delegate { },
        MouseScrollUp = delegate { },
        MouseScrollDown = delegate { };
    public event Action<int, int>
        MouseMove = delegate { },
        MouseMoveLeft = delegate { },
        MouseMoveRight = delegate { },
        MouseMoveUp = delegate { },
        MouseMoveDown = delegate { },
        MouseMoveHorizontal = delegate { },
        MouseMoveVertical = delegate { };
}

Record'lar:

C#:
using static ReisProduction.Winhook.Utilities.Constants;
namespace ReisProduction.Winhook.Utilities;
public abstract record HookBase(bool ShouldStart = true);
public record ProcessStartHook(bool ShouldStart = true, params string[] ProcessNames) : HookBase(ShouldStart);
public record ProcessStopHook(bool ShouldStart = true, params string[] ProcessNames) : HookBase(ShouldStart);
public record ServiceStartHook(bool ShouldStart = true, params string[] ServiceNames) : HookBase(ShouldStart);
public record ServiceStopHook(bool ShouldStart = true, params string[] ServiceNames) : HookBase(ShouldStart);
public record ThreadStartHook(bool ShouldStart = true, params int[] ThreadIds) : HookBase(ShouldStart);
public record ThreadStopHook(bool ShouldStart = true, params int[] ThreadIds) : HookBase(ShouldStart);
public record ModuleLoadHook(bool ShouldStart = true, params string[] ModuleNames) : HookBase(ShouldStart);
public record ModuleUnloadHook(bool ShouldStart = true, params string[] ModuleNames) : HookBase(ShouldStart);
public record RegistryChangeHook(bool ShouldStart = true, params string[] RegistryPaths) : HookBase(ShouldStart);
public record SessionChangeHook(bool ShouldStart = true) : HookBase(ShouldStart);
public record DeviceChangeHook(bool ShouldStart = true, params string[] DeviceIds) : HookBase(ShouldStart);
public record VolumeChangeHook(bool ShouldStart = true, params string[] DriveNames) : HookBase(ShouldStart);
public record PowerManagementHook(bool ShouldStart = true) : HookBase(ShouldStart);
public record SystemConfigChangeHook(bool ShouldStart = true) : HookBase(ShouldStart);
public record TimeChangeHook(bool ShouldStart = true) : HookBase(ShouldStart);
public record SystemTraceHook(bool ShouldStart = true) : HookBase(ShouldStart);
public record IP4RouteTableHook(bool ShouldStart = true) : HookBase(ShouldStart);
public record IP6RouteTableHook(bool ShouldStart = true) : HookBase(ShouldStart);
public record NetworkAdapterConfigChangeHook(bool ShouldStart = true) : HookBase(ShouldStart);
public record ProcessTraceHook(bool ShouldStart = true) : HookBase(ShouldStart);
public record ProcessStartTraceHook(bool ShouldStart = true, params string[] ProcessNames) : HookBase(ShouldStart);
public record ProcessStopTraceHook(bool ShouldStart = true, params string[] ProcessNames) : HookBase(ShouldStart);
public record ThreadTraceHook(bool ShouldStart = true) : HookBase(ShouldStart);
public record ModuleTraceHook(bool ShouldStart = true) : HookBase(ShouldStart);
public record BatchJobStartHook(bool ShouldStart = true, params string[] JobNames) : HookBase(ShouldStart);
public record BatchJobStopHook(bool ShouldStart = true, params string[] JobNames) : HookBase(ShouldStart);
public record ForegroundHook(bool ShouldStart = true) : HookBase(ShouldStart);
public record MinimizeHook(bool ShouldStart = true) : HookBase(ShouldStart);
public record SwitchHook(bool ShouldStart = true) : HookBase(ShouldStart);
public record MoveSizeHook(bool ShouldStart = true) : HookBase(ShouldStart);
public record MenuHook(bool ShouldStart = true) : HookBase(ShouldStart);
public record MenuPopupHook(bool ShouldStart = true) : HookBase(ShouldStart);
public record CaptureHook(bool ShouldStart = true) : HookBase(ShouldStart);
public record ContextHelpHook(bool ShouldStart = true) : HookBase(ShouldStart);
public record DragDropHook(bool ShouldStart = true) : HookBase(ShouldStart);
public record DialogHook(bool ShouldStart = true) : HookBase(ShouldStart);
public record ScrollingHook(bool ShouldStart = true) : HookBase(ShouldStart);
public record DesktopSwitchHook(bool ShouldStart = true) : HookBase(ShouldStart);
public record ConsoleHook(bool ShouldStart = true) : HookBase(ShouldStart);
public record UiaHook(bool ShouldStart = true) : HookBase(ShouldStart);
public record ObjectHook(bool ShouldStart = true) : HookBase(ShouldStart);
public record KeyboardHook(bool ShouldStart = true) : HookBase(ShouldStart);
public record MouseHook(bool ShouldStart = true) : HookBase(ShouldStart);
public record FileHook (bool ShouldStart = true, string Filter = "*.*",
    NotifyFilters Filters = AllNotifyFilters, bool IncludeCreated = true, bool IncludeChanged = true, bool IncludeDeleted = true,
    bool IncludeRenamed = true, bool IncludeError = true, bool IncludeSubdirectories = true, params string[] Paths) : HookBase(ShouldStart);

Prop'lar:​

C#:
public DelayType MouseHoldDelayType { get; set; } = DelayType.TaskDelay;
public DelayType KeyHoldDelayType { get; set; } = DelayType.TaskDelay;
public bool AllowClickOnDoubleClick { get; set; } = true;
public bool AllowPressOnDoublePress { get; set; } = true;
public bool AcceptInjectedKeyboard { get; set; } = true;
public bool IncloudeSubdirectories { get; set; } = false;
public bool EnableRaisingEvents { get; set; } = true;
public bool AcceptInjectedMouse { get; set; } = true;
public bool AcceptNoneInput { get; set; } = false;
public bool AcceptSYSDown { get; set; } = true;
public bool AcceptSYSUp { get; set; } = true;
public bool AllowKeyPress { get; set; } = false;
public bool AllowKeyHold { get; set; } = false;
public bool AllowClick { get; set; } = false;
public bool AllowHold { get; set; } = false;
public int DoubleClickThresholdMs { get; set; } = 250;
public int DoublePressThresholdMs { get; set; } = 250;
public int MovementThreshold { get; set; } = 1;
public int KeyHoldIntervalMs { get; set; } = 50;
public int HoldIntervalMs { get; set; } = 50;
public int MoveThresholdMs { get; set; } =
    Math.Clamp(200 / Environment.ProcessorCount, 25, 100);

InputState:​

C#:
public static bool IsKeyDown(VirtualKey key) => GetKeyState((ushort)key) < 0; // Basılı mı?
public static bool IsKeyUp(VirtualKey key) => !IsKeyDown(key); // Basılı değil mi?
public static bool IsHardwareKeyDown(VirtualKey key) => GetAsyncKeyState((ushort)key) < 0; // Anlık
public static bool IsHardwareKeyUp(VirtualKey key) => !IsHardwareKeyDown(key); // Anlık
public static bool IsTogglingKeyInEffect(VirtualKey key) => (GetKeyState((ushort)key) & 0x1) is 0x1; // CapsLock ve ScrolLock gibi ikili sistem tuşlarının state'ini döner.

Helper'lar:

C#:
private static int GetInt(EventArrivedEventArgs e, string key) => int.TryParse(e.NewEvent.Properties[key]?.Value?.ToString(), out var v) ? v : 0;
private static string GetString(EventArrivedEventArgs e, string key) => e.NewEvent.Properties[key]?.Value?.ToString() ?? "";
public static string GetProcessName(int pid)
{
    try
    {
        using var process = Process.GetProcessById(pid);
        return process.ProcessName;
    }
    catch
    {
        return "Unknown";
    }
}
public static int GetProcessID(string processName)
{
    try
    {
        using var process = Process.GetProcessesByName(processName).FirstOrDefault();
        return process?.Id ?? -1;
    }
    catch
    {
        return -1;
    }
}
public static string GetClassName(EventArrivedEventArgs e) => e.NewEvent.ClassPath.ClassName;
public static string GetProcessCreationDate(EventArrivedEventArgs e) => GetString(e, "ProcessCreationDate");
public static string GetProcessName(EventArrivedEventArgs e) => GetString(e, "ProcessName");
public static string GetServiceName(EventArrivedEventArgs e) => GetString(e, "ServiceName");
public static string GetServiceState(EventArrivedEventArgs e) => GetString(e, "State");
public static string GetFilename(EventArrivedEventArgs e) => GetString(e, "Filename");
public static string GetModulePath(EventArrivedEventArgs e) => GetString(e, "ModulePath");
public static string GetModuleName(EventArrivedEventArgs e) => GetString(e, "ModuleName");
public static string GetVolumeName(EventArrivedEventArgs e) => GetString(e, "DriveName");
public static string GetDeviceID(EventArrivedEventArgs e) => GetString(e, "DeviceID");
public static string GetProperty(EventArrivedEventArgs e) => GetString(e, "PropertyName");
public static string GetOldTime(EventArrivedEventArgs e) => GetString(e, "OldTime");
public static string GetNewTime(EventArrivedEventArgs e) => GetString(e, "NewTime");
public static string GetIPRoute(EventArrivedEventArgs e) => GetString(e, "Route");
public static string GetOwner(EventArrivedEventArgs e) => GetString(e, "Owner");
public static string GetAdapterName(EventArrivedEventArgs e) => GetString(e, "Description");
public static string GetExecutablePath(EventArrivedEventArgs e) => GetString(e, "ExecutablePath");
public static string GetCommandLine(EventArrivedEventArgs e) => GetString(e, "CommandLine");
public static string GetSessionName(EventArrivedEventArgs e) => GetString(e, "SessionName");
public static int GetParentProcessID(EventArrivedEventArgs e) => GetInt(e, "ParentProcessId");
public static int GetProcessID(EventArrivedEventArgs e) => GetInt(e, "ProcessID");
public static int GetThreadID(EventArrivedEventArgs e) => GetInt(e, "ThreadID");
public static int GetSessionID(EventArrivedEventArgs e) => GetInt(e, "SessionId");
public static int GetExitStatus(EventArrivedEventArgs e) => GetInt(e, "ExitStatus");
public static int GetEventType(EventArrivedEventArgs e) => GetInt(e, "EventType");
public static int GetEventTypeCode(EventArrivedEventArgs e) => GetInt(e, "EventTypeCode");

ClipboardHelper (WinUI-Forms)​

C#:
public static class ClipboardHelper
{
    public static bool TryGetClipboardText(bool isWinUI, out string? text)
    {
        text = null;
        try
        {
            if (isWinUI)
            {
                var content = Clipboard.GetContent();
                if (!content.Contains(StandardDataFormats.Text))
                    return false;
                text = content.GetTextAsync().GetAwaiter().GetResult();
            }
            else
            {
                if (!System.Windows.Forms.Clipboard.ContainsText())
                    return false;
                text = System.Windows.Forms.Clipboard.GetText();
            }
            return !string.IsNullOrWhiteSpace(text);
        }
        catch { return false; }
    }
    public static bool TrySetClipboardText(bool isWinUI, string text)
    {
        try
        {
            if (string.IsNullOrWhiteSpace(text))
                throw new ArgumentNullException(nameof(text));
            if (isWinUI)
            {
                DataPackage pkg = new();
                pkg.SetText(text);
                Clipboard.SetContent(pkg);
            }
            else
                System.Windows.Forms.Clipboard.SetText(text);
            return true;
        }
        catch { return false; }
    }
    public static bool TryGetClipboardBitmap(bool isWinUI, out object? bitmap)
    {
        bitmap = null;
        try
        {
            if (isWinUI)
            {
                var content = Clipboard.GetContent();
                if (!content.Contains(StandardDataFormats.Bitmap))
                    return false;
                bitmap = content.GetBitmapAsync().GetAwaiter().GetResult();
                return bitmap is not null;
            }
            else
            {
                if (!System.Windows.Forms.Clipboard.ContainsImage())
                    return false;
                bitmap = System.Windows.Forms.Clipboard.GetImage();
                return bitmap is not null;
            }
        }
        catch { return false; }
    }
    public static bool TrySetClipboardBitmap(bool isWinUI, object bitmap)
    {
        try
        {
            if (bitmap is null)
                return false;
            if (isWinUI)
            {
                if (bitmap is Windows.Storage.Streams.RandomAccessStreamReference rasr)
                {
                    DataPackage pkg = new();
                    pkg.SetBitmap(rasr);
                    Clipboard.SetContent(pkg);
                    return true;
                }
                return false;
            }
            else
            {
                if (bitmap is System.Drawing.Image img)
                {
                    System.Windows.Forms.Clipboard.SetImage(img);
                    return true;
                }
                return false;
            }
        }
        catch { return false; }
    }
    public static bool TryGetClipboardContent(bool isWinUI, out object? content)
    {
        try
        {
            if (isWinUI)
            {
                content = Clipboard.GetContent();
                return content is not null;
            }
            else
            {
                content = System.Windows.Forms.Clipboard.GetDataObject();
                return content is not null;
            }
        }
        catch
        {
            content = null;
            return false;
        }
    }
    public static bool TrySetClipboardContent(bool isWinUI, object content)
    {
        try
        {
            if (content is null)
                return false;
            if (isWinUI)
            {
                if (content is DataPackage pkg)
                {
                    Clipboard.SetContent(pkg);
                    return true;
                }
                return false;
            }
            else
            {
                if (content is System.Windows.Forms.IDataObject dataObj)
                {
                    System.Windows.Forms.Clipboard.SetDataObject(dataObj, true);
                    return true;
                }
                return false;
            }
        }
        catch { return false; }
    }
}

Yakında Winjoys'u da public yapmayı düşünüyorum. Belki sonrasında yapacağım Winmacro'yu da ücretsiz olarak public sunabilirim. Ben macro kullanmayı seven birisiyim ve Jitbit Recorder'a bağlı kalmaktan memnun değilim. Daha iyisini ücretsiz bir şekilde yapabileceğimi düşünüyorum. Şu anda gayet iyi gidiyorum. Görünüm olarak da WinUI 3 kullanacağımdan, o konuda problemim olmayacak. Kütüphaneyi inceleyip eklememi istediğiniz özellik veya düzeltmem gereken bir bug bulursanız bildirmeyi unutmayın. Şimdilik bitti ve rafa kaldırdım. Arada bir değişiklik olursa güncellemeler getiririm.

Ciddi emek sarfettim. C# ile açık kaynak olup Global çalışan en sağlam Hook'lardan biri oldu.
NOT: Bu konu sonradan düzeltilip, kütüphaneye bir sürü eklenmeler yapılmıştır. Ek olarak System.Management (9.0.8) DLL'si kullanılmaya başlanmıştır. Güncellemeler pushlanıp v25.5.1 olarak GitHub'a eklenmiştir.

Sırada ise LowLevel Injector'u tamamen bitirip public yapacağım.
İyi günler ve iyi çalışmalar dilerim!

Yakında çıkacak Windoc uygulamamı takip etmek için: Bilgisayarın sağlığını ve performansını kontrol eden uygulamam Windoc
 
Son düzenleme:
Bu hooklar yüzünden genel olarak bir yavaslama oluyor mu bilgisayarda? Yani butun event'leri takip etsem mesela ciddi bir performans sorunu yaratir mi acaba?

Ayrica dogrudan kernel32'den hook yaptigim icin antivirus'ler kizar mi?
 
Bu hooklar yüzünden genel olarak bir yavaslama oluyor mu bilgisayarda? Yani butun event'leri takip etsem mesela ciddi bir performans sorunu yaratir mi acaba?

Ayrica dogrudan kernel32'den hook yaptigim icin antivirus'ler kizar mi?
Hepsini denemedim ama antivirüsler karışmıyor. En azından InputHook'lara karışmıyor. Ve evet, hepsini birden kullanırsanız polling çok fazla olacaktır ve sistemi yorabilir. Bir de neden hepsini kullanasınız ki 😅 Ben bile asla kullanmayacağım ve kullananın olacağını sanmadığım şeyler ekledim. Bir de bunların WinRT'ye özel olanları var Touch hook, Pen hook gibi ilginç şeyleri de ekleyeceğim.
 
Zamanında yaptığım kalem uygulamasında stylus için pen hook kullandım. Çok tutarsız tepkiler verdi çünkü API 2008’den falan kalma. Size bolca sabır diliyorum şimdiden. :)
Benim bahsettiğim WinRT tabanlı olduğu için daha release bile olmadı preview hâlini ekleyeceğim. InputInjectoru var Gamepad, Touch ve Pen, Mouse, Keyboard ve shortcut injecte edebiliyor Winjoys şu an ama hook a bakamadım yoruldum. Tek dezavantajı SendInput apisine göre daha yeni olmasına rağmen AntiCheat'lere ve bazı yönetici izinli uygulamalara yakalanıyor ve inject red edilip ex fırlatıyor. Ama yine de hızlarını test etmedim. Bakalım SendInput apisinden hızlı mı?
 

Technopat Haberler

Yeni konular

Geri
Yukarı