Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Media key support on macOS #3305

Closed
nbolton opened this issue Oct 13, 2014 · 33 comments
Closed

Media key support on macOS #3305

nbolton opened this issue Oct 13, 2014 · 33 comments

Comments

@nbolton
Copy link
Member

nbolton commented Oct 13, 2014

https://github.com/symless/synergy-enterprise/issues/55

Imported issue:

  • Author: Douglas Mayle
  • Date: 2012-09-19 02:29:36
  • Legacy ID: 3375

Steps to reproduce:

Synergy Mac Clients do not currently support Media keys for a couple of reasons:

  1. The Synergy keymap is built up from keyboard layouts, and keyboard layouts don't contains multimedia keys.
  2. CGEventCreateKeyboardEvent is unable to create a multimedia event, probably for the same reason as above.

I handle the first problem by manually adding these keys to the s_controlKeys structure. To handle the second problem, I wrote a separate application to listen in on and serialize these multimedia events. I then wrote a patch to build a custom event from these serialized events in the case of volume up, down, and mute. To my knowledge, this is the only way possible to simulate these keypresses (the other solution I've seen is to watch for these keypresses, and directly interact with the sound system, which introduces all sorts of edge cases not worth dealing with)

I can't see how to attach a file, so I'm pasting the contents of the patch into the 'Additional comments' section.

I believe I'm leaking CFDataRef's, though since I'm unsure as to the required lifetime with regards to posting the event, I've left it as an exercise for whomever accepts this patch. I'm not a Mac application developer, and given the number of times I press Vol Up/Down/Mute before launching, I'm okay with the leaks on my system, as long as the volume keys work.

Versions and operating systems:

I have only tested this on OSX Mountain Lion as a client, talking to a Linux (Ubuntu) server. The Linux server is running 1.4.10, and my patch was against trunk.

Temporary workarounds:

None

Additional comments:

Index: src/lib/platform/COSXKeyState.cpp
===================================================================
--- src/lib/platform/COSXKeyState.cpp   (revision 1659)
+++ src/lib/platform/COSXKeyState.cpp   (working copy)
@@ -36,6 +36,20 @@
 static const UInt32 s_superVK    = kVK_Command;
 static const UInt32 s_capsLockVK = kVK_CapsLock;
 static const UInt32 s_numLockVK  = kVK_ANSI_KeypadClear; // 71
+
+const UInt8 VolUp_Press[] = { 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x40, 0x35, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x40, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x37, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x02, 0xC0, 0x38, 0x44, 0x34, 0x00, 0x00, 0x44, 0x92, 0x20, 0x00, 0x00, 0x02, 0xC0, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x3A, 0xB0, 0xAB, 0x9F, 0x70, 0x00, 0x00, 0x17, 0x86, 0x00, 0x01, 0x40, 0x3B, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x40, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x6A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x6B, 0x00, 0x00, 0x07, 0x80, 0x00, 0x01, 0x40, 0x53, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0F, 0x40, 0x54, 0x00, 0x00, 0x0B, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+const UInt8 VolUp_Release[] = { 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x40, 0x35, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x40, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x37, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x02, 0xC0, 0x38, 0x44, 0x34, 0x00, 0x00, 0x44, 0x92, 0x20, 0x00, 0x00, 0x02, 0xC0, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x3A, 0xA9, 0xFE, 0x64, 0xF0, 0x00, 0x00, 0x17, 0x86, 0x00, 0x01, 0x40, 0x3B, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x40, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x6A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x6B, 0x00, 0x00, 0x07, 0x80, 0x00, 0x01, 0x40, 0x53, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0F, 0x40, 0x54, 0x00, 0x00, 0x0A, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+const UInt8 VolDown_Press[] = { 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x40, 0x35, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x40, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x37, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x02, 0xC0, 0x38, 0x43, 0xFE, 0x00, 0x00, 0x44, 0x9E, 0x00, 0x00, 0x00, 0x02, 0xC0, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x3A, 0x8C, 0x11, 0x65, 0xC0, 0x00, 0x00, 0x18, 0xCE, 0x00, 0x01, 0x40, 0x3B, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x40, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x6A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x6B, 0x00, 0x00, 0x07, 0x80, 0x00, 0x01, 0x40, 0x53, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0F, 0x40, 0x54, 0x00, 0x01, 0x0A, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+const UInt8 VolDown_Release[] = { 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x40, 0x35, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x40, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x37, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x02, 0xC0, 0x38, 0x43, 0xFE, 0x00, 0x00, 0x44, 0x9E, 0x00, 0x00, 0x00, 0x02, 0xC0, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x3A, 0x91, 0xCD, 0xB8, 0x60, 0x00, 0x00, 0x18, 0xCE, 0x00, 0x01, 0x40, 0x3B, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x40, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x6A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x6B, 0x00, 0x00, 0x07, 0x80, 0x00, 0x01, 0x40, 0x53, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0F, 0x40, 0x54, 0x00, 0x01, 0x0B, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+const UInt8 Mute_Press[] = { 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x40, 0x35, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x40, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x37, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x02, 0xC0, 0x38, 0x43, 0x99, 0x80, 0x00, 0x44, 0x5A, 0x40, 0x00, 0x00, 0x02, 0xC0, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x3A, 0x25, 0x88, 0x1E, 0xD8, 0x00, 0x00, 0x18, 0xFC, 0x00, 0x01, 0x40, 0x3B, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x40, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x6A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x6B, 0x00, 0x00, 0x07, 0x80, 0x00, 0x01, 0x40, 0x53, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0F, 0x40, 0x54, 0x00, 0x07, 0x0A, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+const UInt8 Mute_Release[] = { 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x40, 0x35, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x40, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x37, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x02, 0xC0, 0x38, 0x43, 0x99, 0x80, 0x00, 0x44, 0x5A, 0x40, 0x00, 0x00, 0x02, 0xC0, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x3A, 0x2B, 0xBA, 0x93, 0xA8, 0x00, 0x00, 0x18, 0xFC, 0x00, 0x01, 0x40, 0x3B, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x40, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x6A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x6B, 0x00, 0x00, 0x07, 0x80, 0x00, 0x01, 0x40, 0x53, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0F, 0x40, 0x54, 0x00, 0x07, 0x0B, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+
 #else
 // Hardcoded virtual key table on 10.4 and below.
 static const UInt32 s_shiftVK    = 56;
@@ -103,6 +117,11 @@
    { kKeyKP_Divide,    kVK_ANSI_KeypadDivide },
    { kKeyKP_Subtract,  kVK_ANSI_KeypadMinus },
    { kKeyKP_Enter,     kVK_ANSI_KeypadEnter },
+
+        // Multimedia keys with virtual key codes
+   { kKeyAudioUp,      kVK_VolumeUp },
+   { kKeyAudioDown,    kVK_VolumeDown },
+   { kKeyAudioMute,    kVK_Mute },
 #else
   // Hardcoded virtual key table on 10.4 and below.
    // cursor keys.
@@ -490,9 +509,35 @@
            LOG((CLOG_DEBUG1 "  %%%%%%%%03x (%%%%%%%%08x) %%%%%%%%s", keystroke.m_data.m_button.m_button, keystroke.m_data.m_button.m_client, keystroke.m_data.m_button.m_press ? "down" : "up"));

        // let system figure out character for us
-       ref = CGEventCreateKeyboardEvent(0, mapKeyButtonToVirtualKey(
-                                   keystroke.m_data.m_button.m_button),
-                               keystroke.m_data.m_button.m_press);
+       if (mapKeyButtonToVirtualKey(keystroke.m_data.m_button.m_button) == kVK_VolumeUp) {
+           if (keystroke.m_data.m_button.m_press) {
+               CFDataRef data_press = CFDataCreate(kCFAllocatorDefault, VolUp_Press, sizeof(VolUp_Press));
+               ref = CGEventCreateFromData(kCFAllocatorDefault, data_press);
+           } else {
+               CFDataRef data_release = CFDataCreate(kCFAllocatorDefault, VolUp_Release, sizeof(VolUp_Release));
+               ref = CGEventCreateFromData(kCFAllocatorDefault, data_release);
+           }
+       } else if (mapKeyButtonToVirtualKey(keystroke.m_data.m_button.m_button) == kVK_VolumeDown) {
+           if (keystroke.m_data.m_button.m_press) {
+               CFDataRef data_press = CFDataCreate(kCFAllocatorDefault, VolDown_Press, sizeof(VolDown_Press));
+               ref = CGEventCreateFromData(kCFAllocatorDefault, data_press);
+           } else {
+               CFDataRef data_release = CFDataCreate(kCFAllocatorDefault, VolDown_Release, sizeof(VolDown_Release));
+               ref = CGEventCreateFromData(kCFAllocatorDefault, data_release);
+           }
+       } else if (mapKeyButtonToVirtualKey(keystroke.m_data.m_button.m_button) == kVK_Mute) {
+           if (keystroke.m_data.m_button.m_press) {
+               CFDataRef data_press = CFDataCreate(kCFAllocatorDefault, Mute_Press, sizeof(Mute_Press));
+               ref = CGEventCreateFromData(kCFAllocatorDefault, data_press);
+           } else {
+               CFDataRef data_release = CFDataCreate(kCFAllocatorDefault, Mute_Release, sizeof(Mute_Release));
+               ref = CGEventCreateFromData(kCFAllocatorDefault, data_release);
+           }
+       } else {
+           ref = CGEventCreateKeyboardEvent(0, mapKeyButtonToVirtualKey(
+                                       keystroke.m_data.m_button.m_button),
+                                   keystroke.m_data.m_button.m_press);
+       }
        if (ref == NULL) {
            LOG((CLOG_CRIT "unable to create keyboard event for keystroke"));
        }
@nbolton
Copy link
Member Author

nbolton commented Oct 13, 2014

  • Author: Douglas Mayle
  • Date: 2013-02-01 18:32:43

Do you have any timeline on incorporating this? I was thinking of fixing some more Linux/OS X issues, but have been holding off since I didn't want to maintain my own source tree (I'd have to incorporate this patch, but develop against mainline while ignoring the patch... :-( )

@nbolton
Copy link
Member Author

nbolton commented Oct 13, 2014

  • Author: Douglas Mayle
  • Date: 2013-10-17 22:35:59

I've noticed that you've released a new version. Any chance this will get into the next one?

@nbolton
Copy link
Member Author

nbolton commented Oct 13, 2014

  • Author: James Vautin
  • Date: 2014-01-14 02:46:19

+1 .. this would be VERY useful! and it's already done and working!

@nbolton
Copy link
Member Author

nbolton commented Oct 13, 2014

  • Author: Nathan Rijksen
  • Date: 2014-03-10 01:40:13

Please devs, spare a few minutes of your time to integrate this patch. It adds significant functionality to your product.

@nbolton
Copy link
Member Author

nbolton commented Oct 13, 2014

  • Author: Chaim Leib Halbert
  • Date: 2014-03-12 08:46:22

+1 Pretty please!

@nbolton
Copy link
Member Author

nbolton commented Oct 13, 2014

  • Author: pipedowndjh .
  • Date: 2014-05-05 17:28:22

+1 Please do add this.

@nbolton
Copy link
Member Author

nbolton commented Oct 13, 2014

  • Author: Artur Wi?niewski
  • Date: 2014-05-28 12:52:43

+1 it's not that long time to incorporate this!

@nbolton
Copy link
Member Author

nbolton commented Oct 13, 2014

  • Author: Leonard Jonathan Oh
  • Date: 2014-07-04 19:49:42

+1

@nbolton
Copy link
Member Author

nbolton commented Oct 13, 2014

  • Author: Scott Kingsley Clark
  • Date: 2014-09-19 20:29:50

So much +1 on this, I just revisited Synergy after getting a dual computer setup at home and got a Premium account. Happy to pay more if it gives you some time for this.

@nbolton
Copy link
Member Author

nbolton commented Oct 13, 2014

  • Author: Nick Buraglio
  • Date: 2014-09-25 15:25:51

+1 Same here. I keep going back to Teleport but I have a system that gets left out in that case. I'd consider adding to the bounty for the apple server meta key bits.

@joanmarie
Copy link

+1. I just used one of my Premium votes for this (as "#3305"). But the resulting vote link brings up this search. Please associate my Premium vote with this and not the multitouch support. :)

@ManjotS
Copy link

ManjotS commented Feb 16, 2015

Please fix this

@3nki
Copy link

3nki commented Feb 18, 2015

+1

@nbolton nbolton added enhancement and removed bug labels Mar 6, 2015
@nbolton nbolton changed the title Patch for Volume Up, Down and Mute on OSX Clients Volume up, down and mute keys on OSX clients Mar 6, 2015
@nbolton
Copy link
Member Author

nbolton commented Mar 6, 2015

@XinyuHou @speaker - could one of you turn this into a PR please?

@andrewbolster
Copy link

Sorry to butt in but is it not more sustainable to add a "passthrough" option in the hotkey setup instead of hard-coding a key table?

In my case (#4365) my "media keys" aren't standard but are just ergonomically convenient for my keyboard.

This would need a bit more engineering to have the hotkey dialog not actually bind to key combinations until after configuration, but would at least be setup in the config file.

Also this solution breaks the use case where the media is playing on the client not the server, which could surprise some people.

@jpoet
Copy link

jpoet commented Sep 15, 2015

I just started using Synergy, and Synergy handling the media keys would make it much more useful to me.

andrewbolster, I see that #4365 was closed, but I can't tell why. Do you know if this has been fixed some other way?

@jpoet
Copy link

jpoet commented Sep 15, 2015

Douglas Mayle, you mention that your fix requires a combination of the patch plus another application. I see the patch, but I don't see where to get the application. Is there some place I can get it?

@kyrsjo
Copy link

kyrsjo commented Sep 29, 2015

This enhancement would be great, especially if I could set the media keys (the volume & mute!) to always be sent to a specific machine, i.e. the machine which has the speakers.

The track skip buttons are perfect for changing which computer I'm working on, so please make it possible to specify which buttons should be forwarded...

Setup: Linux server/mac client (this works flawlessly, the other way not so well).

@davecotter
Copy link

also add cmd-option-escape :)

nbolton pushed a commit that referenced this issue May 3, 2019
nbolton pushed a commit that referenced this issue May 3, 2019
nbolton pushed a commit that referenced this issue May 3, 2019
nbolton pushed a commit that referenced this issue May 3, 2019
nbolton pushed a commit that referenced this issue May 3, 2019
nbolton pushed a commit that referenced this issue May 3, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests