Control PC Volume

The previous thread on this topic was back in December and the OP didn't follow up and I'm not getting a response there.

I have an Arduino Micro, that I want to control the volume of my Windows PC with. I'm only looking to have 3 inputs: Volume UP, Volume DOWN, and Ctrl+Alt+Delete.

Here is my program so far:

void setup() {
// put your setup code here, to run once:
pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
pinMode(4, INPUT_PULLUP);
char VolUp = 0xAF;
char VolDn = 0xAE;
char Delet = 0x2E;
char Alt = 0x12;
char Ctrl = 0x11;

}

void loop() {
// Volume UP:
if(digitalRead(2)==LOW){
Keyboard.begin;
Keyboard.print(VolUp);
delay(50);
Keyboard.end;
delay(10);
}

// Volume Down:
if(digitalRead(3)==LOW{
Keyboard.begin;
Keyboard.print(VolDn)
delay(50);
Keyboard.end;
delay(10);
}

// EMERGENCY
if(digitalRead(4)==LOW{
Keyboard.begin;
Keyboard.press(Ctrl);
delay(10);
Keyboard.press(Alt);
delay(10);
Keyboard.press(Delet);
delay(100);
Keyboard.releaseAll();
delay(1000);
Keyboard.end;
delay(10);

}

I'm at work right now and plan on making time this evening to try it out on my Uno board first. I don't understand scan codes or what Paul__B was getting at with his alternate keyboard codes either though.

You can't do that (easily) with the Uno board unless you have a USB shield or something.

The Micro has an ATmega32u4, which supports USB directly. The Uno has an ATmega328p, which does not support USB - it is connected through an Atmega16u2 (on the official boards, most of the clones have CH340G's or FT232s) which is acting as a USB->serial adapter.

The 16u2 on the official Uno board could be reprogrammed to act as HID, but this is a much bigger deal than doing it on the Micro.

So yeah, this is one case where doing it on the Uno first is a bad course of action. The analogous "big board" for the Micro is the Leonardo.

Just to be sure it's the same version. You're saying that the USB on this UNO isn't directly supported here?

I was wrong in my initial post. I have an Arduino mini, not a micro. It looks like this has the same issue as the Uno. :frowning:

Looks like this is the one I'll need.

Thank you very much for saving me that headache! :slight_smile:

Correct (also, that's a board from the arduino.org guys, not the real Arduino - there's some drama within Arduino that's resulted in two groups calling themselves Arduino - that's why the official store is empty. I just use chinese clones, and donate some of the savings to the real Arduino).

On normal Arduino boards, you only get USB serial. You can (with difficulty and ISP programming) get the 16u2 on the Uno to do other stuff, but then you're doing your project on the 16u2, not the 328p (which is the big mcu with all the pins available).

To do USB HID (pretending to be a keyboard or mouse) emulation you want something with a USB-capable chip (like the Micro or Leo, which are based on the 32u4)

Thank you for you help so far. I've ordered the Leonardo board.

Does my program look OK? Paul__B included the scan codes in his version of the Volume Up/Down, but I don't understand those or why they would be needed.

It looks like there's nothing that I can send directly from the Arduino that Windows will pickup as volume commands. Instead i came across this link where someone has written an AutoHotKey script that changes volume on the macro Win+PgUp / Win+PgDown.

void setup() {
// put your setup code here, to run once:
pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
pinMode(4, INPUT_PULLUP);
pinMode(5, INPUT_PULLUP);
Keyboard.begin();

}

void loop() {
// Volume UP:
if(digitalRead(2)==LOW){
Keyboard.press(KEY_LEFT_GUI);
Keyboard.write(KEY_PAGE_UP);
Keyboard.releaseAll();
delay(500);
}

// Volume Down:
if(digitalRead(3)==LOW){
Keyboard.press(KEY_LEFT_GUI);
Keyboard.write(KEY_PAGE_DOWN);
Keyboard.releaseAll();
delay(500);
}

// EMERGENCY:
if(digitalRead(4)==LOW){
Keyboard.press(KEY_LEFT_CTRL);
Keyboard.press(KEY_LEFT_ALT);
Keyboard.press(KEY_DELETE);
Keyboard.releaseAll();
delay(1500);
}

if(digitalRead(5)==LOW){
Keyboard.end();
}

}

This has got me up and running for now. If anyone has a way to accomplish this without needing an application to intercept and run in the middle please let me know. :slight_smile:

I think

Budwyzer:
Thank you for you help so far. I've ordered the Leonardo board.

Does my program look OK? Paul__B included the scan codes in his version of the Volume Up/Down, but I don't understand those or why they would be needed.

To send volume up/down keystrokes as if you were a multimedia keyboard, so you don't need to send the wrong keystrokes and run software on the PC to intercept and translate into volume up/down commands...

I just tried those and all it does is try to write 4O (4 and capital o) for Volume UP, and 6Q for Volume Down.

I just changed my code to use Alt+, or Alt+. , because i was having issues with so many repeated Windows Key presses and it would hang up and do crazy things when I tried typing. I tried Alt+< and Alt+> first but ran into issues with the shift key getting stuck. So basically avoid modifier keys at all costs.

void setup() {
// put your setup code here, to run once:
pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
pinMode(4, INPUT_PULLUP);
pinMode(5, INPUT_PULLUP);
Keyboard.begin();

}

void loop() {
// Volume UP:
if(digitalRead(2)==LOW){
// Hold Alt
Keyboard.press(KEY_LEFT_ALT);
// Press >
Keyboard.write(0x2E);
// Release All held keys
Keyboard.releaseAll();
delay(500);
}

// Volume Down:
if(digitalRead(3)==LOW){
// Hold Alt
Keyboard.press(KEY_LEFT_ALT);
// Press <
Keyboard.write(0x2C);
// Release All held keys
Keyboard.releaseAll();
delay(500);
}

// EMERGENCY:
if(digitalRead(4)==LOW){
// Hold the Left CTRL key
Keyboard.press(KEY_LEFT_CTRL);
// Hold the Left Alt Key
Keyboard.press(KEY_LEFT_ALT);
// Hold the Delete key
Keyboard.press(KEY_DELETE);
// Release all held keys
Keyboard.releaseAll();
delay(1500);
}

if(digitalRead(5)==LOW){
Keyboard.end();
}

}

According to this page the USB scan codes for VolumeUp and VolumeDown are 128 and 129. To get those scan codes through Keyboard.print() unchanged, add 136 to them:

const int AS_RAW_SCANCODE = 136;
Keyboard.print(128+AS_RAW_SCANCODE);  // VolumeUp
Keyboard.print(129+AS_RAW_SCANCODE);  // VolumeDown

I think the other thread was assuming you could use Windows scan codes (VolUp = 0xAF, VolDn = 0xAE) over USB but I don't think that is the case. The Keyboard library takes any value of 136 or more and sends it after subtracting 136.

The values 0xAE and 0xAF would produce USB scan codes 38 and 39 which would show up as the digits 9 and 0 (or '(' and ')' if Shift was pressed)

I couldn't get that to be recognized by Windows as anything other than ASCII characters either. So far, running the key combination through AutoHotKey is working pretty well though!

johnwasser:
According to this page the USB scan codes for VolumeUp and VolumeDown are 128 and 129. To get those scan codes through Keyboard.print() unchanged, add 136 to them:

const int AS_RAW_SCANCODE = 136;

Keyboard.print(128+AS_RAW_SCANCODE);  // VolumeUp
Keyboard.print(129+AS_RAW_SCANCODE);  // VolumeDown




I think the other thread was assuming you could use Windows scan codes (VolUp = 0xAF, VolDn = 0xAE) over USB but I don't think that is the case. The Keyboard library takes any value of 136 or more and sends it after subtracting 136.

The values 0xAE and 0xAF would produce USB scan codes 38 and 39 which would show up as the digits 9 and 0 (or '(' and ')' if Shift was pressed)

Sadly, I don't think your solution will work. True, if you can add 136 to your desired scan code it could work. However, the desired scan code is 128. 128+136=264. Keyboard.print() calls Keyboard.write() calls Keyboard.press(). write() and press() take a single uint8_t. 264 will not fit in 8 bits.