Leonardo Keyboard Volume Control Help

Hi,

I'm new to the leonardo and have been trying to control the PCs volume up/down and mute using the leonardo.

I can send characters and the normal modifiers just fine but it doesn't look like there is support for the volume controls. I looked through (http://www.usb.org/developers/devclass_docs/Hut1_12v2.pdf) and tried sending those hex values 7F, 80 and 81 for the volume controls but it doesn't seem to work.

Does anyone know how to support for these?

Thanks,
Ray

The volume control buttons on most laptops and some keyboards are generally not keycodes but instead handled by ACPI or similar. What Operating System are you running?

Windows 7

That seems to use another program to do the job, it doesn't really show what I need to send. WIN + PGUP doesn't work.

I'm looking to do the same thing - I've made progress, but still can't get it to work.

If you take a look at the hardware/arduino/cores/arduino/USBAPI.h file, it lists out some #defines for button presses:

#define KEY_LEFT_CTRL		0x80
#define KEY_LEFT_SHIFT		0x81
#define KEY_LEFT_ALT		0x82
#define KEY_LEFT_GUI		0x83
#define KEY_RIGHT_CTRL		0x84
#define KEY_RIGHT_SHIFT		0x85
#define KEY_RIGHT_ALT		0x86
#define KEY_RIGHT_GUI		0x87

#define KEY_UP_ARROW		0xDA
#define KEY_DOWN_ARROW		0xD9
#define KEY_LEFT_ARROW		0xD8
#define KEY_RIGHT_ARROW		0xD7

If you compare this to the USB specification (USB HID usage table), you'll find they don't match:

	0x4E	Keyboard PageDown
	0x4F	Keyboard RightArrow
	0x50	Keyboard LeftArrow
	0x51	Keyboard DownArrow
	0x52	Keyboard UpArrow
	0xE0	Keyboard LeftControl
	0xE1	Keyboard LeftShift
	0xE2	Keyboard LeftAlt
	0xE3	Keyboard Left GUI
	0xE4	Keyboard RightControl
	0xE5	Keyboard RightShift
	0xE6	Keyboard RightAlt
	0xE7	Keyboard Right GUI

If you take a look in hardware/arduino/cores/arduino/HID.cpp file, in the 'press' function, you see this:

size_t Keyboard_::press(uint8_t k) 
{
	uint8_t i;
	if (k >= 136) {			// it's a non-printing key (not a modifier)
		k = k - 136;
	} else if (k >= 128) {	// it's a modifier key
		_keyReport.modifiers |= (1<<(k-128));
		k = 0;
	} else {				// it's a printing key
		k = pgm_read_byte(_asciimap + k);
		if (!k) {
			setWriteError();
			return 0;
		}
		if (k & 0x80) {						// it's a capital letter or other character reached with shift
			_keyReport.modifiers |= 0x02;	// the left shift modifier
			k &= 0x7F;
		}
	}

My first gripe - As a programmer, mixing decimal notation and hex notation is a huge pain. 136=0x88 - which is means that the "KEY_LEFT_CTRL" block of #defines will be caught there. They call these 'Modifiers'. 128=0x80 - anything that falls below this is a standard ASCII key, and they look it up to find the HID code.

The reason they do this is so you can do something like "Keyboard.print("A")" and it'll press the 'A' key. Very helpful for printing text, very NOT helpful if you want to press any old key on the keyboard.

What we want to do is press these keys:

	0x7F	Keyboard Mute
	0x80	Keyboard Volume Up
	0x81	Keyboard Volume Down

But if the code is going to subtract 136 (0x88) from them, it is literally impossible to get it to work (with the current 'press' code). Essentially you're limited to only printing the first 256-136 = 120 keys - from 0x00->0x78. JUST SHORT of what we need!

Since that is the case - I went ahead and made some new functions. I made a press_direct and release_direct, which don't do any fiddling with the numbers, they just send it out as-is. I tested my code by passing in the real HID values for letters, and it printed them as expected. Unfortunately - the volume up/down/mute functions STILL don't work!! :0

According to some sources, Windows just doesn't implement the functions in this way. So if the application your sending the keys to will read them, it'll work, but Windows won't pick it up directly. Linux and OS X will apparently work fine.

Hey CyberBil,

is there any chance that you could post the codes to press_direct and release_direct functions which you wrote? I tried to write them myself but witch out any luck.

I got the same problem as described above, but I'm running linux on a apple computer so it might work in my case. :slight_smile: fingers crossed.

Sorry about the slow reply - I had notifications turned off, and then left the planet. :slight_smile:

Unfortunately, I reverted my code, but here is what you can do if you want to test it out:

Open the file: Arduino-Install-Directory\hardware\arduino\cores\arduino\HID.cpp

Find the function: Keyboard_::press (and Keyboard_::release) in that file

Copy & paste that function, rename it to "press_direct", and remove the top portion of the code that tests for k >= 136, and setting modifiers, etc. Then you'll need to open USBAPI.h file, and find the class declaration for Keyboard_, and add a new function definition for your new "press_direct" function.

Sorry for not being able to just copy the code over, but this will get clobbered anytime you install a new version of the arduino code, and I'm not on the latest version.