2004-04-11 14:58:08 +00:00
|
|
|
/*
|
|
|
|
* synergy -- mouse and keyboard sharing utility
|
|
|
|
* Copyright (C) 2004 Chris Schoeneman
|
|
|
|
*
|
|
|
|
* 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 COPYING 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "COSXScreen.h"
|
|
|
|
#include "COSXClipboard.h"
|
|
|
|
#include "COSXEventQueueBuffer.h"
|
|
|
|
#include "COSXKeyState.h"
|
|
|
|
#include "COSXScreenSaver.h"
|
|
|
|
#include "CClipboard.h"
|
|
|
|
#include "CLog.h"
|
|
|
|
#include "IEventQueue.h"
|
|
|
|
#include "TMethodEventJob.h"
|
|
|
|
|
|
|
|
//
|
|
|
|
// COSXScreen
|
|
|
|
//
|
|
|
|
|
|
|
|
COSXScreen::COSXScreen(bool isPrimary) :
|
|
|
|
m_isPrimary(isPrimary),
|
|
|
|
m_isOnScreen(m_isPrimary),
|
2004-05-02 16:13:11 +00:00
|
|
|
m_cursorPosValid(false),
|
2004-04-11 14:58:08 +00:00
|
|
|
m_cursorHidden(false),
|
|
|
|
m_keyState(NULL),
|
|
|
|
m_sequenceNumber(0),
|
|
|
|
m_screensaver(NULL),
|
|
|
|
m_screensaverNotify(false)
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
m_displayID = CGMainDisplayID();
|
|
|
|
updateScreenShape();
|
|
|
|
m_screensaver = new COSXScreenSaver();
|
|
|
|
m_keyState = new COSXKeyState();
|
|
|
|
LOG((CLOG_DEBUG "screen shape: %d,%d %dx%d", m_x, m_y, m_w, m_h));
|
|
|
|
}
|
|
|
|
catch (...) {
|
|
|
|
delete m_keyState;
|
|
|
|
delete m_screensaver;
|
|
|
|
throw;
|
|
|
|
}
|
|
|
|
|
|
|
|
// install event handlers
|
|
|
|
EVENTQUEUE->adoptHandler(CEvent::kSystem, IEventQueue::getSystemTarget(),
|
|
|
|
new TMethodEventJob<COSXScreen>(this,
|
|
|
|
&COSXScreen::handleSystemEvent));
|
|
|
|
|
|
|
|
// install the platform event queue
|
|
|
|
EVENTQUEUE->adoptBuffer(new COSXEventQueueBuffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
COSXScreen::~COSXScreen()
|
|
|
|
{
|
|
|
|
disable();
|
|
|
|
EVENTQUEUE->adoptBuffer(NULL);
|
|
|
|
EVENTQUEUE->removeHandler(CEvent::kSystem, IEventQueue::getSystemTarget());
|
|
|
|
delete m_keyState;
|
|
|
|
delete m_screensaver;
|
|
|
|
}
|
|
|
|
|
|
|
|
void*
|
|
|
|
COSXScreen::getEventTarget() const
|
|
|
|
{
|
|
|
|
return const_cast<COSXScreen*>(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
COSXScreen::getClipboard(ClipboardID, IClipboard* dst) const
|
|
|
|
{
|
|
|
|
COSXClipboard src;
|
|
|
|
CClipboard::copy(dst, &src);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
COSXScreen::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
|
|
|
|
{
|
|
|
|
x = m_x;
|
|
|
|
y = m_y;
|
|
|
|
w = m_w;
|
|
|
|
h = m_h;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
COSXScreen::getCursorPos(SInt32& x, SInt32& y) const
|
|
|
|
{
|
|
|
|
Point mouse;
|
|
|
|
GetGlobalMouse(&mouse);
|
2004-05-02 16:13:11 +00:00
|
|
|
x = mouse.h;
|
|
|
|
y = mouse.v;
|
|
|
|
m_cursorPosValid = true;
|
|
|
|
m_xCursor = x;
|
|
|
|
m_yCursor = y;
|
2004-04-11 14:58:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
COSXScreen::reconfigure(UInt32 activeSides)
|
|
|
|
{
|
|
|
|
// FIXME
|
|
|
|
(void)activeSides;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
COSXScreen::warpCursor(SInt32 x, SInt32 y)
|
|
|
|
{
|
|
|
|
// move cursor without generating events
|
|
|
|
CGPoint pos;
|
|
|
|
pos.x = x;
|
|
|
|
pos.y = y;
|
|
|
|
CGWarpMouseCursorPosition(pos);
|
|
|
|
|
|
|
|
// save new cursor position
|
2004-05-02 16:13:11 +00:00
|
|
|
m_xCursor = x;
|
|
|
|
m_yCursor = y;
|
|
|
|
m_cursorPosValid = true;
|
2004-04-11 14:58:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SInt32
|
|
|
|
COSXScreen::getJumpZoneSize() const
|
|
|
|
{
|
|
|
|
// FIXME -- is this correct?
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
COSXScreen::isAnyMouseButtonDown() const
|
|
|
|
{
|
|
|
|
// FIXME
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
COSXScreen::getCursorCenter(SInt32& x, SInt32& y) const
|
|
|
|
{
|
|
|
|
x = m_xCenter;
|
|
|
|
y = m_yCenter;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
COSXScreen::fakeMouseButton(ButtonID id, bool press) const
|
|
|
|
{
|
|
|
|
// get button index
|
|
|
|
UInt32 index = id - kButtonLeft;
|
|
|
|
if (index >= sizeof(m_buttons) / sizeof(m_buttons[0])) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// update state
|
|
|
|
m_buttons[index] = press;
|
|
|
|
|
|
|
|
// synthesize event. CGPostMouseEvent is a particularly good
|
|
|
|
// example of a bad API. we have to shadow the mouse state to
|
|
|
|
// use this API and if we want to support more buttons we have
|
|
|
|
// to recompile.
|
|
|
|
CGPoint pos;
|
2004-05-02 16:13:11 +00:00
|
|
|
if (!m_cursorPosValid) {
|
|
|
|
SInt32 x, y;
|
|
|
|
getCursorPos(x, y);
|
|
|
|
}
|
2004-04-11 14:58:08 +00:00
|
|
|
pos.x = m_xCursor;
|
|
|
|
pos.y = m_yCursor;
|
|
|
|
CGPostMouseEvent(pos, false, sizeof(m_buttons) / sizeof(m_buttons[0]),
|
|
|
|
m_buttons[0],
|
|
|
|
m_buttons[1],
|
|
|
|
m_buttons[2],
|
|
|
|
m_buttons[3],
|
|
|
|
m_buttons[4]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
COSXScreen::fakeMouseMove(SInt32 x, SInt32 y) const
|
|
|
|
{
|
|
|
|
// synthesize event
|
|
|
|
CGPoint pos;
|
|
|
|
pos.x = x;
|
|
|
|
pos.y = y;
|
|
|
|
// FIXME -- is it okay to pass no buttons here?
|
|
|
|
CGPostMouseEvent(pos, true, 0, m_buttons[0]);
|
|
|
|
|
|
|
|
// save new cursor position
|
2004-05-02 16:13:11 +00:00
|
|
|
m_xCursor = x;
|
|
|
|
m_yCursor = y;
|
|
|
|
m_cursorPosValid = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
COSXScreen::fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const
|
|
|
|
{
|
|
|
|
// OS X does not appear to have a fake relative mouse move function.
|
|
|
|
// simulate it by getting the current mouse position and adding to
|
|
|
|
// that. this can yield the wrong answer but there's not much else
|
|
|
|
// we can do.
|
|
|
|
|
|
|
|
// get current position
|
|
|
|
Point oldPos;
|
|
|
|
GetGlobalMouse(&oldPos);
|
|
|
|
|
|
|
|
// synthesize event
|
|
|
|
CGPoint pos;
|
|
|
|
pos.x = oldPos.h + dx;
|
|
|
|
pos.y = oldPos.v + dy;
|
|
|
|
// FIXME -- is it okay to pass no buttons here?
|
|
|
|
CGPostMouseEvent(pos, true, 0, m_buttons[0]);
|
|
|
|
|
|
|
|
// we now assume we don't know the current cursor position
|
|
|
|
m_cursorPosValid = false;
|
2004-04-11 14:58:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
COSXScreen::fakeMouseWheel(SInt32 delta) const
|
|
|
|
{
|
|
|
|
CGPostScrollWheelEvent(1, delta / 120);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
COSXScreen::enable()
|
|
|
|
{
|
|
|
|
// FIXME -- install clipboard snooper (if we need one)
|
|
|
|
|
|
|
|
if (m_isPrimary) {
|
|
|
|
// FIXME -- start watching jump zones
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// FIXME -- prevent system from entering power save mode
|
|
|
|
|
|
|
|
// hide cursor
|
|
|
|
if (!m_cursorHidden) {
|
|
|
|
CGDisplayHideCursor(m_displayID);
|
|
|
|
m_cursorHidden = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// warp the mouse to the cursor center
|
|
|
|
fakeMouseMove(m_xCenter, m_yCenter);
|
|
|
|
|
|
|
|
// FIXME -- prepare to show cursor if it moves
|
|
|
|
}
|
|
|
|
|
|
|
|
updateKeys();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
COSXScreen::disable()
|
|
|
|
{
|
|
|
|
if (m_isPrimary) {
|
|
|
|
// FIXME -- stop watching jump zones, stop capturing input
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// show cursor
|
|
|
|
if (m_cursorHidden) {
|
|
|
|
CGDisplayShowCursor(m_displayID);
|
|
|
|
m_cursorHidden = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME -- allow system to enter power saving mode
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME -- uninstall clipboard snooper (if we needed one)
|
|
|
|
|
|
|
|
m_isOnScreen = m_isPrimary;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
COSXScreen::enter()
|
|
|
|
{
|
|
|
|
if (m_isPrimary) {
|
|
|
|
// FIXME -- stop capturing input, watch jump zones
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// show cursor
|
|
|
|
if (m_cursorHidden) {
|
|
|
|
CGDisplayShowCursor(m_displayID);
|
|
|
|
m_cursorHidden = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// reset buttons
|
|
|
|
for (UInt32 i = 0; i < sizeof(m_buttons) / sizeof(m_buttons[0]); ++i) {
|
|
|
|
m_buttons[i] = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// now on screen
|
|
|
|
m_isOnScreen = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
COSXScreen::leave()
|
|
|
|
{
|
|
|
|
// FIXME -- choose keyboard layout if per-process and activate it here
|
|
|
|
|
|
|
|
if (m_isPrimary) {
|
|
|
|
// update key and button state
|
|
|
|
updateKeys();
|
|
|
|
|
|
|
|
// warp to center
|
|
|
|
warpCursor(m_xCenter, m_yCenter);
|
|
|
|
|
|
|
|
// capture events
|
|
|
|
// FIXME
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// hide cursor
|
|
|
|
if (!m_cursorHidden) {
|
|
|
|
CGDisplayHideCursor(m_displayID);
|
|
|
|
m_cursorHidden = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// warp the mouse to the cursor center
|
|
|
|
fakeMouseMove(m_xCenter, m_yCenter);
|
|
|
|
|
|
|
|
// FIXME -- prepare to show cursor if it moves
|
|
|
|
|
|
|
|
// take keyboard focus
|
|
|
|
// FIXME
|
|
|
|
}
|
|
|
|
|
|
|
|
// now off screen
|
|
|
|
m_isOnScreen = false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
COSXScreen::setClipboard(ClipboardID, const IClipboard* src)
|
|
|
|
{
|
|
|
|
COSXClipboard dst;
|
|
|
|
if (src != NULL) {
|
|
|
|
// save clipboard data
|
|
|
|
return CClipboard::copy(&dst, src);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// assert clipboard ownership
|
|
|
|
if (!dst.open(0)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
dst.empty();
|
|
|
|
dst.close();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
COSXScreen::checkClipboards()
|
|
|
|
{
|
|
|
|
// FIXME -- do nothing if we're always up to date
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
COSXScreen::openScreensaver(bool notify)
|
|
|
|
{
|
|
|
|
m_screensaverNotify = notify;
|
|
|
|
if (!m_screensaverNotify) {
|
|
|
|
m_screensaver->disable();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
COSXScreen::closeScreensaver()
|
|
|
|
{
|
|
|
|
if (!m_screensaverNotify) {
|
|
|
|
m_screensaver->enable();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
COSXScreen::screensaver(bool activate)
|
|
|
|
{
|
|
|
|
if (activate) {
|
|
|
|
m_screensaver->activate();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
m_screensaver->deactivate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
COSXScreen::resetOptions()
|
|
|
|
{
|
|
|
|
// no options
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
COSXScreen::setOptions(const COptionsList&)
|
|
|
|
{
|
|
|
|
// no options
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
COSXScreen::setSequenceNumber(UInt32 seqNum)
|
|
|
|
{
|
|
|
|
m_sequenceNumber = seqNum;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
COSXScreen::isPrimary() const
|
|
|
|
{
|
|
|
|
return m_isPrimary;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
COSXScreen::handleSystemEvent(const CEvent&, void*)
|
|
|
|
{
|
|
|
|
// FIXME
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
COSXScreen::updateButtons()
|
|
|
|
{
|
|
|
|
// FIXME -- get current button state into m_buttons[]
|
|
|
|
}
|
|
|
|
|
|
|
|
IKeyState*
|
|
|
|
COSXScreen::getKeyState() const
|
|
|
|
{
|
|
|
|
return m_keyState;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
COSXScreen::updateScreenShape()
|
|
|
|
{
|
|
|
|
// FIXME -- handle multiple monitors
|
|
|
|
|
|
|
|
// get shape of default screen
|
|
|
|
m_x = 0;
|
|
|
|
m_y = 0;
|
|
|
|
m_w = CGDisplayPixelsWide(m_displayID);
|
|
|
|
m_h = CGDisplayPixelsHigh(m_displayID);
|
|
|
|
|
|
|
|
// get center of default screen
|
|
|
|
m_xCenter = m_x + (m_w >> 1);
|
|
|
|
m_yCenter = m_y + (m_h >> 1);
|
|
|
|
}
|