2

Im trying to build a small app that would send input to a game. After searching for a while, I found many answers that suggest SendInput should be used.

Below there is the code that I'm working on (basically doing a lots of tests to see what works, hence the messiness). I would suggest you ignore most of the code, the line that interests me , or should I say that causes the build problem is:

public static extern uint SendInput(
    uint nInputs,[MarshalAs(UnmanagedType.LPArray), In] INPUT[] pInputs, int cbSize);

This gives me the error :

'INPUT' is inaccessible due to its protection level.

I am new to C# (and Windows programming), so I cannot really figure out what I should do to fix that.

Any help would be appreciated.

Thanks in advance.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using WindowsInput;

namespace WindowsFormsApplication1
{
    [Flags]
    public enum KeyFlag
    {
        KeyDown = 0x0000,
        KeyUp = 0x0002,
        Scancode = 0x0008
    }


    internal static class VirtualKeyboard
    {

        public static void KeyDown(System.Windows.Forms.Keys key)
        {

            Console.WriteLine("Sending keybdevent: " + (byte)key);
            //keybd_event((byte)key, 0, 0, 0);
            /*INPUT[] InputData = new INPUT[2];
            Key ScanCode = Microsoft.DirectX.DirectInput.Key.W;

            InputData[0].type = 1; //INPUT_KEYBOARD
            InputData[0].wScan = (ushort)ScanCode;
            InputData[0].dwFlags = (uint)SendInputFlags.KEYEVENTF_SCANCODE;

            InputData[1].type = 1; //INPUT_KEYBOARD
            InputData[1].wScan = (ushort)ScanCode;
            InputData[1].dwFlags = (uint)(SendInputFlags.KEYEVENTF_KEYUP | SendInputFlags.KEYEVENTF_UNICODE);

            // send keydown
            if (SendInput(2, InputData, Marshal.SizeOf(InputData[1])) == 0)
            {
                System.Diagnostics.Debug.WriteLine("SendInput failed with code: " +
                Marshal.GetLastWin32Error().ToString());
            }*/
            //InputSimulator.SimulateKeyDown(VirtualKeyCode.VK_E);

            Console.WriteLine("Exit.....");
        }
        [DllImport("user32.dll", SetLastError = true)]
        public static extern uint SendInput(uint nInputs, [MarshalAs(UnmanagedType.LPArray), In] INPUT[] pInputs, int cbSize);
        public static void SendKey(short keyCode, KeyFlag keyFlag)
        {
            INPUT[] InputData = new INPUT[1];

            InputData[0].type = 1;
            InputData[0].ki.wScan = keyCode; // 0x14 = T for example
            InputData[0].ki.dwFlags = (int)keyFlag;
            InputData[0].ki.time = 0;
            InputData[0].ki.dwExtraInfo = IntPtr.Zero;

            SendInput(1, InputData, Marshal.SizeOf(typeof(INPUT)));
        }

        public static void PressKey(short key)
        {
            SendKey(key, KeyFlag.KeyDown | KeyFlag.Scancode);
            SendKey(key, KeyFlag.KeyUp | KeyFlag.Scancode);
        }

        public static void KeyUp(System.Windows.Forms.Keys key)
        {
            //keybd_event((byte)key, 0, 0x7F, 0);
        }
    }
}
Salah Akbari
  • 39,330
  • 10
  • 79
  • 109
eemerge
  • 75
  • 2
  • 9

2 Answers2

3

The INPUT struct must be a higher access level, such as public so other classes can access it. See access modifiers.

public struct INPUT 
{  
   ...
}
Cyral
  • 13,999
  • 6
  • 50
  • 90
  • internal or protected internal would also work if INPUT Is located in the same assembly, no? – David L Jun 09 '15 at 20:36
  • internal would work, protected internal would only work for derived classes. (It depends where INPUT is defined, I am assuming based on other questions that it is a struct) – Cyral Jun 09 '15 at 20:37
  • I am gonna try to review the examples maybe I missed the point where they define the structure. @DavidL : I tried internal also, same problem. But it must be because I did not define the structure... – eemerge Jun 09 '15 at 20:37
  • protected internal only works for derived classes if the class exists in another assembly. It seems likely that the struct exists in the same assembly as the form control, making it a valid choice. But since you updated your answer language to "such as", I'd say it qualifies appropriately now :). – David L Jun 09 '15 at 20:38
  • 1
    @eemerge Looks like [this question](http://stackoverflow.com/a/8963130/1218281) might have those definitions. – Cyral Jun 09 '15 at 20:39
  • @DavidL TIL that `protected internal` means for derived classes OR anybody from the assembly. Thought it only allowed derived classes in the same assembly. – Cyral Jun 09 '15 at 20:42
  • @Cyral Nope, clever little OR clause in there. That tripped me up one day. – David L Jun 09 '15 at 20:45
  • @Cyral thanks for the link, I think that should do the trick ! – eemerge Jun 09 '15 at 20:49
1

In C# you have to explicitly mark struct members as public. In c++ they are automatically public. So you must mark INPUT as public.

Salah Akbari
  • 39,330
  • 10
  • 79
  • 109