Skip to content

Instantly share code, notes, and snippets.

@HaxNobody
Last active July 19, 2022 02:23
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save HaxNobody/7bde369d7a41348b8b91c1a4f358ea4a to your computer and use it in GitHub Desktop.
Save HaxNobody/7bde369d7a41348b8b91c1a4f358ea4a to your computer and use it in GitHub Desktop.
Physical mute button for Zoom using an ATTiny85/Digispark and the Micronucleus bootloader to allow programming with the Arduino IDE
/*
Thanks to Elliotmade for the inspiration on this project
https://elliotmade.com/2020/04/23/physical-mute-button-for-zoom-meetings/
Refactored by HaxNobody to extend functionalty and add comments for my own understanding
This program will send USB HID keyboard presses to bring the Zoom window into
the foreground and activate microphone and video functions.
* A momentary press on button 1 will toggle mute on or off.
* Press and hold button 1 to activate PTT (Push-to-Talk) functionality.
* A momentary press on button 2 will toggle video on or off.
Unfortunately, exiting a meeting with only key presses is no longer possible in Zoom, so I have removed that feature.
*/
#include <DigiKeyboard.h> // Library for sending keystrokes as an HID device over USB
#include <OneButton.h> // Library for button input functions
#include <FastLED.h> // Library for controlling LEDs with high speed math
#define LedBreatheSpeed 12 // Speed of LED breathing animation in BPM
#define LedMinBrightness 5 // Minimum brightness value
OneButton button1(
0, // Pin Number
true, // Input is active LOW
true // Enable internal pull-up resistor
);
OneButton button2(
2, // Pin Number
true, // Input is active LOW
true // Enable internal pull-up resistor
);
void setup() {
button1.attachClick(button1click); // Set up button 1 for Zoom mute toggle function
button1.attachLongPressStart(button1longPressStart); // Set up button 1 for Zoom temporary unmute function
button1.attachLongPressStop(button1longPressStop); // Set up button 1 for Zoom temporary unmute release function
button2.attachClick(button2click); // Set up button 2 for Zoom video toggle function
button1.setPressTicks(300); // Reduce long-press delay for button 1 to make temporary unmute more responsive
DigiKeyboard.delay(50); // Delay before entering loop
pinMode(1, OUTPUT); // Initialize LED pin
}
void loop() {
DigiKeyboard.update(); // Maintain USB communication
button1.tick(); // Check status of buttons in a continuous loop
button2.tick();
analogWrite(1, beatsin8(LedBreatheSpeed, LedMinBrightness)); // Make LED "breathe"
}
// This function will be called when button 1 is pressed for more than 50ms and less than 300ms.
void button1click() {
DigiKeyboard.sendKeyStroke(0); // Clear any current key presses
DigiKeyboard.sendKeyStroke(0, MOD_SHIFT_LEFT | MOD_CONTROL_LEFT | MOD_ALT_LEFT); // Bring Zoom into foreground
DigiKeyboard.delay(50); // Give Zoom a chance to get into the foreground
DigiKeyboard.sendKeyStroke(KEY_A, MOD_ALT_LEFT); // Toggle mute on or off in Zoom
}
// This function will be called when button 2 is pressed for more than 50ms and less than 300ms.
void button2click() {
DigiKeyboard.sendKeyStroke(0); // Clear any current key presses
DigiKeyboard.sendKeyStroke(0, MOD_SHIFT_LEFT | MOD_CONTROL_LEFT | MOD_ALT_LEFT); // Bring Zoom into foreground
DigiKeyboard.delay(50); // Give Zoom a chance to get into the foreground
DigiKeyboard.sendKeyStroke(KEY_V, MOD_ALT_LEFT); // Toggle video on or off in Zoom
}
// This function will be called when button 1 is pressed and held down for more than 300ms.
void button1longPressStart() {
DigiKeyboard.sendKeyStroke(0); // Clear any current key presses
DigiKeyboard.sendKeyStroke(0, MOD_SHIFT_LEFT | MOD_CONTROL_LEFT | MOD_ALT_LEFT); // Bring Zoom into foreground
DigiKeyboard.delay(50); // Give Zoom a chance to get into the foreground
DigiKeyboard.sendKeyPress(KEY_SPACE); // Press and hold the space key to trigger zoom to temporarily unmute
}
// This function will be called when button 1 is released after being held down.
void button1longPressStop() {
DigiKeyboard.delay(300); // Delay to prevent cutting off the speaker's last word
DigiKeyboard.sendKeyPress(0); // Release space key to re-mute Zoom after temporary unmute
}
@HaxNobody
Copy link
Author

Added LED functionality for fun in rev 2.

@jonlait
Copy link

jonlait commented Dec 14, 2020

Hi Hax,
I notice that you use pin ‘0’ and pin ‘2’ why not use pin ‘0’ and ‘1’?

How would I go about adding a 3rd button instead of the long press on button one?
Would adding a 3rd button be as easy as defining pin 3 as in line 22-26, copy line 37 and change it to button3, and copying lines 59-65 and changing line 64 with another zoom shortcut, eg Alt-f2 display gallery view?

Also when it come to the wiring, can you use a single resistor for both (or 3) buttons, or does it need to be a resistor per button?

Thanks very much.

Jon.

@jonlait
Copy link

jonlait commented Dec 14, 2020

Sorry, just adding a PS, where can I find your wiring diagram, as I am interested in where you added in the led.

@HaxNobody
Copy link
Author

HaxNobody commented Dec 14, 2020

I notice that you use pin ‘0’ and pin ‘2’ why not use pin ‘0’ and ‘1’?

Pin 1 on these devices is tied to an LED that is mounted on the board. If you want to use it as an input, you have to disconnect the LED or break it off the board. As you can see, I make the LED fade just as a bit of extra visual fun.

How would I go about adding a 3rd button instead of the long press on button one?

Since pins 3 and 4 are used for USB communications, you cannot use them, however there is still pin 5 available for further inputs. Pin 5 isn't as powerful when used as an output, but works fine as an input. It's also a possibility that pin 5 doesn't have an internal pullup, so you may need an external pullup resistor (not sure, haven't tested).

Would adding a 3rd button be as easy as defining pin 3 as in line 22-26, copy line 37 and change it to button3, and copying lines 59-65 and changing line 64 with another zoom shortcut, eg Alt-f2 display gallery view?

Correct.

Also when it come to the wiring, can you use a single resistor for both (or 3) buttons, or does it need to be a resistor per button?

For pins 0-2, they have internal pullup resistors which are turned on inside the code. External resistors aren't required.

@HaxNobody
Copy link
Author

I just verified that Pin 5 (the reset pin) does have an internal pullup as well.

@jonlait
Copy link

jonlait commented Dec 14, 2020

Thanks for that simple explanation, I will try and see how pin 5 works!
Now I know why it didn’t work when I wired up pins 0 and 1 on elliotsmade instructable, and also when I tried to do my own 3 button version using pin 3!
Thanks for the speedy answer.

@HaxNobody
Copy link
Author

Thanks for that simple explanation, I will try and see how pin 5 works!
Now I know why it didn’t work when I wired up pins 0 and 1 on elliotsmade instructable, and also when I tried to do my own 3 button version using pin 3!
Thanks for the speedy answer.

No problem.

Sorry, just adding a PS, where can I find your wiring diagram, as I am interested in where you added in the led.

I haven't made one, sorry. As I mentioned, the LED is on the board and I haven't added it, and since there is no need for pullup resistors the wiring is literally just switch contacts between the pins and the ground wire.

@jonlait
Copy link

jonlait commented Dec 14, 2020

That’s so helpful, I will have to boot up the pc now and copy the code into Arduino and try adding the 3rd button.
Can I come back to you if I mess it up completely or don’t code it right?

@HaxNobody
Copy link
Author

That’s so helpful, I will have to boot up the pc now and copy the code into Arduino and try adding the 3rd button.
Can I come back to you if I mess it up completely or don’t code it right?

I don't know how much help I can be on the software side, it took me a while to figure out. I think the important part is to make sure you have the right libraries and have the digispark setup for programming, which doesn't work out of the box with arduino unless you tweak the IDE.

@jonlait
Copy link

jonlait commented Dec 14, 2020

I managed to get elliots one working, but couldn’t work out how to add the extra 3 button.
Your code however explains each step more simply.
I am trying to remove the Pitt long press start and release the button to stop, to long press once to stop the camera and long press again to start it.
So button 1 will be mute, long hold stop video.
Button 2 raise hand
Button 3 switch to gallery view.
But I keep getting a fault (no member named) on the long press when I try to upload it.
I will keep trying!

@jonlait
Copy link

jonlait commented Dec 14, 2020

Sorry Pitt should be push to talk

@HaxNobody
Copy link
Author

I managed to get elliots one working, but couldn’t work out how to add the extra 3 button.
Your code however explains each step more simply.
I am trying to remove the Pitt long press start and release the button to stop, to long press once to stop the camera and long press again to start it.
So button 1 will be mute, long hold stop video.
Button 2 raise hand
Button 3 switch to gallery view.
But I keep getting a fault (no member named) on the long press when I try to upload it.
I will keep trying!

I found out just now that the FastLED library is broken if you use the latest version. If you aren't using that feature, remove it to save space. Otherwise, use version 3.3.2 instead of the latest 3.3.3.

To change the long press behavior to a toggle function instead of a press-and-hold function, use sendKeyStroke instead of sendKeyPress. Also, adjust the value of setPressTicks to change how long of a delay when holding the button down before it takes action.

I think you could completely remove attachLongPressStop and its associated function since you are sending a one-shot keystroke and not holding a button that needs to be released later.

@kingfisher1234
Copy link

"Unfortunately, exiting a meeting with only key presses is no longer possible in Zoom, so I have removed that feature."

This still works (In Windows) Here is my code:

// This function will be called when button 1 is pressed and held down for more than 300ms.
void button1longPressStart() {
  DigiKeyboard.sendKeyStroke(0); // Clear any current key presses
  DigiKeyboard.sendKeyStroke(0, MOD_SHIFT_LEFT | MOD_CONTROL_LEFT | MOD_ALT_LEFT);
  DigiKeyboard.delay(50);
  DigiKeyboard.sendKeyStroke(KEY_Q, MOD_ALT_LEFT);
  DigiKeyboard.delay(50);
  DigiKeyboard.sendKeyStroke(KEY_ENTER);
}

@kingfisher1234
Copy link

I'm trying to get the code to work on a Mac does anyone have example KeyStrokes?

@kingfisher1234
Copy link

Here is the logic for Mute on a Mac
DigiKeyboard.sendKeyStroke(KEY_A, MOD_GUI_LEFT | MOD_CMD_LEFT | MOD_SHIFT_LEFT); // Toggle mute on or off in Zoom

And here is the logic for ending a meeting

  DigiKeyboard.sendKeyStroke(0); // Clear any current key presses
  DigiKeyboard.delay(50);
  DigiKeyboard.sendKeyStroke(KEY_W, MOD_CMD_LEFT);
  DigiKeyboard.delay(500);
  DigiKeyboard.sendKeyStroke(KEY_ENTER);
  DigiKeyboard.delay(500);

I had to add "#define MOD_CMD_LEFT 0x00000008" for the comand key

And unlike on a PC, there doesn't appear to be a zooms shortcut to bring the window into focus

@kingfisher1234
Copy link

Here is a Mac Version if anyone is looking for it:
https://gist.github.com/kingfisher1234/caf351bed786f9050e1fa28c3352ded9

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment