using System;
using System.Runtime.InteropServices;

namespace DemonstracjaPotrzebyZnaniaWinAPI.WinApi
{
    // Metody wysyłające informacje do Input Stream (klawiatura, mysz, sprzęt, itd.)
    // Działają na abstrakcji - wrapperze INPUT, który przechowuje rózne typy inputów
    public static class InputStream
    {
        private enum KeyFlag
        {
            KEY_DOWN = 0,
            KEY_UP = 2
        }





        [DllImport("user32.dll", SetLastError = true)]
        private static extern uint SendInput(uint numberOfInputs, INPUT[] inputs, int sizeOfInputStructure);





        public static void SendKeyDown(KeyCode keyCode)
        {
            CreateKeyInput(keyCode, KeyFlag.KEY_DOWN, out var input);
            SetInputs(out var inputs, input);
            SendInputs(inputs);
        }

        public static void SendKeyUp(KeyCode keyCode)
        {
            CreateKeyInput(keyCode, KeyFlag.KEY_UP, out var input);
            SetInputs(out var inputs, input);
            SendInputs(inputs);
        }

        public static void SendKeyPress(KeyCode keyCode)
        {
            SendKeyDown(keyCode);
            SendKeyUp(keyCode);
        }





        private static void CreateKeyInput(KeyCode keyCode, KeyFlag keyFlag, out INPUT input)
        {
            input = new INPUT
            {
                Type = 1,
            };

            input.Data.Keyboard = new KEYBDINPUT
            {
                Vk = (ushort)keyCode,
                Scan = 0,
                Flags = (uint)keyFlag,
                Time = 0,
                ExtraInfo = IntPtr.Zero
            };
        }

        private static void SetInputs(out INPUT[] inputs, params INPUT[] setData)
        {
            inputs = new INPUT[setData.Length];

            for (int i = 0; i < setData.Length; i++)
            {
                inputs[i] = setData[i];
            }
        }

        private static void SendInputs(INPUT[] inputs)
        {
            if (SendInput((uint)inputs.Length, inputs, Marshal.SizeOf(typeof(INPUT))) == 0)
            {
                throw new Exception();
            }
        }
    }
}
