Go Down

Topic: [c#] Simulating Keystroke for Gamepad (Read 998 times) previous topic - next topic

LittleRain

I just started my first Arduino project and I'm trying to make a custom gamepad.
Its just a bunch of buttons on a breadboard, and connected to PC through serial with USB.

I got all the serial communication finished, but I'm having a problem with getting the actual key events to work with an emulator.

It enters the keys fine in text boxes, even when its minimized. But when I try to map the keys to an emulator wierd keys come up.
ZSnes gave me "C5H", BizHawk gave me "Pause", and kigb gave me "NumLock.," every key being the same in each emulator.
Zsnes did how ever do something, in the main menu for Mario world, I would try to select a file, but it would go to where it says "Press Start," I'd press any button again and it would go back to file select screen, then it would just repeat.

I tried mapping them with the keyboard since I use WASD for the directional buttons, but its not actually detecting the events.



Heres my C# code for the keystrokes.




Code: [Select]
  [DllImport("user32.dll")]
        public static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);

        const byte extendedKey = 0x0001; //Is the key from a numpad? (I think thats what this is for)
        const byte eventKeyUp = 0x0002;


        /// <summary>
        /// Simulates a key press(down?) event.
        /// </summary>
        /// <param name="key">Keycode</param>
        public static void KeyPress(Keys key)
        {
            keybd_event((byte)key,
                     0x45,
                     extendedKey | 0,
                     0);
        }

        /// <summary>
        /// Simulates a key up event.
        /// </summary>
        /// <param name="key">Keycode</param>
        public static void KeyRelease(Keys key)
        {
            keybd_event((byte)key,
                    0x45,
                    extendedKey | eventKeyUp,
                    0);
        }

sterretje

Can't help you but Interfacing w/ Software on the Computer might be a better section to post your question. You can use the report to moderator link under your post to request a move if you want to.

Further, which Arduino are you using? A Leonardo or Micro (and a few others if not mistaken) can act as a HID; maybe worth considering.
If you understand an example, use it.
If you don't understand an example, don't use it.

Electronics engineer by trade, software engineer by profession. Trying to get back into electronics after 15 years absence.

LittleRain

I was going to post it there but wasn't sure since this issue happened after the serial communication, I'll do that though.

I'm using an UNO, had no idea that only a few of them could be used as an HID device until just a few days ago. I was looking into flashing the card with the Leonardo (software?), but am a little worried I might screw it up and render it useless.

I just ordered the Leonardo a couple days ago so if I can't get this to work I'll just wait I guess.

Thanks!

Coding Badly

Quote
I'm just wondering if I could get this post moved to Interfacing w/ Software Computer.
Yes.  Done.  Thank you for using Report-to-moderator.


Robin2

Its just a bunch of buttons on a breadboard, and connected to PC through serial with USB.

I got all the serial communication finished, but I'm having a problem with getting the actual key events to work with an emulator.
Are you trying this with a real Arduino or just with some emulator? If the latter perhaps it does not emulate properly.


If you need help with Arduino code this is the place - but you eed to post your Arduino program and tell us what Arduino you are using.

If you need help with C# code for a PC program then you need to ask on a Forum that deals with PC programming.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

LittleRain

Robin I am using the UNO, and am using serial communication to send 2 bytes to my c# program.
It is getting the bytes and processing the inputs fine, but when I try to use it in a snes emulator, they aren't getting the correct keys that I have simulated. One emulator shows up as 'Num Lock', the other shows up as 'Pause' and another one as 'CH5', what ever that is.

I did have this post in the Programming sub-forum but the fellow above said I should have it moved here.

Here is my arduino code. And if you want my C# program (source) you can download it here.

Code: [Select]

const int ledPin =  13;

const int upPin = 3;
const int rightPin = 4;
const int downPin = 5;
const int leftPin = 2;

const int startPin = 7;
const int selectPin = 6;

const int redPin = 9;
const int greenPin = 10;
const int bluePin = 11;
const int yellowPin = 8;

int upState = 0;
int rightState = 0;
int downState = 0;
int leftState = 0;

int selectState = 0;
int startState = 0;

int redState = 0;
int greenState = 0;
int yellowState = 0;
int blueState = 0;

#define wait delay(6);

 byte data[2]= {0, 0};


void setup() {
  Serial.begin(9600); //Set up the serial com

  pinMode(ledPin, OUTPUT);

  pinMode(upPin, INPUT);
  pinMode(rightPin, INPUT);
  pinMode(downPin, INPUT);
  pinMode(leftPin, INPUT);

  pinMode(startPin, INPUT);
  pinMode(selectPin, INPUT);

  pinMode(redPin, INPUT);
  pinMode(greenPin, INPUT);
  pinMode(bluePin, INPUT);
  pinMode(yellowPin, INPUT);
}


void loop() {

  //Get the states for each of the buttons.
  upState = digitalRead(upPin);
  rightState = digitalRead(rightPin);
  downState = digitalRead(downPin);
  leftState = digitalRead(leftPin);

  selectState = digitalRead(selectPin);
  startState = digitalRead(startPin);

  redState = digitalRead(redPin);
  greenState = digitalRead(greenPin);
  blueState = digitalRead(bluePin);
  yellowState = digitalRead(yellowPin);
 

  //encode the button states into a byte each, with the first bit being used to sort which byte is which on the other end.
  data[0] = (0 << 0) + (startState << 1) + (selectState << 2) + (leftState << 3) + (downState << 4) + (rightState << 5) + ( upState << 6);
  data[1] =  (1 << 0) + (yellowState << 1) + (redState << 2) + (greenState << 3) + (blueState << 4);

  //Send the bytes through serial
  Serial.write(data[0]);
  Serial.write(data[1]);

  //Wait 6ms to try and make it run at 60fps, this is probably wrong though.
  wait;


    //This is just to make sure the buttons are working.
   if (upState == HIGH || rightState == HIGH || downState == HIGH || leftState == HIGH || redState == HIGH || greenState == HIGH  || blueState == HIGH || yellowState == HIGH  || selectState == HIGH || startState == HIGH  ) {
    // turn LED on:
    digitalWrite(ledPin, HIGH);
  } else {
    // turn LED off:
    digitalWrite(ledPin, LOW);
  }

}

sterretje

Flashing an Uno with the Leonardo bootloader will not work. There is at least one article on the web how to modify an Uno to be used as a HID; do a search for "arduino as hid". It involves flashing the 16U2 with dedicated firmware.

I had to do some research as to what SNES and WASD are.

For WASD, I assume that (in this case) it's software that translates e.g. the 'Z' key on a keyboard to the arrow key. If so, I assume that you want to send a 'Z' when a specific button 'on' the Arduino is pressed. Or if you press e.g. '2', it translates to <ctrl>S to start the game (just as an example).

If the above about WASD is correct, it points to the fact that you actually have to use an Arduino that can act as a HID. Further use of WASD does not make much sense to me; why not send the code for the left arrow key instead of 'Z' as your project will be a dedicated game controller?

PS
I assume the emulators that you talk about allow you to play Nintendo games on a PC?
If you understand an example, use it.
If you don't understand an example, don't use it.

Electronics engineer by trade, software engineer by profession. Trying to get back into electronics after 15 years absence.

LittleRain

#7
Jan 22, 2018, 01:44 am Last Edit: Jan 22, 2018, 05:30 am by LittleRain
Sorry sterretje I didn't know that it would be confusing to some people, but yes you got it right.

I was going to flash it but was a little worried that I would mess it up somehow.
The thing is the program I wrote to read the serial data is working, in this picture you can see its taking inputs correctly, you can also see it is simulating the keys in notepad.




These pictures though, znes and bizhawk(which apparently uses zsnes as well) is coming up as the wrong keys, and all the same for some reason.



Edit: Ok I actually figured out what is kind of wrong, and it was with the first bit of code at the top. I was sending 0x45 to the bScan, which is the hardware keycode. I'm not sure exactly what it is. There is still an issue though, and that the keys its giving me are way different then what is set. Things like numlock, f11 and stuff. It is working in the emulator, but since its pressing f11 keys its turning settings on and off.
I think another issue is that I'm not using virtual keycodes for the bVk, when I'm done working I'm going to try using those instead.

Code: [Select]
         /* Info as seen on the first URL.
bVk [in]
Type: BYTE
A virtual-key code. The code must be a value in the range 1 to 254. For a complete list, see Virtual Key Codes.

bScan [in]
Type: BYTE
A hardware scan code for the key.

dwFlags [in]
Type: DWORD
Controls various aspects of function operation. This parameter can be one or more of the following values.

dwExtraInfo [in]
Type: ULONG_PTR
An additional value associated with the key stroke.

         */



        [DllImport("user32.dll")]
        public static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);

        const byte extendedKey = 0x0001; //Is the key from a numpad? (I think thats what this is for)
        const byte eventKeyUp = 0x0002;


        /// <summary>
        /// Simulates a key press(down?) event.
        /// </summary>
        /// <param name="key">Keycode</param>
        public static void KeyPress(Keys key)
        {
            keybd_event((byte)key,
                     (byte)key,
                     0,
                     0);

            /*
                keybd_event((byte)key,
                     0x45,
                     extendedKey | 0,
                     0);
             */
        }

        /// <summary>
        /// Simulates a key up event.
        /// </summary>
        /// <param name="key">Keycode</param>
        public static void KeyRelease(Keys key)
        {
            keybd_event((byte)key,
                     (byte)key,
                    eventKeyUp,
                    0);


            /*
                keybd_event((byte)key,
                    0x45,
                    extendedKey | eventKeyUp,
                    0);
            */
        }




Edit: Ok I figured it out, I used a keycode for the (byte)key, and where it says 0x45 I used a scan code, which did not know existed.

Go Up