Nano as Virtual Keyboard

I would like to build an interface between a keyboard and computer. The device will have functionality that will look to the computer as a keyboard. I want to be able to re-purpose some of the keys on my keyboard for things such as recording and replaying keyboard macros.

I figure that the first step in doing this is to get an Arduino (Nano at this time, maybe a ATMega328 later) to pretend to be a keyboard and to type text such as "Hello World" to the computer. I have breadboarded the interface described at http://www.practicalarduino.com. I have the code from: github.com/practicalarduino/VirtualUsbKeyboard and http://code.rancidbacon.com/ProjectLogArduinoUSB. I have not gotten it to compile yet but I feel I am getting close.

I am not 100% certain that I know which pins to use. The schematic calls for connections to "DIO2", "DIO4" and "DIO5". My best guess is that those are the Arduino pins D2, D4 and D5, but I could be wrong there too.

Has anyone done this before? Is there a better way?

The next step will be to take input from a USB keyboard. Can someone point be toward some good examples for that?

Yes, D2, D4, D5.

There is an ArduinoNotes.txt file in my copy of the library, that says, inter alia:

* Note: The pins we use on the PCB (not protoboard) hardware shield are:

    INT0 == PD2 == IC Pin 4 == Arduino Digital Pin 2 == D+

    ---- == PD4 == -------- == Arduino Digital Pin 4 == D-

    ---- == PD5 == -------- == Arduino Digital Pin 5 == pull-up

Thank you Nick. As always, you are great.

When I found the file it also says "* At present the IDE won't compile our library so ..."

So it makes since that I can't get it to compile with the IDE. More to learn.

Assuming that I can get the "Pretend to be a Keyboard" to work. Anyone know how to read a USB Keyboard?

Try downloading the 0022 version of the IDE. After all, I have a "pretend" keyboard working under that.

As for reading one, not personally, although I believe you can reconfigure your USB chip (on the Uno) to do that ... maybe.

RandallR: I would like to build an interface between a keyboard and computer. The device will have functionality that will look to the computer as a keyboard. I want to be able to re-purpose some of the keys on my keyboard for things such as recording and replaying keyboard macros.

With a USB host shield, and an Arduino with a USB that can pretend to be a HID, it sounds feasible.

Depending what OS you're connecting this device to, you may find it's possible to use a 'hotkey' style macro recorder utility to do what you want without extra hardware.

I recently threw away a programmable keyboard interceptor that did pretty much exactly what you want. It was part of a flight control system for a flight simulator. Making your own might be most of the fun, but if you're more interested in the end result you might want to look around for programmable flight control systems that already do this type of thing.

Hey Randal, I’m working on a very similar project and have it working with the exception of the fact it occasionally hangs… :frowning: I am using IDE 1.0 without problems but did find that the coding was VERY tricky. I would suggest starting with a VERY simple sketch with nothing more than establishing the USB connection.

Here is a very basic sketch which I got running as one of my first experiments.

// Derived from this project
// http://www.practicalarduino.com/projects/virtual-usb-keyboard

// Requires the use of the "UsbKeyboard" library available from
// http://code.google.com/p/vusb-for-arduino/
#include "UsbKeyboard.h"

long counter = 0;

void setup()
{
  // Disable timer0 since it can mess with the USB timing. Note that
  // this means some functions such as delay() will no longer work.
  TIMSK0&=!(1<<TOIE0);

  // Clear interrupts while performing time-critical operations
  cli();

  // Force re-enumeration so the host will detect us
  usbDeviceDisconnect();
  delayMs(250);
  usbDeviceConnect();

  // Set interrupts again
  sei();

  //initialization period....
  for (int initCounter = 0; initCounter < 100; initCounter++)  {
    delayMs(100);   
    UsbKeyboard.update();
  }
}

void loop()
{
  UsbKeyboard.update();
  delayMs(100);
  UsbKeyboard.sendKeyStroke(KEY_X);
}

// Define our own delay function so that we don't have to rely on
// operation of timer0, the interrupt used by the internal delay()
void delayMs(unsigned int ms)
{
  for (int i = 0; i < ms; i++) {
    delayMicroseconds(1000);
  }
}

I have read that the Uno can change the behavior of the Serial to USB interface. You can then talk USB with "Serial" I/O statements. That is all well and good but 1) I don't have an Uno and 2) I would like to boil it down to a simple box (i.e. chip, crystal, a few resistors and capacitors) that I can easily breadboard and build (i.e. no surface mount).

I have used "Hot Keys" and recorded macros since Windows 3.1 but I like the hardware approach. It is OS independent and I don't need to have Admin rights. I have an "AnyKey" keyboard but it is PS2 and getting very old.

I am compiling by sketch on "arduino-1.0.1-rc2". I have not gotten around to installing the official release yet.

I am currently getting the following error messages:

UsbKeyboard.h:36: warning: only initialized variables can be placed into program memory area UsbKeyboard.h:35: error: conflicting declaration 'const uint8_t usbDescriptorHidReport [35]' usbdrv.h:484: error: 'usbDescriptorHidReport' has a previous declaration as 'char usbDescriptorHidReport []'

But I haven't given up.

Still looking for info on reading a USB keyboard/mouse with an older Arduino (Nano, Duemilanove, Diecimila, ...).

I resolved the type mismatch. The array was defined as char in one place and uint8_t somewhere else.

Now I have:

Hello_World.cpp.o: In function UsbKeyboardDevice': /UsbKeyboard.h:139: undefined reference tousbInit()' Hello_World.cpp.o: In function UsbKeyboardDevice::update()': /UsbKeyboard.h:150: undefined reference tousbPoll()' usbdrv.c.o: In function usbGenericSetInterrupt': ...\Temp\build2589925038285248341.tmp/usbdrv.c:240: undefined reference tousbCrc16Append'

The definitions for usbInit and usbPoll are in usbdrv.c The project directory contain the following files: Hello_World.ino oddebug.c oddebug.h usbconfig.h usbdrv.c usbdrv.h UsbKeyboard.h usbportability.h

It appears to be compiling the file

C:\Desktop\Arduino\arduino-1.0.1\hardware\tools\avr\bin\avr-gcc -c -g -Os -Wall -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -MMD -DUSB_VID=null -DUSB_PID=null -DARDUINO=101 -IC:\Desktop\Arduino\arduino-1.0.1\hardware\arduino\cores\arduino -IC:\Desktop\Arduino\arduino-1.0.1\hardware\arduino\variants\standard C:\AppData\Local\Temp\build2589925038285248341.tmp\usbdrv.c -o

Others seem to solved this problem. I see many posting of people using "virtual keyboards".

That appears to be in usbdrvasm.S ...

usbdrvasm.S:    public  usbCrc16Append
usbdrvasm.S:    .global usbCrc16Append
usbdrvasm.S:; extern unsigned usbCrc16Append(unsigned char *data, unsigned char len);
usbdrvasm.S:usbCrc16Append:

Hey RandallR,

I have made this circuit up and had it running. I found some limitations though with the setup and realised it would take a bit of work to get it playing nicely. One of the members, PaulS, suggested the http://www.pjrc.com/teensy/, which is very similar to an arduino but appears to be much friendlier with the virtual keyboard setup. One example I found here: http://theifdark.blogspot.com.au/2012/03/teensy-ir-pc-remote-keyboard-mouse.html shows the teensy in action as a virtual keyboard.

Happy to help getting your arduino running as a keyboard though if I can.

kopper:
One of the members, PaulS, suggested the http://www.pjrc.com/teensy/, which is very similar to an arduino but appears to be much friendlier with the virtual keyboard setup.

The Teensy and Teensy++ are much better suited for Virtual Keyboard applications because they use a processor that has USB functionality built in. They actually have D+ and D- pins. I may get one as some point, especially if I need to do heavier USB processing. But for now, I would like to try and get this to work

kopper:
Happy to help getting your arduino running as a keyboard though if I can.

I thank you for your offer of help. So this is how I got to where I am.

I have tried a couple different sketches without success. My progress so far. I started out attempting to compile “VirtualUsbKeyboard.pde” from practicalarduino.com (GitHub - practicalarduino/VirtualUsbKeyboard: Use an Arduino to send HID (Human Interface Device) events to a host computer as if it were a keyboard) just as a starting point.

/**
 * VirtualUsbKeyboard
 *
 * Enumerates itself as a HID (Human Interface Device) to a host
 * computer using a USB shield. The Arduino then appears to the host to
 * be a USB keyboard and keypress events can be sent on demand.
 *
 * This example watches the state of 6 push buttons and when a button
 * is pressed it sends a matching keypress event to the host.
 *
 * Copyright 2009 Jonathan Oxer <jon@oxer.com.au>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version. http://www.gnu.org/licenses/
 *
 * www.practicalarduino.com/projects/easy/virtual-usb-keyboard
 */

// Requires the use of the "UsbKeyboard" library available from
//   http://code.rancidbacon.com/ProjectLogArduinoUSB
#include "UsbKeyboard.h"

// Define the inputs to use for buttons
#define BUTTON_A 6
#define BUTTON_B 7
#define BUTTON_C 8
#define BUTTON_D 9
#define BUTTON_MSG 10
#define BUTTON_ENTER 11

// Use the on-board LED as an activity display
int ledPin = 13;

/**
 * Configure button inputs and set up the USB connection to the host
 */
void setup()
{
  // Set up the activity display LED
  pinMode (ledPin, OUTPUT);
  digitalWrite (ledPin, HIGH);

  // Set the button pins to inputs
  pinMode (BUTTON_A, INPUT);
  pinMode (BUTTON_B, INPUT);
  pinMode (BUTTON_C, INPUT);
  pinMode (BUTTON_D, INPUT);
  pinMode (BUTTON_MSG, INPUT);
  pinMode (BUTTON_ENTER, INPUT);

  // Enable the CPU's internal 20k pull-up resistors on the button
  // inputs so they default to a "high" state
  digitalWrite (BUTTON_A, HIGH);
  digitalWrite (BUTTON_B, HIGH);
  digitalWrite (BUTTON_C, HIGH);
  digitalWrite (BUTTON_D, HIGH);
  digitalWrite (BUTTON_MSG, HIGH);
  digitalWrite (BUTTON_ENTER, HIGH); 

  // Disable timer0 since it can mess with the USB timing. Note that
  // this means some functions such as delay() will no longer work.
  TIMSK0&=!(1<<TOIE0);

  // Clear interrupts while performing time-critical operations
  cli();

  // Force re-enumeration so the host will detect us
  usbDeviceDisconnect();
  delayMs(250);
  usbDeviceConnect();

  // Set interrupts again
  sei();
}


/**
 * Main program loop. Scan for keypresses and send a matching keypress
 * event to the host
 * FIXME: currently repeats as fast as it can. Add transition detection
 */
void loop()
{
  UsbKeyboard.update();

  if (digitalRead(BUTTON_A) == LOW) {
    UsbKeyboard.sendKeyStroke(KEY_A);
    digitalWrite(ledPin, !digitalRead(ledPin)); // Toggle status LED
  }

  if (digitalRead(BUTTON_B) == LOW) {
    UsbKeyboard.sendKeyStroke(KEY_B);
    digitalWrite(ledPin, !digitalRead(ledPin)); // Toggle status LED
  }

  if (digitalRead(BUTTON_C) == LOW) {
    UsbKeyboard.sendKeyStroke(KEY_C);
    digitalWrite(ledPin, !digitalRead(ledPin)); // Toggle status LED
  }

  if (digitalRead(BUTTON_D) == LOW) {
    UsbKeyboard.sendKeyStroke(KEY_D);
    digitalWrite(ledPin, !digitalRead(ledPin)); // Toggle status LED
  }

  if (digitalRead(BUTTON_MSG) == LOW) {
    UsbKeyboard.sendKeyStroke(KEY_H, MOD_SHIFT_LEFT);
    UsbKeyboard.sendKeyStroke(KEY_E);
    UsbKeyboard.sendKeyStroke(KEY_L);
    UsbKeyboard.sendKeyStroke(KEY_L);
    UsbKeyboard.sendKeyStroke(KEY_O);
    UsbKeyboard.sendKeyStroke(KEY_SPACE);
    UsbKeyboard.sendKeyStroke(KEY_W, MOD_SHIFT_LEFT);
    UsbKeyboard.sendKeyStroke(KEY_O);
    UsbKeyboard.sendKeyStroke(KEY_R);
    UsbKeyboard.sendKeyStroke(KEY_L);
    UsbKeyboard.sendKeyStroke(KEY_D);
    UsbKeyboard.sendKeyStroke(KEY_ENTER);
    digitalWrite(ledPin, !digitalRead(ledPin)); // Toggle status LED
  }

  if (digitalRead(BUTTON_ENTER) == LOW) {
    UsbKeyboard.sendKeyStroke(KEY_ENTER);
    digitalWrite(ledPin, !digitalRead(ledPin)); // Toggle status LED
  }
}


/**
 * Define our own delay function so that we don't have to rely on
 * operation of timer0, the interrupt used by the internal delay()
 */
void delayMs(unsigned int ms)
{
  for (int i = 0; i < ms; i++) {
    delayMicroseconds(1000);
  }
}

Of course it failed. It says it need a library from (Project Log : Arduino USB - ProjectLogArduinoUSB). So I downloaded it and copied the library “UsbKeyboard” into my Arduino IDE libraries. Attempted to compile again and it failed again.

Well in the UsbKeyboard library there is a text file “ArduinoNotes.txt” which says among other things:

At present the IDE won’t compile our library so it needs to be pre-compiled with:
avr-g++ -Wall -Os -I. -DF_CPU=16000000 -mmcu=atmega168 -c usbdrvasm.S -c usbdrv.c

So from the command line in the library I run:

C:\Arduino\arduino-1.0.1\libraries\UsbKeyboard>C:\Arduino\arduino-1.0.1\hardware\tools\avr\bin\avr-g++.exe -Wall -Os -I. -DF_CPU=16000000 -mmcu=atmega328p -c usbdrvasm.S -c usbdrv.c
usbdrv.c:70: warning: only initialized variables can be placed into program memory area
usbdrv.c:80: warning: only initialized variables can be placed into program memory area
usbdrv.c:89: warning: only initialized variables can be placed into program memory area
usbdrv.c:111: warning: only initialized variables can be placed into program memory area
usbdrv.c:142: warning: only initialized variables can be placed into program memory area

Again I try and fail to compile and link the sketch. I get the following errors:

VirtualUsbKeyboard.cpp.o: In function UsbKeyboardDevice': C:\Arduino\arduino-1.0.1\libraries\UsbKeyboard/UsbKeyboard.h:139: undefined reference to usbInit()’
VirtualUsbKeyboard.cpp.o: In function UsbKeyboardDevice::update()': C:\Arduino\arduino-1.0.1\libraries\UsbKeyboard/UsbKeyboard.h:150: undefined reference to usbPoll()’

At this point I have hit a wall. I’m not sure what to try next. So near and yet so far.

What is the next step? What has worked for you? Does the new IDE not support this? Do I have an out of date library?

As I said above, those functions appear to be in usbdrvasm.S. You need to get that into your project somehow.

[quote author=Nick Gammon link=topic=106835.msg805182#msg805182 date=1337894900] As I said above, those functions appear to be in usbdrvasm.S. You need to get that into your project somehow. [/quote] The function "usbCrc16Append" appears to be in "usbdrvasm.S", however that nolonger appears to be an issue. I seems that the compile from the command line resolved that issue. Functions "usbInit()" and "usbPoll()" are defined in "usbdrv.c" and "usbdrv.h". I'm not sure why it is failing to link. One possibly, that I have not investigate, is that the functions are conditionally compiled and the conditions where not been met.

OK, you may have compiled them but the IDE doesn't know to link them:

C:\Arduino\arduino-1.0.1\hardware\tools\avr\bin\avr-g++.exe -Wall -Os -I. -DF_CPU=16000000 -mmcu=atmega328p  -c usbdrvasm.S  -c usbdrv.c

I'm not sure how to get it do that. Maybe do the link step manually and add in the extra .o file?

Here is the verbose output from the IDE

C:\Arduino\arduino-1.0.1\hardware\tools\avr\bin\avr-g++ -c -g -Os -Wall -fno-exceptions -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -MMD -DUSB_VID=null -DUSB_PID=null -DARDUINO=101 -IC:\Arduino\arduino-1.0.1\hardware\arduino\cores\arduino -IC:\Arduino\arduino-1.0.1\hardware\arduino\variants\eightanaloginputs -IC:\Arduino\arduino-1.0.1\libraries\UsbKeyboard .\Temp\build7823043113122028301.tmp\VirtualUsbKeyboard.cpp -o .\Temp\build7823043113122028301.tmp\VirtualUsbKeyboard.cpp.o 
In file included from VirtualUsbKeyboard.cpp:23:
[color=red]
C:\Arduino\arduino-1.0.1\libraries\UsbKeyboard/UsbKeyboard.h:36: warning: only initialized variables can be placed into program memory area
[/color]
C:\Arduino\arduino-1.0.1\hardware\tools\avr\bin\avr-gcc -c -g -assembler-with-cpp -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=101 -DUSB_VID=null -DUSB_PID=null -IC:\Arduino\arduino-1.0.1\hardware\arduino\cores\arduino -IC:\Arduino\arduino-1.0.1\hardware\arduino\variants\eightanaloginputs -IC:\Arduino\arduino-1.0.1\libraries\UsbKeyboard -IC:\Arduino\arduino-1.0.1\libraries\UsbKeyboard\utility C:\Arduino\arduino-1.0.1\libraries\UsbKeyboard\usbdrvasm.S -o.\Temp\build7823043113122028301.tmp\UsbKeyboard\usbdrvasm.S.o 
C:\Arduino\arduino-1.0.1\hardware\tools\avr\bin\avr-gcc -c -g -Os -Wall -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -MMD -DUSB_VID=null -DUSB_PID=null -DARDUINO=101 -IC:\Arduino\arduino-1.0.1\hardware\arduino\cores\arduino -IC:\Arduino\arduino-1.0.1\hardware\arduino\variants\eightanaloginputs -IC:\Arduino\arduino-1.0.1\libraries\UsbKeyboard -IC:\Arduino\arduino-1.0.1\libraries\UsbKeyboard\utility C:\Arduino\arduino-1.0.1\libraries\UsbKeyboard\oddebug.c -o .\Temp\build7823043113122028301.tmp\UsbKeyboard\oddebug.c.o 
C:\Arduino\arduino-1.0.1\hardware\tools\avr\bin\avr-gcc -c -g -Os -Wall -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -MMD -DUSB_VID=null -DUSB_PID=null -DARDUINO=101 -IC:\Arduino\arduino-1.0.1\hardware\arduino\cores\arduino -IC:\Arduino\arduino-1.0.1\hardware\arduino\variants\eightanaloginputs -IC:\Arduino\arduino-1.0.1\libraries\UsbKeyboard -IC:\Arduino\arduino-1.0.1\libraries\UsbKeyboard\utility C:\Arduino\arduino-1.0.1\libraries\UsbKeyboard\usbdrv.c -o .\Temp\build7823043113122028301.tmp\UsbKeyboard\usbdrv.c.o 
C:\Arduino\arduino-1.0.1\hardware\tools\avr\bin\avr-gcc -c -g -Os -Wall -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -MMD -DUSB_VID=null -DUSB_PID=null -DARDUINO=101 -IC:\Arduino\arduino-1.0.1\hardware\arduino\cores\arduino -IC:\Arduino\arduino-1.0.1\hardware\arduino\variants\eightanaloginputs C:\Arduino\arduino-1.0.1\hardware\arduino\cores\arduino\WInterrupts.c -o .\Temp\build7823043113122028301.tmp\WInterrupts.c.o 
C:\Arduino\arduino-1.0.1\hardware\tools\avr\bin\avr-g++ -c -g -Os -Wall -fno-exceptions -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -MMD -DUSB_VID=null -DUSB_PID=null -DARDUINO=101 -IC:\Arduino\arduino-1.0.1\hardware\arduino\cores\arduino -IC:\Arduino\arduino-1.0.1\hardware\arduino\variants\eightanaloginputs C:\Arduino\arduino-1.0.1\hardware\arduino\cores\arduino\main.cpp -o .\Temp\build7823043113122028301.tmp\main.cpp.o 
C:\Arduino\arduino-1.0.1\hardware\tools\avr\bin\avr-g++ -c -g -Os -Wall -fno-exceptions -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -MMD -DUSB_VID=null -DUSB_PID=null -DARDUINO=101 -IC:\Arduino\arduino-1.0.1\hardware\arduino\cores\arduino -IC:\Arduino\arduino-1.0.1\hardware\arduino\variants\eightanaloginputs C:\Arduino\arduino-1.0.1\hardware\arduino\cores\arduino\USBCore.cpp -o .\Temp\build7823043113122028301.tmp\USBCore.cpp.o 
.\Temp\build7823043113122028301.tmp\main.cpp.o 
.\Temp\build7823043113122028301.tmp\USBCore.cpp.o 
C:\Arduino\arduino-1.0.1\hardware\tools\avr\bin\avr-gcc -Os -Wl,--gc-sections -mmcu=atmega328p -o .\Temp\build7823043113122028301.tmp\VirtualUsbKeyboard.cpp.elf .\Temp\build7823043113122028301.tmp\VirtualUsbKeyboard.cpp.o .\Temp\build7823043113122028301.tmp\UsbKeyboard\usbdrvasm.S.o .\Temp\build7823043113122028301.tmp\UsbKeyboard\oddebug.c.o .\Temp\build7823043113122028301.tmp\UsbKeyboard\usbdrv.c.o .\Temp\build7823043113122028301.tmp\core.a -L.\Temp\build7823043113122028301.tmp -lm 
[color=red]
VirtualUsbKeyboard.cpp.o: In function `UsbKeyboardDevice':
C:\Arduino\arduino-1.0.1\libraries\UsbKeyboard/UsbKeyboard.h:139: undefined reference to `usbInit()'
VirtualUsbKeyboard.cpp.o: In function `UsbKeyboardDevice::update()':
C:\Arduino\arduino-1.0.1\libraries\UsbKeyboard/UsbKeyboard.h:150: undefined reference to `usbPoll()'
[/color]

So it appears that usbdrvasm.S was assembled as the following command was given without errors.

C:\Arduino\arduino-1.0.1\hardware\tools\avr\bin\avr-gcc -c -g -assembler-with-cpp -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=101 -DUSB_VID=null -DUSB_PID=null -IC:\Arduino\arduino-1.0.1\hardware\arduino\cores\arduino -IC:\Arduino\arduino-1.0.1\hardware\arduino\variants\eightanaloginputs -IC:\Arduino\arduino-1.0.1\libraries\UsbKeyboard -IC:\Arduino\arduino-1.0.1\libraries\UsbKeyboard\utility C:\Arduino\arduino-1.0.1\libraries\UsbKeyboard\usbdrvasm.S -o.\Temp\build7823043113122028301.tmp\UsbKeyboard\usbdrvasm.S.o

It looks like usbdrv.c was compiled without error.

C:\Arduino\arduino-1.0.1\hardware\tools\avr\bin\avr-gcc -c -g -Os -Wall -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -MMD -DUSB_VID=null -DUSB_PID=null -DARDUINO=101 -IC:\Arduino\arduino-1.0.1\hardware\arduino\cores\arduino -IC:\Arduino\arduino-1.0.1\hardware\arduino\variants\eightanaloginputs -IC:\Arduino\arduino-1.0.1\libraries\UsbKeyboard -IC:\Arduino\arduino-1.0.1\libraries\UsbKeyboard\utility C:\Arduino\arduino-1.0.1\libraries\UsbKeyboard\usbdrv.c -o .\Temp\build7823043113122028301.tmp\UsbKeyboard\usbdrv.c.o

And of course the sketch was compiled with one warning.

C:\Arduino\arduino-1.0.1\hardware\tools\avr\bin\avr-g++ -c -g -Os -Wall -fno-exceptions -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -MMD -DUSB_VID=null -DUSB_PID=null -DARDUINO=101 -IC:\Arduino\arduino-1.0.1\hardware\arduino\cores\arduino -IC:\Arduino\arduino-1.0.1\hardware\arduino\variants\eightanaloginputs -IC:\Arduino\arduino-1.0.1\libraries\UsbKeyboard .\Temp\build7823043113122028301.tmp\VirtualUsbKeyboard.cpp -o .\Temp\build7823043113122028301.tmp\VirtualUsbKeyboard.cpp.o In file included from VirtualUsbKeyboard.cpp:23:

C:\Arduino\arduino-1.0.1\libraries\UsbKeyboard/UsbKeyboard.h:36: warning: only initialized variables can be placed into program memory area

The link (or I think it is the link) seems to include all the necessary modules

C:\Arduino\arduino-1.0.1\hardware\tools\avr\bin\avr-gcc -Os -Wl,--gc-sections -mmcu=atmega328p -o .\Temp\build7823043113122028301.tmp\VirtualUsbKeyboard.cpp.elf .\Temp\build7823043113122028301.tmp\VirtualUsbKeyboard.cpp.o .\Temp\build7823043113122028301.tmp\UsbKeyboard\usbdrvasm.S.o .\Temp\build7823043113122028301.tmp\UsbKeyboard\oddebug.c.o .\Temp\build7823043113122028301.tmp\UsbKeyboard\usbdrv.c.o .\Temp\build7823043113122028301.tmp\core.a -L.\Temp\build7823043113122028301.tmp -lm

I'm not sure what I would do different.

Can you confirm that in your usbdrv.h file you have the "extern C" line as shown below?

#ifdef __cplusplus
extern "C"{
#endif
USB_PUBLIC void usbInit(void);
/* This function must be called before interrupts are enabled and the main
 * loop is entered. We exepct that the PORT and DDR bits for D+ and D- have
 * not been changed from their default status (which is 0). If you have changed
 * them, set both back to 0 (configure them as input with no internal pull-up).
 */
USB_PUBLIC void usbPoll(void);

There are 3 functions defined within ‘extern “C”{’ but none of them are usbInit or usbPoll.

I have attached the file.

usbdrv.h (30.4 KB)

Nick, Yet again you prove that "You Are Da Man".

I made the change that you pointed to and it now compiles. I don't know if it runs but am an happy with progress. Progress in the right direction is even better.

Now if this worked, Why?

Look up C++ "name mangling".

I got it to compile and link but I still can’t get it to work.

It appears that the Nano is being “reset” over and over again. My code is:

// Arduino Digital Pin 2 == Port D=Bit 2 == D+      (INT0)
// Arduino Digital Pin 4 == Port D=Bit 4 == D-
// Arduino Digital Pin 5 == Port D=Bit 5 == Pull-Up
#include "UsbKeyboard.h"
#define BUTTON 12
#define BYPASS_TIMER_ISR 1  // If the timer isr is corrected to not take so long change this to 0.

/* Define our own delay function so that we don't have to rely on operation of timer0, the interrupt used by the internal delay() */
void delayMs(unsigned int ms) {
#if BYPASS_TIMER_ISR
  for (; ms > 0; ms--) { delayMicroseconds(1000); }
#else
  delay(ms);
#endif
}

void setup() {
  static uint8_t iCnt=0;
  Serial.begin(9600);
  Serial.print(" Setup Cnt="); Serial.println(++iCnt);
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(BUTTON, INPUT_PULLUP);
#if BYPASS_TIMER_ISR
  // Disable timer0 since it can mess with the USB timing.
  // Note: that this means some functions such as delay() will no longer work.
  TIMSK0&=!(1<<TOIE0);
#endif

  cli();  // Clear interrupts while performing time-critical operations
  
  usbDeviceDisconnect();   // Force re-enumeration so the host will detect us
  delayMs(250);
  usbDeviceConnect();

  sei(); // Set interrupts again
}

void loop() {
  UsbKeyboard.update();

  if (digitalRead(BUTTON) == LOW) {
    Serial.print("Botton Pressed");
    digitalWrite(LED_BUILTIN, HIGH);
    UsbKeyboard.sendKeyStroke(KEY_H, MOD_SHIFT_LEFT);
    UsbKeyboard.sendKeyStroke(KEY_E);
    UsbKeyboard.sendKeyStroke(KEY_L);
    UsbKeyboard.sendKeyStroke(KEY_L);
    UsbKeyboard.sendKeyStroke(KEY_O);

    UsbKeyboard.sendKeyStroke(KEY_SPACE);

    UsbKeyboard.sendKeyStroke(KEY_W, MOD_SHIFT_LEFT);
    UsbKeyboard.sendKeyStroke(KEY_O);
    UsbKeyboard.sendKeyStroke(KEY_R);
    UsbKeyboard.sendKeyStroke(KEY_L);
    UsbKeyboard.sendKeyStroke(KEY_D);

    UsbKeyboard.sendKeyStroke(KEY_ENTER);

    delayMs(20);
    while (digitalRead(BUTTON) == LOW);
    Serial.println(",  Botton Released");
    digitalWrite(LED_BUILTIN, LOW);
  }
}

I put a print statement at the top of the setup() function. My results are:

 Setup Cnt=1
@Setup Cnt=1
 Setup Cnt=1
 Setup Cnt=1
 Setup Cnt=1
 Setup Cnt=1
 Setup Cnt=1
@Setup Cnt=1
@Setup Cnt=1
 Setup Cnt=1
@Setup Cnt=1
 Setup Cnt=1
@Setup Cnt=1
@Setup Cnt=1
 Setup Cnt=1
@Setup Cnt=1
 Setup Cnt=1
 Setup Cnt=1
 Setup Cnt=1
 Setup Cnt=1
 Setup Cnt=1
 Setup Cnt=1
 Setup Cnt=1
 Setup Cnt=1
 Setup Cnt=1
@Setup Cnt=1
 Setup Cnt=1
 Setup Cnt=1
 Setup Cnt=1
@Setup Cnt=1
@Setup Cnt=1
 Setup Cnt=1
 Setup Cnt=1
 Setup Cnt=1
@Setup Cnt=1
@Setup Cnt=1

Since iCnt is a static that is being incremented, it appears that the static variable is being initialized.

I have attached the USB library I am using as well.

HELP anyone.

UsbKeyboard.zip (115 KB)