Nano 33 BLE as USB "Gaming Keyboard"

Hi All,

I know this topic had been raised a few times, but none of them seem to cover my current dilemma.

I am currently trying to make a one handed controller for gaming that basically emulates a keyboard instead of a controller, with the Thumbstick emulating WASD and push buttons for other keys.

I used the base USBHID -> Keyboard example that was included under the Nano 33 BLE, and successfully managed to get the below script to upload and run on my Nano 33 BLE:

#include "PluggableUSBHID.h"
#include "USBKeyboard.h"

USBKeyboard Keyboard;

// This is where we create variables to map the PIN positions for the Thumbstick axis, and each individual button

const int jxPin = A0;
const int jyPin = A1;
const int jsPin = 4;

// This is where we create an additional variable to read the current value for each PIN

int jxVal;
int jyVal;
int jsVal;

// These values are just to configure the "dead zone" for the Thumbstick
int up = 482;
int down = 542;
int left = 542;
int right = 482;

//Any delays go here for easy access
int dt1 = 200;

void setup() {
  Serial.begin(9600);

  pinMode(jxPin, INPUT);
  pinMode(jyPin, INPUT);
  pinMode(jsPin, INPUT);
  
  digitalWrite(jsPin, HIGH);

}

void loop() {
  // This is where we read the values for each PIN
  jxVal = analogRead(jxPin);
  jyVal = analogRead(jyPin);
  jsVal = digitalRead(jsPin);

  delay(dt1);

  //This is where we attempt to map the Thumbstick directions to WASD
  if (jxVal < up){
    Serial.print("W");
    Keyboard._putc(87);
  }
  if (jxVal > down){
    Serial.print("S");
    Keyboard._putc(83);
  }
  if (jyVal > left){
    Serial.print("A");
    Keyboard._putc(65);
  }
  if (jyVal < right){
    Serial.print("D");
    Keyboard._putc(68);
  }
  
}

I can see the values change in the Serial Monitor, and the characters typing in Notepad... But for some reason these do not seem to work in game.

I assume that the Arduino is just sending the "text" value of the key being pressed and not actually emulating the key being pressed? If so, how do I get it to send the actual key press?

I have tried using both _putc and key_code, but neither seem to work.

UPDATE: I managed to get it to work perfectly by making 2 changes to my code.

The 1st was moving my delay from "void loop" to "void setup", and the second was to use the ASCII values for each key instead of the letter or "HID scan codes."(I think that's what they are called?)

This is what I had attempted before with both _putc and key_code:

  if (jxVal > down){
    Serial.println("S");
    Keyboard.key_code(0x16,0);
  }

  if (jxVal > down){
    Serial.println("S");
    Keyboard.key_code('s',0);
  }

  if (jxVal > down){
    Serial.println("S");
    Keyboard.key_code(83,0);
  }

These are the values that I used to finally get it to work:

//This is where we attempt to map the Thumbstick directions to WASD
  if (jxVal < up){
    Serial.println("W");
    Keyboard.key_code(0x77,0);
  }
  if (jxVal > down){
    Serial.println("S");
    Keyboard.key_code(0x73,0);
  }
  if (jyVal > left){
    Serial.println("A");
    Keyboard.key_code(0x61,0);
  }
  if (jyVal < right){
    Serial.println("D");
    Keyboard.key_code(0x64,0);
  }
  if (jsVal == LOW){
    Serial.println("Jump");
    Keyboard.key_code(0x20,0);
  }

Full code here to get the thumbstick to send WASD for the movement directions, and Space Bar for the push button:

// This Arduino Script is to attempt to emulate a "Gaming Keyboard" as a one handed controller
// - Short term goals:
// - 1) Get at least 9 push buttons plus the Thumbstick button mapped to individual keys.
// - 2) One of the 9 buttons should act as a "modifier" to allow two mappings per button.
// - 3) Use the Thumbstick as WASD movement
// 
// - Long term goals:
// - 1) Be able to switch the controller over to emulate half an actual controller with a flip switch
// - 2) Replace the trigger push button with a force sensor to allow it to act as a "throttle"
//      similarly to how most controller triggers work.
// 
// - Optional goals:
// - 1) Add a battery and charger module so that we can go wireless via Bluetooth
// - 2) Add option to enable the motion sensors and use that for extra controller options,
//      e.g. VR controller(?)

#include "PluggableUSBHID.h"
//#include "USBKeyboard.h"
#include "USBMouseKeyboard.h"

//USBKeyboard Keyboard;
USBMouseKeyboard Keyboard;

// This is where we create variables to map the PIN positions for the Thumbstick axis, and each individual button

const int jxPin = A0;
const int jyPin = A1;
const int jsPin = 4;

// This is where we create an additional variable to read the current value for each PIN

int jxVal;
int jyVal;
int jsVal;

// These values are just to configure the "dead zone" for the Thumbstick
int up = 482;
int down = 542;
int left = 542;
int right = 482;

//Any delays go here for easy access
int dt1 = 200;

void setup() {
  Serial.begin(9600);

  pinMode(jxPin, INPUT);
  pinMode(jyPin, INPUT);
  pinMode(jsPin, INPUT_PULLUP);
  
  digitalWrite(jsPin, HIGH);

  delay(dt1);
}


void loop() {
  // This is where we read the values for each PIN
  jxVal = analogRead(jxPin);
  jyVal = analogRead(jyPin);
  jsVal = digitalRead(jsPin);

  //delay(dt1);

  //This is where we attempt to map the Thumbstick directions to WASD
  if (jxVal < up){
    Serial.print("Pressing W - Joystick X value: ");
    Serial.println(jxVal);    
    Keyboard.key_code(0x77,0);
  }
  if (jxVal > down){
    Serial.print("Pressing S - Joystick X value: ");
    Serial.println(jxVal);    
    Keyboard.key_code(0x73,0);
  }
  if (jyVal > left){
    Serial.print("Pressing A - Joystick Y value: ");
    Serial.println(jyVal);
    Keyboard.key_code(0x61,0);
  }
  if (jyVal < right){
    Serial.print("Pressing D - Joystick Y value: ");
    Serial.println(jyVal);
    Keyboard.key_code(0x64,0);
  }
  if (jsVal == LOW){
    Serial.println("Jump");
    Keyboard.key_code(0x20,0);
  }
}

@

Your other topic on the same subject deleted.

Please do not duplicate your questions as doing so wastes the time and effort of the volunteers trying to help you as they are then answering the same thing in different places.

Please create one topic only for your question and choose the forum category carefully. If you have multiple questions about the same project then please ask your questions in the one topic as the answers to one question provide useful context for the others, and also you won’t have to keep explaining your project repeatedly.

Repeated duplicate posting could result in a temporary or permanent ban from the forum.

Could you take a few moments to Learn How To Use The Forum

It will help you get the best out of the forum in the future.

Thank you.

My apologies.

I didn't think to post the follow up under this as I assumed that it would be better to reference back to the original issue for context rather than following up in the same thread.

This topic was mostly about getting the code to send out any key presses to my PC, whereas the second one was more relating to specific "control keys" (i.e. Esc, Shift & Ctrl) that I was struggling with.

I will repost the follow up under this thread.

Thanks for correcting me.

I managed to build out the entire circuit with all the buttons and Thumbstick working perfectly. The problem now is that I am not able to figure out how to send Esc, Shift, and Ctrl from the arduino so that it registers correctly on PC.

I have tried all the different Hex and decimal codes that I could find for these keys, but I have not bee able to get them to work.

Does anyone else know what I could be doing wrong?

I used the USBHID -> Keyboard example that was included under the Nano 33 BLE, and build everything up from there.

I am using these two libraries that were included in the example, and they have gotten me this far:

#include "PluggableUSBHID.h"
#include "USBMouseKeyboard.h"

But I don't see any KeyPress type methods being named in either of these.

Could anyone please help point me in the right direction?

EDIT: Including my code for reference. (I'm very much still a beginner at this)

Summary
// This Arduino Script is to attempt to emulate a "Gaming Keyboard" as a one handed controller
// - Short term goals:
// - 1) Get at least 9 push buttons plus the Thumbstick button mapped to individual keys.
//        - This had been done for the most part, keys still left to map once I have figured out how:
//        - Shift  
//        - Ctrl
//        - Esc
//
// - 2) One of the 9 buttons should act as a "modifier" to allow two mappings per button. - Done
// - 3) Use the Thumbstick as WASD movement. - Done
// 
// - Long term goals:
// - 1) Be able to switch the controller over to emulate half an actual controller with a flip switch.
// - 2) Replace the trigger push button with a force sensor to allow it to act as a "throttle"
//      similarly to how most controller triggers work.
// 
// - Optional goals:
// - 1) Add a battery and charger module so that we can go wireless via Bluetooth.
// - 2) Add option to enable the motion sensors and use that for extra controller options,
//      e.g. VR controller(?)

#include "PluggableUSBHID.h"
#include "USBMouseKeyboard.h"

USBMouseKeyboard Keyboard;

// This is where the variables are set to map the PIN positions for the Thumbstick axis, and each individual button.

const int jxPin = A0;
const int jyPin = A1;
const int jsPin = 12;

const int b1Pin = 2;
const int b2Pin = 3;
const int b3Pin = 4;
const int b4Pin = 5;

const int bpPin = 6;
const int tgPin = 7;

const int stPin = 8;
const int slPin = 9;

const int fnPin = 11;

// This is where additional variables are set to read the current value for each PIN.

int jxVal;
int jyVal;
int jsVal;

int b1Val;
int b2Val;
int b3Val;
int b4Val;

int bpVal;
int tgVal;

int stVal;
int slVal;

int fnVal;

// These values are just here to easily configure the "dead zone" for the Thumbstick.
int up = 462;
int down = 562;
int left = 562;
int right = 462;

//Any delays go here for easy access.
int dts = 800;
int dtb = 0                                                                                                                                                                                                                                     ;

void setup() {
  Serial.begin(9600);

//Setting the pinMode for each of the pins.
  pinMode(jxPin, INPUT);
  pinMode(jyPin, INPUT);
  pinMode(jsPin, INPUT_PULLUP);
  
  pinMode(b1Pin, INPUT_PULLUP);
  pinMode(b2Pin, INPUT_PULLUP);
  pinMode(b3Pin, INPUT_PULLUP);
  pinMode(b4Pin, INPUT_PULLUP);

  pinMode(bpPin, INPUT_PULLUP);
  pinMode(tgPin, INPUT_PULLUP);

  pinMode(stPin, INPUT_PULLUP);
  pinMode(slPin, INPUT_PULLUP);

  pinMode(fnPin, INPUT_PULLUP);
  
// Prepping the buttons with a default state.
  digitalWrite(jsPin, HIGH);
  
  digitalWrite(b1Pin, HIGH);
  digitalWrite(b2Pin, HIGH);
  digitalWrite(b3Pin, HIGH);
  digitalWrite(b4Pin, HIGH);

  digitalWrite(bpPin, HIGH);
  digitalWrite(tgPin, HIGH);

  digitalWrite(stPin, HIGH);
  digitalWrite(slPin, HIGH);

  digitalWrite(fnPin, HIGH);

  delay(dts);
}


void loop() {
// This is where the values for each PIN is read.
  jxVal = analogRead(jxPin);
  jyVal = analogRead(jyPin);
  jsVal = digitalRead(jsPin);
  
  b1Val = digitalRead(b1Pin);
  b2Val = digitalRead(b2Pin);
  b3Val = digitalRead(b3Pin);
  b4Val = digitalRead(b4Pin);

  bpVal = digitalRead(bpPin);
  tgVal = digitalRead(tgPin);

  stVal = digitalRead(stPin);
  slVal = digitalRead(slPin);

  fnVal = digitalRead(fnPin);


//This is where I attempt to map the Thumbstick directions to WASD, and this seems to work perfectly (I hope)
  if (jxVal < up){
    Serial.print("Pressing W - Joystick X value: ");
    Serial.println(jxVal);    
    Keyboard.key_code(0x77,0);
  }
  if (jxVal > down){
    Serial.print("Pressing S - Joystick X value: ");
    Serial.println(jxVal);    
    Keyboard.key_code(0x73,0);
  }
  if (jyVal > left){
    Serial.print("Pressing A - Joystick Y value: ");
    Serial.println(jyVal);
    Keyboard.key_code(0x61,0);
  }
  if (jyVal < right){
    Serial.print("Pressing D - Joystick Y value: ");
    Serial.println(jyVal);
    Keyboard.key_code(0x64,0);
  }
  if (jsVal == LOW){
    if (fnVal == LOW){
      Serial.println("Pressing T");
      Keyboard.key_code(0x74,0);
    } else {
      Serial.println("Pressing Space");
      Keyboard.key_code(0x20,0);
    }
    delay(dtb);
  }

  // This is where the four "Primary Buttons" are being mapped to Keys.
  if (b1Val == LOW){
    if (fnVal == LOW){
      Serial.println("Pressing Z");
      Keyboard.key_code(0x7a,0);
    } else {
      Serial.println("Pressing Q");
      Keyboard.key_code(0x71,0);
    }    
    delay(dtb);
  }
  if (b2Val == LOW){
    if (fnVal == LOW){
      Serial.println("Pressing X");
      Keyboard.key_code(0x78,0);
    } else {    
      Serial.println("Pressing E");
      Keyboard.key_code(0x65,0);
    }
    delay(dtb);
  }
  if (b3Val == LOW){
    if (fnVal == LOW){
      Serial.println("Pressing C");
      Keyboard.key_code(0x63,0);
    } else {    
      Serial.println("Pressing R");
      Keyboard.key_code(0x72,0);
    }
    delay(dtb);
  }
  if (b4Val == LOW){
    if (fnVal == LOW){
      Serial.println("Pressing V");
      Keyboard.key_code(0x76,0);
    } else {    
      Serial.println("Pressing F");
      Keyboard.key_code(0x66,0);
    }
    delay(dtb);
  }

// This is where the Bumper and Trigger are mapped to Keys
  if (bpVal == LOW){
    if (fnVal == LOW){
      Serial.println("Pressing B");
      Keyboard.key_code(0x62,0);
    } else {
      Serial.println("Pressing CTRL");
      Keyboard.key_code(0x11);
    }
    delay(dtb);
  }
  if (tgVal == LOW){
    if (fnVal == LOW){
      Serial.println("Pressing G");
      Keyboard.key_code(0x76,0);
    } else {
      Serial.println("Pressing Shift");
      Keyboard.key_code(0x10);
    }
    delay(dtb);
  }

// This is where the Start and Select buttons are mapped to Keys
  if (stVal == LOW){
    if (fnVal == LOW){
      Serial.println("Pressing I");
      Keyboard.key_code(0x69,0);
    } else {
      Serial.println("Pressing Esc");
      Keyboard.key_code(0Xb1);
    }
    delay(dtb);
  }
  if (slVal == LOW){
if (fnVal == LOW){
      Serial.println("Pressing M");
      Keyboard.key_code(0x6d,0);
    } else {    
      Serial.println("Pressing Tab");
      Keyboard.key_code(0x09,0);
    }
    delay(dtb);
  }
}

USB and ASCII use different codes for the characters and commands. For example ESC is 0x1B in ASCII and 0x29 in USB standard. The KEYMAP in USBKeyboard.cpp defines a look-up table which maps the ASCII characters to USB so we can just write 'putc('A')' and get correct output. Now it turns out that they forgot to include ESC in the look-up table. If you change line 64 in USBKeyboard.cpp from

{0, 0},   /* ESC */

to

{0x29, 0},  /* ESC */

everything works as expected and you can send ESC just with 'Keyboard.putc(0x1B)'.

Shift and Ctrl are already defined and are working correctly out of the box, afaik.