Use IOHID to fake mouse buttons
This commit is contained in:
parent
271ac9e057
commit
f83da9ae34
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2012-2016 Symless Ltd.
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file LICENSE that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Carbon/Carbon.h>
|
||||
|
||||
//! IOHID event on Mac
|
||||
class OSXIOHID {
|
||||
public:
|
||||
void postModifierKeys(UInt32 mask);
|
||||
void postKey(const UInt8 virtualKeyCode,
|
||||
const bool down);
|
||||
void fakeMouseButton(UInt32 button, bool press);
|
||||
|
||||
private:
|
||||
void postMouseEvent(io_connect_t event, UInt32 type,
|
||||
NXEventData* ev, IOOptionBits flags,
|
||||
IOOptionBits options);
|
||||
};
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2012-2016 Symless Ltd.
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file LICENSE that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "platform/OSXIOHID.h"
|
||||
|
||||
#include "base/Log.h"
|
||||
|
||||
#include <IOKit/hidsystem/event_status_driver.h>
|
||||
#include <AppKit/NSEvent.h>
|
||||
#include <IOKit/hidsystem/IOHIDLib.h>
|
||||
|
||||
static io_connect_t getEventDriver(void)
|
||||
{
|
||||
static mach_port_t sEventDrvrRef = 0;
|
||||
mach_port_t masterPort, service, iter;
|
||||
kern_return_t kr;
|
||||
|
||||
if (!sEventDrvrRef) {
|
||||
// Get master device port
|
||||
kr = IOMasterPort(bootstrap_port, &masterPort);
|
||||
assert(KERN_SUCCESS == kr);
|
||||
|
||||
kr = IOServiceGetMatchingServices(masterPort,
|
||||
IOServiceMatching(kIOHIDSystemClass), &iter);
|
||||
assert(KERN_SUCCESS == kr);
|
||||
|
||||
service = IOIteratorNext(iter);
|
||||
assert(service);
|
||||
|
||||
kr = IOServiceOpen(service, mach_task_self(),
|
||||
kIOHIDParamConnectType, &sEventDrvrRef);
|
||||
assert(KERN_SUCCESS == kr);
|
||||
|
||||
IOObjectRelease(service);
|
||||
IOObjectRelease(iter);
|
||||
}
|
||||
|
||||
return sEventDrvrRef;
|
||||
}
|
||||
|
||||
void
|
||||
OSXIOHID::postModifierKeys(UInt32 mask)
|
||||
{
|
||||
NXEventData event;
|
||||
bzero(&event, sizeof(NXEventData));
|
||||
IOGPoint loc = { 0, 0 };
|
||||
kern_return_t kr;
|
||||
kr = IOHIDPostEvent(getEventDriver(), NX_FLAGSCHANGED, loc,
|
||||
&event, kNXEventDataVersion, mask, true);
|
||||
assert(KERN_SUCCESS == kr);
|
||||
}
|
||||
|
||||
void
|
||||
OSXIOHID::postKey(const UInt8 virtualKeyCode,
|
||||
const bool down)
|
||||
{
|
||||
NXEventData event;
|
||||
bzero(&event, sizeof(NXEventData));
|
||||
IOGPoint loc = { 0, 0 };
|
||||
event.key.repeat = false;
|
||||
event.key.keyCode = virtualKeyCode;
|
||||
event.key.origCharSet = event.key.charSet = NX_ASCIISET;
|
||||
event.key.origCharCode = event.key.charCode = 0;
|
||||
kern_return_t kr;
|
||||
kr = IOHIDPostEvent(getEventDriver(),
|
||||
down ? NX_KEYDOWN : NX_KEYUP,
|
||||
loc, &event, kNXEventDataVersion, 0, false);
|
||||
assert(KERN_SUCCESS == kr);
|
||||
}
|
||||
|
||||
void
|
||||
OSXIOHID::fakeMouseButton(UInt32 button, bool press)
|
||||
{
|
||||
NXEventData event;
|
||||
memset (&event, 0, sizeof(event));
|
||||
|
||||
// Mouse presses actually generate two events, one with a bitfield of buttons, one with a button number
|
||||
event.compound.subType = NX_SUBTYPE_AUX_MOUSE_BUTTONS;
|
||||
event.compound.misc.L[0] = (1 << button);
|
||||
event.compound.misc.L[1] = press ? (1 << button) : 0;
|
||||
postMouseEvent(getEventDriver(), NX_SYSDEFINED, &event, 0, 0);
|
||||
|
||||
memset(&event, 0, sizeof(event));
|
||||
event.mouse.buttonNumber = button;
|
||||
UInt32 type;
|
||||
|
||||
switch (button){
|
||||
case 0:
|
||||
type = press ? NX_LMOUSEDOWN : NX_LMOUSEUP;
|
||||
break;
|
||||
case 1:
|
||||
type = press ? NX_RMOUSEDOWN : NX_RMOUSEUP;
|
||||
break;
|
||||
default:
|
||||
type = press ? NX_OMOUSEDOWN : NX_OMOUSEUP;
|
||||
}
|
||||
|
||||
if (press) {
|
||||
event.mouse.pressure = 255;
|
||||
}
|
||||
|
||||
postMouseEvent(getEventDriver(), type, &event, 0, 0);
|
||||
}
|
||||
|
||||
void
|
||||
OSXIOHID::postMouseEvent(
|
||||
io_connect_t event, UInt32 type,
|
||||
NXEventData* ev, IOOptionBits flags,
|
||||
IOOptionBits options)
|
||||
{
|
||||
|
||||
IOGPoint location = {0, 0};
|
||||
if ((options & kIOHIDSetRelativeCursorPosition) && type != NX_MOUSEMOVED){
|
||||
// Mouse button only accepts absolute coordinates
|
||||
CGEventRef cge = CGEventCreate(nil);
|
||||
CGPoint loc = CGEventGetLocation(cge);
|
||||
CFRelease(cge);
|
||||
location.x = floor(loc.x + ev->mouseMove.dx);
|
||||
location.y = floor(loc.y + ev->mouseMove.dy);
|
||||
options = (options & ~kIOHIDSetRelativeCursorPosition) | kIOHIDSetCursorPosition;
|
||||
}
|
||||
|
||||
kern_return_t res = IOHIDPostEvent(event, type, location, ev, kNXEventDataVersion, flags | NX_NONCOALSESCEDMASK, options);
|
||||
if (res != kIOReturnSuccess) {
|
||||
LOG((CLOG_DEBUG1 "IOHIDPostEvent event failed: %x\n", res));
|
||||
}
|
||||
}
|
|
@ -16,6 +16,7 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "platform/OSXIOHID.h"
|
||||
#include "platform/OSXKeyState.h"
|
||||
#include "platform/OSXUchrKeyResource.h"
|
||||
#include "platform/OSXMediaKeySupport.h"
|
||||
|
@ -470,46 +471,13 @@ OSXKeyState::getKeyMap(synergy::KeyMap& keyMap)
|
|||
}
|
||||
}
|
||||
|
||||
static io_connect_t getEventDriver(void)
|
||||
{
|
||||
static mach_port_t sEventDrvrRef = 0;
|
||||
mach_port_t masterPort, service, iter;
|
||||
kern_return_t kr;
|
||||
|
||||
if (!sEventDrvrRef) {
|
||||
// Get master device port
|
||||
kr = IOMasterPort(bootstrap_port, &masterPort);
|
||||
assert(KERN_SUCCESS == kr);
|
||||
|
||||
kr = IOServiceGetMatchingServices(masterPort,
|
||||
IOServiceMatching(kIOHIDSystemClass), &iter);
|
||||
assert(KERN_SUCCESS == kr);
|
||||
|
||||
service = IOIteratorNext(iter);
|
||||
assert(service);
|
||||
|
||||
kr = IOServiceOpen(service, mach_task_self(),
|
||||
kIOHIDParamConnectType, &sEventDrvrRef);
|
||||
assert(KERN_SUCCESS == kr);
|
||||
|
||||
IOObjectRelease(service);
|
||||
IOObjectRelease(iter);
|
||||
}
|
||||
|
||||
return sEventDrvrRef;
|
||||
}
|
||||
|
||||
void
|
||||
OSXKeyState::postHIDVirtualKey(const UInt8 virtualKeyCode,
|
||||
const bool postDown)
|
||||
{
|
||||
static UInt32 modifiers = 0;
|
||||
|
||||
NXEventData event;
|
||||
IOGPoint loc = { 0, 0 };
|
||||
UInt32 modifiersDelta = 0;
|
||||
|
||||
bzero(&event, sizeof(NXEventData));
|
||||
OSXIOHID hid;
|
||||
|
||||
switch (virtualKeyCode)
|
||||
{
|
||||
|
@ -550,21 +518,11 @@ OSXKeyState::postHIDVirtualKey(const UInt8 virtualKeyCode,
|
|||
modifiers &= ~modifiersDelta;
|
||||
}
|
||||
|
||||
kern_return_t kr;
|
||||
kr = IOHIDPostEvent(getEventDriver(), NX_FLAGSCHANGED, loc,
|
||||
&event, kNXEventDataVersion, modifiers, true);
|
||||
assert(KERN_SUCCESS == kr);
|
||||
hid.postModifierKeys(modifiers);
|
||||
break;
|
||||
|
||||
default:
|
||||
event.key.repeat = false;
|
||||
event.key.keyCode = virtualKeyCode;
|
||||
event.key.origCharSet = event.key.charSet = NX_ASCIISET;
|
||||
event.key.origCharCode = event.key.charCode = 0;
|
||||
kr = IOHIDPostEvent(getEventDriver(),
|
||||
postDown ? NX_KEYDOWN : NX_KEYUP,
|
||||
loc, &event, kNXEventDataVersion, 0, false);
|
||||
assert(KERN_SUCCESS == kr);
|
||||
hid.postKey(virtualKeyCode, postDown);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
|
||||
#include "platform/OSXScreen.h"
|
||||
|
||||
#include "base/EventQueue.h"
|
||||
#include "client/Client.h"
|
||||
#include "platform/OSXIOHID.h"
|
||||
#include "platform/OSXClipboard.h"
|
||||
#include "platform/OSXEventQueueBuffer.h"
|
||||
#include "platform/OSXKeyState.h"
|
||||
|
@ -35,16 +35,18 @@
|
|||
#include "mt/Mutex.h"
|
||||
#include "mt/Thread.h"
|
||||
#include "arch/XArch.h"
|
||||
#include "base/Log.h"
|
||||
#include "base/EventQueue.h"
|
||||
#include "base/IEventQueue.h"
|
||||
#include "base/TMethodEventJob.h"
|
||||
#include "base/TMethodJob.h"
|
||||
#include "base/Log.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#include <AvailabilityMacros.h>
|
||||
#include <IOKit/hidsystem/event_status_driver.h>
|
||||
#include <AppKit/NSEvent.h>
|
||||
#include <IOKit/hidsystem/IOHIDLib.h>
|
||||
|
||||
// This isn't in any Apple SDK that I know of as of yet.
|
||||
enum {
|
||||
|
@ -515,65 +517,13 @@ OSXScreen::fakeMouseButton(ButtonID id, bool press)
|
|||
return;
|
||||
}
|
||||
|
||||
CGPoint pos;
|
||||
if (!m_cursorPosValid) {
|
||||
SInt32 x, y;
|
||||
getCursorPos(x, y);
|
||||
}
|
||||
pos.x = m_xCursor;
|
||||
pos.y = m_yCursor;
|
||||
|
||||
// variable used to detect mouse coordinate differences between
|
||||
// old & new mouse clicks. Used in double click detection.
|
||||
SInt32 xDiff = m_xCursor - m_lastSingleClickXCursor;
|
||||
SInt32 yDiff = m_yCursor - m_lastSingleClickYCursor;
|
||||
double diff = sqrt(xDiff * xDiff + yDiff * yDiff);
|
||||
// max sqrt(x^2 + y^2) difference allowed to double click
|
||||
// since we don't have double click distance in NX APIs
|
||||
// we define our own defaults.
|
||||
const double maxDiff = sqrt(2) + 0.0001;
|
||||
|
||||
double clickTime = [NSEvent doubleClickInterval];
|
||||
|
||||
// As long as the click is within the time window and distance window
|
||||
// increase clickState (double click, triple click, etc)
|
||||
// This will allow for higher than triple click but the quartz documenation
|
||||
// does not specify that this should be limited to triple click
|
||||
if (press) {
|
||||
if ((ARCH->time() - m_lastClickTime) <= clickTime && diff <= maxDiff){
|
||||
m_clickState++;
|
||||
}
|
||||
else {
|
||||
m_clickState = 1;
|
||||
}
|
||||
|
||||
m_lastClickTime = ARCH->time();
|
||||
}
|
||||
|
||||
if (m_clickState == 1){
|
||||
m_lastSingleClickXCursor = m_xCursor;
|
||||
m_lastSingleClickYCursor = m_yCursor;
|
||||
}
|
||||
|
||||
EMouseButtonState state = press ? kMouseButtonDown : kMouseButtonUp;
|
||||
|
||||
LOG((CLOG_DEBUG1 "faking mouse button id: %d press: %s", index, press ? "pressed" : "released"));
|
||||
|
||||
MouseButtonEventMapType thisButtonMap = MouseButtonEventMap[index];
|
||||
CGEventType type = thisButtonMap[state];
|
||||
|
||||
CGEventRef event = CGEventCreateMouseEvent(NULL, type, pos, static_cast<CGMouseButton>(index));
|
||||
|
||||
CGEventSetIntegerValueField(event, kCGMouseEventClickState, m_clickState);
|
||||
|
||||
// Fix for sticky keys
|
||||
CGEventFlags modifiers = m_keyState->getModifierStateAsOSXFlags();
|
||||
CGEventSetFlags(event, modifiers);
|
||||
OSXIOHID hid;
|
||||
hid.fakeMouseButton(index, press);
|
||||
|
||||
EMouseButtonState state = press ? kMouseButtonDown : kMouseButtonUp;
|
||||
m_buttonState.set(index, state);
|
||||
CGEventPost(kCGHIDEventTap, event);
|
||||
|
||||
CFRelease(event);
|
||||
|
||||
if (!press && (id == kButtonLeft)) {
|
||||
if (m_fakeDraggingStarted) {
|
||||
|
@ -1894,21 +1844,22 @@ OSXScreen::handleCGInputEventSecondary(
|
|||
CGEventRef event,
|
||||
void* refcon)
|
||||
{
|
||||
// this fix is really screwing with the correct show/hide behavior. it
|
||||
// should be tested better before reintroducing.
|
||||
return event;
|
||||
CGEventMask mask = kCGEventFlagMaskCommand;
|
||||
mask = CGEventGetFlags(event);
|
||||
LOG ((CLOG_INFO "%x", mask));
|
||||
auto i = CGEventGetIntegerValueField(event, kCGEventSourceUnixProcessID);
|
||||
LOG ((CLOG_INFO "Target PID:%lld", i));
|
||||
|
||||
OSXScreen* screen = (OSXScreen*)refcon;
|
||||
if (screen->m_cursorHidden && type == kCGEventMouseMoved) {
|
||||
switch(type) {
|
||||
case kCGEventLeftMouseDown:
|
||||
case kCGEventRightMouseDown:
|
||||
case kCGEventOtherMouseDown:
|
||||
case kCGEventScrollWheel:
|
||||
case kCGEventKeyDown:
|
||||
case kCGEventFlagsChanged:
|
||||
;//LOG((CLOG_INFO "local input detected"));
|
||||
}
|
||||
|
||||
CGPoint pos = CGEventGetLocation(event);
|
||||
if (pos.x != screen->m_xCenter || pos.y != screen->m_yCenter) {
|
||||
|
||||
LOG((CLOG_DEBUG "show cursor on secondary, type=%d pos=%d,%d",
|
||||
type, pos.x, pos.y));
|
||||
screen->showCursor();
|
||||
}
|
||||
}
|
||||
return event;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue