Qwiic Pro Micro USB-C (ATmega32U4) Hookup Guide

Pages
Contributors: bboyho
Favorited Favorite 2

Example 2: HID Mouse and Keyboard

When the Pro Micro's were released, the most revolutionary feature (as far as Arduinos go) is its true USB functionality. The Pro Micro can be programmed to emulate any USB device you could imagine. You can even program it to act just like a mouse, keyboard, or other HID-class USB device.

What is HID?

It's one of the many defined USB device classes. Every USB device is assigned a class, which defines what its general purpose is. There are loads of classes -- printers, hubs, speakers, and webcams to mention a few, but in this example we'll be emulating HID -- Human Interface Device. The ATmega32U4 takes care of the USB-hardware hurdle, but we've still got to clear the firmware one. Time for some example code! We broke up the HID example into two parts.

Example 2a: USB Keyboards Made Simple

To emulate a USB keyboard, we'll be making use of the Keyboard class. Here are some of the functions made available to use by this class:

  • Keyboard.write(char) - This function will send a single character over USB. The character passed can be any standard, printable, ASCII-defined character: 0-9, a-z, A-Z, space, symbols, etc. Here's an example line of code:

    Keyboard.write('z') // This will send a single 'z' character to your computer.
  • Keyboard.print(string) - If you need to perform a series a Keyboard.write()'s, consider using just a single Keyboard.print(). This works similar to Serial.print() – give it a string of characters and it'll send that stream of characters over USB. Keyboard.println(string) is also defined, if you want a newline/linefeed to close out your string. An example:

    Keyboard.print("Hello, world"); // This'll send your computer an 'H', followed by 'e', followed by...
  • Keyboard.press(byte) and Keyboard.release(byte) give you more precise control over key presses. They do exactly what you'd expect. One presses a button down, the other releases a button. Make sure you release any buttons you press, otherwise you'll encounter some wiggyness on your computer.

That's it. You don't need to include any libraries or anything, just invoke any of those functions. Here's an example sketch to try it out:

language:c
/* HID KeyBoard Example
   by: Jim Lindblom
   date: 1/12/2012
   license: MIT License - Feel free to use this code for any purpose.
   No restrictions. Just keep this license if you go on to use this
   code in your future endeavors! Reuse and share.

   This is very simplistic code that allows you to send a 'z' with
   a momentary pushbutton.
*/

#include <Keyboard.h>
int buttonPin = 9;  // Set a button to any pin

void setup()
{
  pinMode(buttonPin, INPUT);  // Set the button as an input
  digitalWrite(buttonPin, HIGH);  // Pull the button high

  Keyboard.begin(); //Init keyboard emulation
}

void loop()
{
  if (digitalRead(buttonPin) == 0)  // if the button goes low
  {
    Keyboard.write('z');  // send a 'z' to the computer via Keyboard HID
    delay(1000);  // delay so there aren't a kajillion z's
  }
}

In this sketch, connecting pin 9 to ground will make the Qwiic Pro Micro spit out a 'z' character. If you have a simple, momentary button handy, tie one end to pin 9 and the other to ground. Otherwise, just use a wire to short 9 to GND.

After a Keyboard.write() or Keyboard.print() function has been performed by the Qwiic Pro Micro, your computer will have to decide what to do with it. What your computer does with that character, or string of characters, is entirely dependent on what program it's running at the time. If you have a text editor (Notepad, Word, TextEdit, etc.) open and active, it'll print it out there. Or you can try using the textbox below to test.

Example 2b: USB Mouse Functionality

That covers about half of USB HID library. How about we add a mouse to the mix now? Implementing a USB HID mouse requires a few more functions, but it's still crazy simple. There are five functions provided by Arduino's HID class that can be used to implement a mouse:

  • Mouse.move(x, y, wheel) tells the computer to move the mouse a certain number of pixels along either the x, y and/or wheel axis. Each variable can be any value between -128 and +127, with negative numbers moving the cursor down/left, positive numbers move the right/up.

  • Mouse.press(b) sends a down-click on a button or buttons. The button(s) will remain "pressed" until you call Mouse.release(b). The b variable is a single byte, each bit of which represents a different button. You can set it equal to any of the following, or OR (|) them together to click multiple buttons at once:

    • MOUSE_LEFT - Left mouse button
    • MOUSE_RIGHT - Right mouse button
    • MOUSE_MIDDLE - Middle mouse button
    • MOUSE_ALL - All three mouse buttons

  • Mouse.click(b) sends a down-click (press) followed immediately by an up-click (release) on button(s) b. For example, to click the left and right buttons simultaneously, try this:

    Mouse.click(MOUSE_LEFT | MOUSE_RIGHT); // Press and release the left and right mouse buttons

Here's some example code to show off these functions:

language:c
/* HID Joystick Mouse Example
   by: Jim Lindblom
   date: 1/12/2012
   license: MIT License - Feel free to use this code for any purpose.
   No restrictions. Just keep this license if you go on to use this
   code in your future endeavors! Reuse and share.

   This is very simplistic code that allows you to turn the
   SparkFun Thumb Joystick (http://www.sparkfun.com/products/9032)
   into an HID Mouse. The select button on the joystick is set up
   as the mouse left click.
*/
#include <Mouse.h>
int horzPin = A0;  // Analog output of horizontal joystick pin
int vertPin = A1;  // Analog output of vertical joystick pin
int selPin = 9;  // select button pin of joystick

int vertZero, horzZero;  // Stores the initial value of each axis, usually around 512
int vertValue, horzValue;  // Stores current analog output of each axis
const int sensitivity = 200;  // Higher sensitivity value = slower mouse, should be <= about 500
int mouseClickFlag = 0;

//int invertMouse = 1;        //Invert joystick based on orientation
int invertMouse = -1;         //Noninverted joystick based on orientation

void setup()
{
  pinMode(horzPin, INPUT);  // Set both analog pins as inputs
  pinMode(vertPin, INPUT);
  pinMode(selPin, INPUT);  // set button select pin as input
  digitalWrite(selPin, HIGH);  // Pull button select pin high
  delay(1000);  // short delay to let outputs settle
  vertZero = analogRead(vertPin);  // get the initial values
  horzZero = analogRead(horzPin);  // Joystick should be in neutral position when reading these

  Mouse.begin(); //Init mouse emulation
}

void loop()
{
  vertValue = analogRead(vertPin) - vertZero;  // read vertical offset
  horzValue = analogRead(horzPin) - horzZero;  // read horizontal offset

  if (vertValue != 0)
    Mouse.move(0, (invertMouse * (vertValue / sensitivity)), 0); // move mouse on y axis
  if (horzValue != 0)
    Mouse.move((invertMouse * (horzValue / sensitivity)), 0, 0); // move mouse on x axis

  if ((digitalRead(selPin) == 0) && (!mouseClickFlag))  // if the joystick button is pressed
  {
    mouseClickFlag = 1;
    Mouse.press(MOUSE_LEFT);  // click the left button down
  }
  else if ((digitalRead(selPin)) && (mouseClickFlag)) // if the joystick button is not pressed
  {
    mouseClickFlag = 0;
    Mouse.release(MOUSE_LEFT);  // release the left button
  }
}

This sketch is set up so that an analog joystick connected to analog pins A0 and A1 can be used to move your mouse cursor.

The loop() of this code continuously monitors the horizontal and vertical analog values of the joystick and sends the Mouse.move() command based on what it reads. It'll move the mouse in steps, depending on what the sensitivity variable is set to. With sensitivity set to 2, the cursor will move in either 1 or 2 pixel steps. Depending on the orientation of the joystick, there is also an option to invert the mouse based on how the "V" is pointing by adjusting invertMouse.

The select switch on the joystick is used to control the mouse left click. Notice this code is using Mouse.press() and Mouse.release(), rather than just calling a single Mouse.click(). This requires a bit more coding, but it allows you to do things like drag-and-drop, double click, etc.


For more HID example code, check out the Arduino-supplied examples under the File > Examples > 09.USB menu. Or check out Arduino's reference language under USB for more information.