mirror of
https://github.com/debauchee/barrier.git
synced 2026-05-11 00:58:14 +08:00
Initial commit of the synergy trunk sources from sf.net
This commit is contained in:
209
lib/platform/CMSWindowsClipboard.cpp
Normal file
209
lib/platform/CMSWindowsClipboard.cpp
Normal file
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 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 "CMSWindowsClipboard.h"
|
||||
#include "CMSWindowsClipboardTextConverter.h"
|
||||
#include "CMSWindowsClipboardUTF16Converter.h"
|
||||
#include "CMSWindowsClipboardBitmapConverter.h"
|
||||
#include "CMSWindowsClipboardHTMLConverter.h"
|
||||
#include "CLog.h"
|
||||
#include "CArchMiscWindows.h"
|
||||
|
||||
//
|
||||
// CMSWindowsClipboard
|
||||
//
|
||||
|
||||
UINT CMSWindowsClipboard::s_ownershipFormat = 0;
|
||||
|
||||
CMSWindowsClipboard::CMSWindowsClipboard(HWND window) :
|
||||
m_window(window),
|
||||
m_time(0)
|
||||
{
|
||||
// add converters, most desired first
|
||||
m_converters.push_back(new CMSWindowsClipboardUTF16Converter);
|
||||
if (CArchMiscWindows::isWindows95Family()) {
|
||||
// windows nt family converts to/from unicode automatically.
|
||||
// let it do so to avoid text encoding issues.
|
||||
m_converters.push_back(new CMSWindowsClipboardTextConverter);
|
||||
}
|
||||
m_converters.push_back(new CMSWindowsClipboardBitmapConverter);
|
||||
m_converters.push_back(new CMSWindowsClipboardHTMLConverter);
|
||||
}
|
||||
|
||||
CMSWindowsClipboard::~CMSWindowsClipboard()
|
||||
{
|
||||
clearConverters();
|
||||
}
|
||||
|
||||
bool
|
||||
CMSWindowsClipboard::emptyUnowned()
|
||||
{
|
||||
LOG((CLOG_DEBUG "empty clipboard"));
|
||||
|
||||
// empty the clipboard (and take ownership)
|
||||
if (!EmptyClipboard()) {
|
||||
LOG((CLOG_DEBUG "failed to grab clipboard"));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CMSWindowsClipboard::empty()
|
||||
{
|
||||
if (!emptyUnowned()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// mark clipboard as being owned by synergy
|
||||
HGLOBAL data = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, 1);
|
||||
SetClipboardData(getOwnershipFormat(), data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsClipboard::add(EFormat format, const CString& data)
|
||||
{
|
||||
LOG((CLOG_DEBUG "add %d bytes to clipboard format: %d", data.size(), format));
|
||||
|
||||
// convert data to win32 form
|
||||
for (ConverterList::const_iterator index = m_converters.begin();
|
||||
index != m_converters.end(); ++index) {
|
||||
IMSWindowsClipboardConverter* converter = *index;
|
||||
|
||||
// skip converters for other formats
|
||||
if (converter->getFormat() == format) {
|
||||
HANDLE win32Data = converter->fromIClipboard(data);
|
||||
if (win32Data != NULL) {
|
||||
UINT win32Format = converter->getWin32Format();
|
||||
if (SetClipboardData(win32Format, win32Data) == NULL) {
|
||||
// free converted data if we couldn't put it on
|
||||
// the clipboard
|
||||
GlobalFree(win32Data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CMSWindowsClipboard::open(Time time) const
|
||||
{
|
||||
LOG((CLOG_DEBUG "open clipboard"));
|
||||
|
||||
if (!OpenClipboard(m_window)) {
|
||||
LOG((CLOG_WARN "failed to open clipboard"));
|
||||
return false;
|
||||
}
|
||||
|
||||
m_time = time;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsClipboard::close() const
|
||||
{
|
||||
LOG((CLOG_DEBUG "close clipboard"));
|
||||
CloseClipboard();
|
||||
}
|
||||
|
||||
IClipboard::Time
|
||||
CMSWindowsClipboard::getTime() const
|
||||
{
|
||||
return m_time;
|
||||
}
|
||||
|
||||
bool
|
||||
CMSWindowsClipboard::has(EFormat format) const
|
||||
{
|
||||
for (ConverterList::const_iterator index = m_converters.begin();
|
||||
index != m_converters.end(); ++index) {
|
||||
IMSWindowsClipboardConverter* converter = *index;
|
||||
if (converter->getFormat() == format) {
|
||||
if (IsClipboardFormatAvailable(converter->getWin32Format())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
CString
|
||||
CMSWindowsClipboard::get(EFormat format) const
|
||||
{
|
||||
// find the converter for the first clipboard format we can handle
|
||||
IMSWindowsClipboardConverter* converter = NULL;
|
||||
UINT win32Format = EnumClipboardFormats(0);
|
||||
while (converter == NULL && win32Format != 0) {
|
||||
for (ConverterList::const_iterator index = m_converters.begin();
|
||||
index != m_converters.end(); ++index) {
|
||||
converter = *index;
|
||||
if (converter->getWin32Format() == win32Format &&
|
||||
converter->getFormat() == format) {
|
||||
break;
|
||||
}
|
||||
converter = NULL;
|
||||
}
|
||||
win32Format = EnumClipboardFormats(win32Format);
|
||||
}
|
||||
|
||||
// if no converter then we don't recognize any formats
|
||||
if (converter == NULL) {
|
||||
return CString();
|
||||
}
|
||||
|
||||
// get a handle to the clipboard data
|
||||
HANDLE win32Data = GetClipboardData(converter->getWin32Format());
|
||||
if (win32Data == NULL) {
|
||||
return CString();
|
||||
}
|
||||
|
||||
// convert
|
||||
return converter->toIClipboard(win32Data);
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsClipboard::clearConverters()
|
||||
{
|
||||
for (ConverterList::iterator index = m_converters.begin();
|
||||
index != m_converters.end(); ++index) {
|
||||
delete *index;
|
||||
}
|
||||
m_converters.clear();
|
||||
}
|
||||
|
||||
bool
|
||||
CMSWindowsClipboard::isOwnedBySynergy()
|
||||
{
|
||||
// create ownership format if we haven't yet
|
||||
if (s_ownershipFormat == 0) {
|
||||
s_ownershipFormat = RegisterClipboardFormat(TEXT("SynergyOwnership"));
|
||||
}
|
||||
return (IsClipboardFormatAvailable(getOwnershipFormat()) != 0);
|
||||
}
|
||||
|
||||
UINT
|
||||
CMSWindowsClipboard::getOwnershipFormat()
|
||||
{
|
||||
// create ownership format if we haven't yet
|
||||
if (s_ownershipFormat == 0) {
|
||||
s_ownershipFormat = RegisterClipboardFormat(TEXT("SynergyOwnership"));
|
||||
}
|
||||
|
||||
// return the format
|
||||
return s_ownershipFormat;
|
||||
}
|
||||
104
lib/platform/CMSWindowsClipboard.h
Normal file
104
lib/platform/CMSWindowsClipboard.h
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 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.
|
||||
*/
|
||||
|
||||
#ifndef CMSWINDOWSCLIPBOARD_H
|
||||
#define CMSWINDOWSCLIPBOARD_H
|
||||
|
||||
#include "IClipboard.h"
|
||||
#include "stdvector.h"
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
class IMSWindowsClipboardConverter;
|
||||
|
||||
//! Microsoft windows clipboard implementation
|
||||
class CMSWindowsClipboard : public IClipboard {
|
||||
public:
|
||||
CMSWindowsClipboard(HWND window);
|
||||
virtual ~CMSWindowsClipboard();
|
||||
|
||||
//! Empty clipboard without ownership
|
||||
/*!
|
||||
Take ownership of the clipboard and clear all data from it.
|
||||
This must be called between a successful open() and close().
|
||||
Return false if the clipboard ownership could not be taken;
|
||||
the clipboard should not be emptied in this case. Unlike
|
||||
empty(), isOwnedBySynergy() will return false when emptied
|
||||
this way. This is useful when synergy wants to put data on
|
||||
clipboard but pretend (to itself) that some other app did it.
|
||||
When using empty(), synergy assumes the data came from the
|
||||
server and doesn't need to be sent back. emptyUnowned()
|
||||
makes synergy send the data to the server.
|
||||
*/
|
||||
bool emptyUnowned();
|
||||
|
||||
//! Test if clipboard is owned by synergy
|
||||
static bool isOwnedBySynergy();
|
||||
|
||||
// IClipboard overrides
|
||||
virtual bool empty();
|
||||
virtual void add(EFormat, const CString& data);
|
||||
virtual bool open(Time) const;
|
||||
virtual void close() const;
|
||||
virtual Time getTime() const;
|
||||
virtual bool has(EFormat) const;
|
||||
virtual CString get(EFormat) const;
|
||||
|
||||
private:
|
||||
void clearConverters();
|
||||
|
||||
UINT convertFormatToWin32(EFormat) const;
|
||||
HANDLE convertTextToWin32(const CString& data) const;
|
||||
CString convertTextFromWin32(HANDLE) const;
|
||||
|
||||
static UINT getOwnershipFormat();
|
||||
|
||||
private:
|
||||
typedef std::vector<IMSWindowsClipboardConverter*> ConverterList;
|
||||
|
||||
HWND m_window;
|
||||
mutable Time m_time;
|
||||
ConverterList m_converters;
|
||||
static UINT s_ownershipFormat;
|
||||
};
|
||||
|
||||
//! Clipboard format converter interface
|
||||
/*!
|
||||
This interface defines the methods common to all win32 clipboard format
|
||||
converters.
|
||||
*/
|
||||
class IMSWindowsClipboardConverter : public IInterface {
|
||||
public:
|
||||
// accessors
|
||||
|
||||
// return the clipboard format this object converts from/to
|
||||
virtual IClipboard::EFormat
|
||||
getFormat() const = 0;
|
||||
|
||||
// return the atom representing the win32 clipboard format that
|
||||
// this object converts from/to
|
||||
virtual UINT getWin32Format() const = 0;
|
||||
|
||||
// convert from the IClipboard format to the win32 clipboard format.
|
||||
// the input data must be in the IClipboard format returned by
|
||||
// getFormat(). the return data will be in the win32 clipboard
|
||||
// format returned by getWin32Format(), allocated by GlobalAlloc().
|
||||
virtual HANDLE fromIClipboard(const CString&) const = 0;
|
||||
|
||||
// convert from the win32 clipboard format to the IClipboard format
|
||||
// (i.e., the reverse of fromIClipboard()).
|
||||
virtual CString toIClipboard(HANDLE data) const = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
145
lib/platform/CMSWindowsClipboardAnyTextConverter.cpp
Normal file
145
lib/platform/CMSWindowsClipboardAnyTextConverter.cpp
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 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 "CMSWindowsClipboardAnyTextConverter.h"
|
||||
|
||||
//
|
||||
// CMSWindowsClipboardAnyTextConverter
|
||||
//
|
||||
|
||||
CMSWindowsClipboardAnyTextConverter::CMSWindowsClipboardAnyTextConverter()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
CMSWindowsClipboardAnyTextConverter::~CMSWindowsClipboardAnyTextConverter()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
IClipboard::EFormat
|
||||
CMSWindowsClipboardAnyTextConverter::getFormat() const
|
||||
{
|
||||
return IClipboard::kText;
|
||||
}
|
||||
|
||||
HANDLE
|
||||
CMSWindowsClipboardAnyTextConverter::fromIClipboard(const CString& data) const
|
||||
{
|
||||
// convert linefeeds and then convert to desired encoding
|
||||
CString text = doFromIClipboard(convertLinefeedToWin32(data));
|
||||
UInt32 size = text.size();
|
||||
|
||||
// copy to memory handle
|
||||
HGLOBAL gData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, size);
|
||||
if (gData != NULL) {
|
||||
// get a pointer to the allocated memory
|
||||
char* dst = (char*)GlobalLock(gData);
|
||||
if (dst != NULL) {
|
||||
memcpy(dst, text.data(), size);
|
||||
GlobalUnlock(gData);
|
||||
}
|
||||
else {
|
||||
GlobalFree(gData);
|
||||
gData = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return gData;
|
||||
}
|
||||
|
||||
CString
|
||||
CMSWindowsClipboardAnyTextConverter::toIClipboard(HANDLE data) const
|
||||
{
|
||||
// get datator
|
||||
const char* src = (const char*)GlobalLock(data);
|
||||
UInt32 srcSize = (UInt32)GlobalSize(data);
|
||||
if (src == NULL || srcSize <= 1) {
|
||||
return CString();
|
||||
}
|
||||
|
||||
// convert text
|
||||
CString text = doToIClipboard(CString(src, srcSize));
|
||||
|
||||
// release handle
|
||||
GlobalUnlock(data);
|
||||
|
||||
// convert newlines
|
||||
return convertLinefeedToUnix(text);
|
||||
}
|
||||
|
||||
CString
|
||||
CMSWindowsClipboardAnyTextConverter::convertLinefeedToWin32(
|
||||
const CString& src) const
|
||||
{
|
||||
// note -- we assume src is a valid UTF-8 string
|
||||
|
||||
// count newlines in string
|
||||
UInt32 numNewlines = 0;
|
||||
UInt32 n = src.size();
|
||||
for (const char* scan = src.c_str(); n > 0; ++scan, --n) {
|
||||
if (*scan == '\n') {
|
||||
++numNewlines;
|
||||
}
|
||||
}
|
||||
if (numNewlines == 0) {
|
||||
return src;
|
||||
}
|
||||
|
||||
// allocate new string
|
||||
CString dst;
|
||||
dst.reserve(src.size() + numNewlines);
|
||||
|
||||
// copy string, converting newlines
|
||||
n = src.size();
|
||||
for (const char* scan = src.c_str(); n > 0; ++scan, --n) {
|
||||
if (scan[0] == '\n') {
|
||||
dst += '\r';
|
||||
}
|
||||
dst += scan[0];
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
CString
|
||||
CMSWindowsClipboardAnyTextConverter::convertLinefeedToUnix(
|
||||
const CString& src) const
|
||||
{
|
||||
// count newlines in string
|
||||
UInt32 numNewlines = 0;
|
||||
UInt32 n = src.size();
|
||||
for (const char* scan = src.c_str(); n > 0; ++scan, --n) {
|
||||
if (scan[0] == '\r' && scan[1] == '\n') {
|
||||
++numNewlines;
|
||||
}
|
||||
}
|
||||
if (numNewlines == 0) {
|
||||
return src;
|
||||
}
|
||||
|
||||
// allocate new string
|
||||
CString dst;
|
||||
dst.reserve(src.size());
|
||||
|
||||
// copy string, converting newlines
|
||||
n = src.size();
|
||||
for (const char* scan = src.c_str(); n > 0; ++scan, --n) {
|
||||
if (scan[0] != '\r' || scan[1] != '\n') {
|
||||
dst += scan[0];
|
||||
}
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
56
lib/platform/CMSWindowsClipboardAnyTextConverter.h
Normal file
56
lib/platform/CMSWindowsClipboardAnyTextConverter.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 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.
|
||||
*/
|
||||
|
||||
#ifndef CMSWINDOWSCLIPBOARDANYTEXTCONVERTER_H
|
||||
#define CMSWINDOWSCLIPBOARDANYTEXTCONVERTER_H
|
||||
|
||||
#include "CMSWindowsClipboard.h"
|
||||
|
||||
//! Convert to/from some text encoding
|
||||
class CMSWindowsClipboardAnyTextConverter :
|
||||
public IMSWindowsClipboardConverter {
|
||||
public:
|
||||
CMSWindowsClipboardAnyTextConverter();
|
||||
virtual ~CMSWindowsClipboardAnyTextConverter();
|
||||
|
||||
// IMSWindowsClipboardConverter overrides
|
||||
virtual IClipboard::EFormat
|
||||
getFormat() const;
|
||||
virtual UINT getWin32Format() const = 0;
|
||||
virtual HANDLE fromIClipboard(const CString&) const;
|
||||
virtual CString toIClipboard(HANDLE) const;
|
||||
|
||||
protected:
|
||||
//! Convert from IClipboard format
|
||||
/*!
|
||||
Do UTF-8 conversion only. Memory handle allocation and
|
||||
linefeed conversion is done by this class. doFromIClipboard()
|
||||
must include the nul terminator in the returned string (not
|
||||
including the CString's nul terminator).
|
||||
*/
|
||||
virtual CString doFromIClipboard(const CString&) const = 0;
|
||||
|
||||
//! Convert to IClipboard format
|
||||
/*!
|
||||
Do UTF-8 conversion only. Memory handle allocation and
|
||||
linefeed conversion is done by this class.
|
||||
*/
|
||||
virtual CString doToIClipboard(const CString&) const = 0;
|
||||
|
||||
private:
|
||||
CString convertLinefeedToWin32(const CString&) const;
|
||||
CString convertLinefeedToUnix(const CString&) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
146
lib/platform/CMSWindowsClipboardBitmapConverter.cpp
Normal file
146
lib/platform/CMSWindowsClipboardBitmapConverter.cpp
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* 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 "CMSWindowsClipboardBitmapConverter.h"
|
||||
#include "CLog.h"
|
||||
|
||||
//
|
||||
// CMSWindowsClipboardBitmapConverter
|
||||
//
|
||||
|
||||
CMSWindowsClipboardBitmapConverter::CMSWindowsClipboardBitmapConverter()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
CMSWindowsClipboardBitmapConverter::~CMSWindowsClipboardBitmapConverter()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
IClipboard::EFormat
|
||||
CMSWindowsClipboardBitmapConverter::getFormat() const
|
||||
{
|
||||
return IClipboard::kBitmap;
|
||||
}
|
||||
|
||||
UINT
|
||||
CMSWindowsClipboardBitmapConverter::getWin32Format() const
|
||||
{
|
||||
return CF_DIB;
|
||||
}
|
||||
|
||||
HANDLE
|
||||
CMSWindowsClipboardBitmapConverter::fromIClipboard(const CString& data) const
|
||||
{
|
||||
// copy to memory handle
|
||||
HGLOBAL gData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, data.size());
|
||||
if (gData != NULL) {
|
||||
// get a pointer to the allocated memory
|
||||
char* dst = (char*)GlobalLock(gData);
|
||||
if (dst != NULL) {
|
||||
memcpy(dst, data.data(), data.size());
|
||||
GlobalUnlock(gData);
|
||||
}
|
||||
else {
|
||||
GlobalFree(gData);
|
||||
gData = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return gData;
|
||||
}
|
||||
|
||||
CString
|
||||
CMSWindowsClipboardBitmapConverter::toIClipboard(HANDLE data) const
|
||||
{
|
||||
// get datator
|
||||
const char* src = (const char*)GlobalLock(data);
|
||||
if (src == NULL) {
|
||||
return CString();
|
||||
}
|
||||
UInt32 srcSize = (UInt32)GlobalSize(data);
|
||||
|
||||
// check image type
|
||||
const BITMAPINFO* bitmap = reinterpret_cast<const BITMAPINFO*>(src);
|
||||
LOG((CLOG_INFO "bitmap: %dx%d %d", bitmap->bmiHeader.biWidth, bitmap->bmiHeader.biHeight, (int)bitmap->bmiHeader.biBitCount));
|
||||
if (bitmap->bmiHeader.biPlanes == 1 &&
|
||||
(bitmap->bmiHeader.biBitCount == 24 ||
|
||||
bitmap->bmiHeader.biBitCount == 32) &&
|
||||
bitmap->bmiHeader.biCompression == BI_RGB) {
|
||||
// already in canonical form
|
||||
CString image(src, srcSize);
|
||||
GlobalUnlock(data);
|
||||
return image;
|
||||
}
|
||||
|
||||
// create a destination DIB section
|
||||
LOG((CLOG_INFO "convert image from: depth=%d comp=%d", bitmap->bmiHeader.biBitCount, bitmap->bmiHeader.biCompression));
|
||||
void* raw;
|
||||
BITMAPINFOHEADER info;
|
||||
LONG w = bitmap->bmiHeader.biWidth;
|
||||
LONG h = bitmap->bmiHeader.biHeight;
|
||||
info.biSize = sizeof(BITMAPINFOHEADER);
|
||||
info.biWidth = w;
|
||||
info.biHeight = h;
|
||||
info.biPlanes = 1;
|
||||
info.biBitCount = 32;
|
||||
info.biCompression = BI_RGB;
|
||||
info.biSizeImage = 0;
|
||||
info.biXPelsPerMeter = 1000;
|
||||
info.biYPelsPerMeter = 1000;
|
||||
info.biClrUsed = 0;
|
||||
info.biClrImportant = 0;
|
||||
HDC dc = GetDC(NULL);
|
||||
HBITMAP dst = CreateDIBSection(dc, (BITMAPINFO*)&info,
|
||||
DIB_RGB_COLORS, &raw, NULL, 0);
|
||||
|
||||
// find the start of the pixel data
|
||||
const char* srcBits = (const char*)bitmap + bitmap->bmiHeader.biSize;
|
||||
if (bitmap->bmiHeader.biBitCount >= 16) {
|
||||
if (bitmap->bmiHeader.biCompression == BI_BITFIELDS &&
|
||||
(bitmap->bmiHeader.biBitCount == 16 ||
|
||||
bitmap->bmiHeader.biBitCount == 32)) {
|
||||
srcBits += 3 * sizeof(DWORD);
|
||||
}
|
||||
}
|
||||
else if (bitmap->bmiHeader.biClrUsed != 0) {
|
||||
srcBits += bitmap->bmiHeader.biClrUsed * sizeof(RGBQUAD);
|
||||
}
|
||||
else {
|
||||
srcBits += (1 << bitmap->bmiHeader.biBitCount) * sizeof(RGBQUAD);
|
||||
}
|
||||
|
||||
// copy source image to destination image
|
||||
HDC dstDC = CreateCompatibleDC(dc);
|
||||
HGDIOBJ oldBitmap = SelectObject(dstDC, dst);
|
||||
SetDIBitsToDevice(dstDC, 0, 0, w, h, 0, 0, 0, h,
|
||||
srcBits, bitmap, DIB_RGB_COLORS);
|
||||
SelectObject(dstDC, oldBitmap);
|
||||
DeleteDC(dstDC);
|
||||
GdiFlush();
|
||||
|
||||
// extract data
|
||||
CString image((const char*)&info, info.biSize);
|
||||
image.append((const char*)raw, 4 * w * h);
|
||||
|
||||
// clean up GDI
|
||||
DeleteObject(dst);
|
||||
ReleaseDC(NULL, dc);
|
||||
|
||||
// release handle
|
||||
GlobalUnlock(data);
|
||||
|
||||
return image;
|
||||
}
|
||||
35
lib/platform/CMSWindowsClipboardBitmapConverter.h
Normal file
35
lib/platform/CMSWindowsClipboardBitmapConverter.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef CMSWINDOWSCLIPBOARDBITMAPCONVERTER_H
|
||||
#define CMSWINDOWSCLIPBOARDBITMAPCONVERTER_H
|
||||
|
||||
#include "CMSWindowsClipboard.h"
|
||||
|
||||
//! Convert to/from some text encoding
|
||||
class CMSWindowsClipboardBitmapConverter :
|
||||
public IMSWindowsClipboardConverter {
|
||||
public:
|
||||
CMSWindowsClipboardBitmapConverter();
|
||||
virtual ~CMSWindowsClipboardBitmapConverter();
|
||||
|
||||
// IMSWindowsClipboardConverter overrides
|
||||
virtual IClipboard::EFormat
|
||||
getFormat() const;
|
||||
virtual UINT getWin32Format() const;
|
||||
virtual HANDLE fromIClipboard(const CString&) const;
|
||||
virtual CString toIClipboard(HANDLE) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
107
lib/platform/CMSWindowsClipboardHTMLConverter.cpp
Normal file
107
lib/platform/CMSWindowsClipboardHTMLConverter.cpp
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* 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 "CMSWindowsClipboardHTMLConverter.h"
|
||||
#include "CStringUtil.h"
|
||||
|
||||
//
|
||||
// CMSWindowsClipboardHTMLConverter
|
||||
//
|
||||
|
||||
CMSWindowsClipboardHTMLConverter::CMSWindowsClipboardHTMLConverter()
|
||||
{
|
||||
m_format = RegisterClipboardFormat("HTML Format");
|
||||
}
|
||||
|
||||
CMSWindowsClipboardHTMLConverter::~CMSWindowsClipboardHTMLConverter()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
IClipboard::EFormat
|
||||
CMSWindowsClipboardHTMLConverter::getFormat() const
|
||||
{
|
||||
return IClipboard::kHTML;
|
||||
}
|
||||
|
||||
UINT
|
||||
CMSWindowsClipboardHTMLConverter::getWin32Format() const
|
||||
{
|
||||
return m_format;
|
||||
}
|
||||
|
||||
CString
|
||||
CMSWindowsClipboardHTMLConverter::doFromIClipboard(const CString& data) const
|
||||
{
|
||||
// prepare to CF_HTML format prefix and suffix
|
||||
CString prefix("Version:0.9\nStartHTML:-1\nEndHTML:-1\n"
|
||||
"StartFragment:XXXXXXXXXX\nEndFragment:YYYYYYYYYY\n"
|
||||
"<!DOCTYPE><HTML><BODY><!--StartFragment-->");
|
||||
CString suffix("<!--EndFragment--></BODY></HTML>\n");
|
||||
UInt32 start = prefix.size();
|
||||
UInt32 end = start + data.size();
|
||||
prefix.replace(prefix.find("XXXXXXXXXX"), 10,
|
||||
CStringUtil::print("%010u", start));
|
||||
prefix.replace(prefix.find("YYYYYYYYYY"), 10,
|
||||
CStringUtil::print("%010u", end));
|
||||
|
||||
// concatenate
|
||||
prefix += data;
|
||||
prefix += suffix;
|
||||
return prefix;
|
||||
}
|
||||
|
||||
CString
|
||||
CMSWindowsClipboardHTMLConverter::doToIClipboard(const CString& data) const
|
||||
{
|
||||
// get fragment start/end args
|
||||
CString startArg = findArg(data, "StartFragment");
|
||||
CString endArg = findArg(data, "EndFragment");
|
||||
if (startArg.empty() || endArg.empty()) {
|
||||
return CString();
|
||||
}
|
||||
|
||||
// convert args to integers
|
||||
SInt32 start = (SInt32)atoi(startArg.c_str());
|
||||
SInt32 end = (SInt32)atoi(endArg.c_str());
|
||||
if (start <= 0 || end <= 0 || start >= end) {
|
||||
return CString();
|
||||
}
|
||||
|
||||
// extract the fragment
|
||||
return data.substr(start, end - start);
|
||||
}
|
||||
|
||||
CString
|
||||
CMSWindowsClipboardHTMLConverter::findArg(
|
||||
const CString& data, const CString& name) const
|
||||
{
|
||||
CString::size_type i = data.find(name);
|
||||
if (i == CString::npos) {
|
||||
return CString();
|
||||
}
|
||||
i = data.find_first_of(":\r\n", i);
|
||||
if (i == CString::npos || data[i] != ':') {
|
||||
return CString();
|
||||
}
|
||||
i = data.find_first_of("0123456789\r\n", i + 1);
|
||||
if (i == CString::npos || data[i] == '\r' || data[i] == '\n') {
|
||||
return CString();
|
||||
}
|
||||
CString::size_type j = data.find_first_not_of("0123456789", i);
|
||||
if (j == CString::npos) {
|
||||
j = data.size();
|
||||
}
|
||||
return data.substr(i, j - i);
|
||||
}
|
||||
44
lib/platform/CMSWindowsClipboardHTMLConverter.h
Normal file
44
lib/platform/CMSWindowsClipboardHTMLConverter.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef CMSWINDOWSCLIPBOARDHTMLCONVERTER_H
|
||||
#define CMSWINDOWSCLIPBOARDHTMLCONVERTER_H
|
||||
|
||||
#include "CMSWindowsClipboardAnyTextConverter.h"
|
||||
|
||||
//! Convert to/from HTML encoding
|
||||
class CMSWindowsClipboardHTMLConverter :
|
||||
public CMSWindowsClipboardAnyTextConverter {
|
||||
public:
|
||||
CMSWindowsClipboardHTMLConverter();
|
||||
virtual ~CMSWindowsClipboardHTMLConverter();
|
||||
|
||||
// IMSWindowsClipboardConverter overrides
|
||||
virtual IClipboard::EFormat
|
||||
getFormat() const;
|
||||
virtual UINT getWin32Format() const;
|
||||
|
||||
protected:
|
||||
// CMSWindowsClipboardAnyTextConverter overrides
|
||||
virtual CString doFromIClipboard(const CString&) const;
|
||||
virtual CString doToIClipboard(const CString&) const;
|
||||
|
||||
private:
|
||||
CString findArg(const CString& data, const CString& name) const;
|
||||
|
||||
private:
|
||||
UINT m_format;
|
||||
};
|
||||
|
||||
#endif
|
||||
55
lib/platform/CMSWindowsClipboardTextConverter.cpp
Normal file
55
lib/platform/CMSWindowsClipboardTextConverter.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 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 "CMSWindowsClipboardTextConverter.h"
|
||||
#include "CUnicode.h"
|
||||
|
||||
//
|
||||
// CMSWindowsClipboardTextConverter
|
||||
//
|
||||
|
||||
CMSWindowsClipboardTextConverter::CMSWindowsClipboardTextConverter()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
CMSWindowsClipboardTextConverter::~CMSWindowsClipboardTextConverter()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
UINT
|
||||
CMSWindowsClipboardTextConverter::getWin32Format() const
|
||||
{
|
||||
return CF_TEXT;
|
||||
}
|
||||
|
||||
CString
|
||||
CMSWindowsClipboardTextConverter::doFromIClipboard(const CString& data) const
|
||||
{
|
||||
// convert and add nul terminator
|
||||
return CUnicode::UTF8ToText(data) += '\0';
|
||||
}
|
||||
|
||||
CString
|
||||
CMSWindowsClipboardTextConverter::doToIClipboard(const CString& data) const
|
||||
{
|
||||
// convert and truncate at first nul terminator
|
||||
CString dst = CUnicode::textToUTF8(data);
|
||||
CString::size_type n = dst.find('\0');
|
||||
if (n != CString::npos) {
|
||||
dst.erase(n);
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
36
lib/platform/CMSWindowsClipboardTextConverter.h
Normal file
36
lib/platform/CMSWindowsClipboardTextConverter.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 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.
|
||||
*/
|
||||
|
||||
#ifndef CMSWINDOWSCLIPBOARDTEXTCONVERTER_H
|
||||
#define CMSWINDOWSCLIPBOARDTEXTCONVERTER_H
|
||||
|
||||
#include "CMSWindowsClipboardAnyTextConverter.h"
|
||||
|
||||
//! Convert to/from locale text encoding
|
||||
class CMSWindowsClipboardTextConverter :
|
||||
public CMSWindowsClipboardAnyTextConverter {
|
||||
public:
|
||||
CMSWindowsClipboardTextConverter();
|
||||
virtual ~CMSWindowsClipboardTextConverter();
|
||||
|
||||
// IMSWindowsClipboardConverter overrides
|
||||
virtual UINT getWin32Format() const;
|
||||
|
||||
protected:
|
||||
// CMSWindowsClipboardAnyTextConverter overrides
|
||||
virtual CString doFromIClipboard(const CString&) const;
|
||||
virtual CString doToIClipboard(const CString&) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
55
lib/platform/CMSWindowsClipboardUTF16Converter.cpp
Normal file
55
lib/platform/CMSWindowsClipboardUTF16Converter.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 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 "CMSWindowsClipboardUTF16Converter.h"
|
||||
#include "CUnicode.h"
|
||||
|
||||
//
|
||||
// CMSWindowsClipboardUTF16Converter
|
||||
//
|
||||
|
||||
CMSWindowsClipboardUTF16Converter::CMSWindowsClipboardUTF16Converter()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
CMSWindowsClipboardUTF16Converter::~CMSWindowsClipboardUTF16Converter()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
UINT
|
||||
CMSWindowsClipboardUTF16Converter::getWin32Format() const
|
||||
{
|
||||
return CF_UNICODETEXT;
|
||||
}
|
||||
|
||||
CString
|
||||
CMSWindowsClipboardUTF16Converter::doFromIClipboard(const CString& data) const
|
||||
{
|
||||
// convert and add nul terminator
|
||||
return CUnicode::UTF8ToUTF16(data).append(sizeof(wchar_t), 0);
|
||||
}
|
||||
|
||||
CString
|
||||
CMSWindowsClipboardUTF16Converter::doToIClipboard(const CString& data) const
|
||||
{
|
||||
// convert and strip nul terminator
|
||||
CString dst = CUnicode::UTF16ToUTF8(data);
|
||||
CString::size_type n = dst.find('\0');
|
||||
if (n != CString::npos) {
|
||||
dst.erase(n);
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
36
lib/platform/CMSWindowsClipboardUTF16Converter.h
Normal file
36
lib/platform/CMSWindowsClipboardUTF16Converter.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 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.
|
||||
*/
|
||||
|
||||
#ifndef CMSWINDOWSCLIPBOARDUTF16CONVERTER_H
|
||||
#define CMSWINDOWSCLIPBOARDUTF16CONVERTER_H
|
||||
|
||||
#include "CMSWindowsClipboardAnyTextConverter.h"
|
||||
|
||||
//! Convert to/from UTF-16 encoding
|
||||
class CMSWindowsClipboardUTF16Converter :
|
||||
public CMSWindowsClipboardAnyTextConverter {
|
||||
public:
|
||||
CMSWindowsClipboardUTF16Converter();
|
||||
virtual ~CMSWindowsClipboardUTF16Converter();
|
||||
|
||||
// IMSWindowsClipboardConverter overrides
|
||||
virtual UINT getWin32Format() const;
|
||||
|
||||
protected:
|
||||
// CMSWindowsClipboardAnyTextConverter overrides
|
||||
virtual CString doFromIClipboard(const CString&) const;
|
||||
virtual CString doToIClipboard(const CString&) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
1033
lib/platform/CMSWindowsDesks.cpp
Normal file
1033
lib/platform/CMSWindowsDesks.cpp
Normal file
File diff suppressed because it is too large
Load Diff
296
lib/platform/CMSWindowsDesks.h
Normal file
296
lib/platform/CMSWindowsDesks.h
Normal file
@@ -0,0 +1,296 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef CMSWINDOWSDESKS_H
|
||||
#define CMSWINDOWSDESKS_H
|
||||
|
||||
#include "CSynergyHook.h"
|
||||
#include "KeyTypes.h"
|
||||
#include "MouseTypes.h"
|
||||
#include "OptionTypes.h"
|
||||
#include "CCondVar.h"
|
||||
#include "CMutex.h"
|
||||
#include "CString.h"
|
||||
#include "stdmap.h"
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
class CEvent;
|
||||
class CEventQueueTimer;
|
||||
class CThread;
|
||||
class IJob;
|
||||
class IScreenSaver;
|
||||
|
||||
//! Microsoft Windows desk handling
|
||||
/*!
|
||||
Desks in Microsoft Windows are only remotely like desktops on X11
|
||||
systems. A desk is another virtual surface for windows but desks
|
||||
impose serious restrictions: a thread can interact with only one
|
||||
desk at a time, you can't switch desks if the thread has any hooks
|
||||
installed or owns any windows, windows cannot exist on multiple
|
||||
desks at once, etc. Basically, they're useless except for running
|
||||
the login window or the screensaver, which is what they're used
|
||||
for. Synergy must deal with them mainly because of the login
|
||||
window and screensaver but users can create their own desks and
|
||||
synergy should work on those too.
|
||||
|
||||
This class encapsulates all the desk nastiness. Clients of this
|
||||
object don't have to know anything about desks.
|
||||
*/
|
||||
class CMSWindowsDesks {
|
||||
public:
|
||||
//! Constructor
|
||||
/*!
|
||||
\p isPrimary is true iff the desk is for a primary screen.
|
||||
\p screensaver points to a screensaver object and it's used
|
||||
only to check if the screensaver is active. The \p updateKeys
|
||||
job is adopted and is called when the key state should be
|
||||
updated in a thread attached to the current desk.
|
||||
\p hookLibrary must be a handle to the hook library.
|
||||
*/
|
||||
CMSWindowsDesks(bool isPrimary, HINSTANCE hookLibrary,
|
||||
const IScreenSaver* screensaver, IJob* updateKeys);
|
||||
~CMSWindowsDesks();
|
||||
|
||||
//! @name manipulators
|
||||
//@{
|
||||
|
||||
//! Enable desk tracking
|
||||
/*!
|
||||
Enables desk tracking. While enabled, this object checks to see
|
||||
if the desk has changed and ensures that the hooks are installed
|
||||
on the new desk. \c setShape should be called at least once
|
||||
before calling \c enable.
|
||||
*/
|
||||
void enable();
|
||||
|
||||
//! Disable desk tracking
|
||||
/*!
|
||||
Disables desk tracking. \sa enable.
|
||||
*/
|
||||
void disable();
|
||||
|
||||
//! Notify of entering a desk
|
||||
/*!
|
||||
Prepares a desk for when the cursor enters it.
|
||||
*/
|
||||
void enter();
|
||||
|
||||
//! Notify of leaving a desk
|
||||
/*!
|
||||
Prepares a desk for when the cursor leaves it.
|
||||
*/
|
||||
void leave(HKL keyLayout);
|
||||
|
||||
//! Notify of options changes
|
||||
/*!
|
||||
Resets all options to their default values.
|
||||
*/
|
||||
void resetOptions();
|
||||
|
||||
//! Notify of options changes
|
||||
/*!
|
||||
Set options to given values. Ignores unknown options and doesn't
|
||||
modify options that aren't given in \c options.
|
||||
*/
|
||||
void setOptions(const COptionsList& options);
|
||||
|
||||
//! Update the key state
|
||||
/*!
|
||||
Causes the key state to get updated to reflect the physical keyboard
|
||||
state and current keyboard mapping.
|
||||
*/
|
||||
void updateKeys();
|
||||
|
||||
//! Tell desk about new size
|
||||
/*!
|
||||
This tells the desks that the display size has changed.
|
||||
*/
|
||||
void setShape(SInt32 x, SInt32 y,
|
||||
SInt32 width, SInt32 height,
|
||||
SInt32 xCenter, SInt32 yCenter, bool isMultimon);
|
||||
|
||||
//! Install/uninstall screensaver hooks
|
||||
/*!
|
||||
If \p install is true then the screensaver hooks are installed and,
|
||||
if desk tracking is enabled, updated whenever the desk changes. If
|
||||
\p install is false then the screensaver hooks are uninstalled.
|
||||
*/
|
||||
void installScreensaverHooks(bool install);
|
||||
|
||||
//! Start ignoring user input
|
||||
/*!
|
||||
Starts ignoring user input so we don't pick up our own synthesized events.
|
||||
*/
|
||||
void fakeInputBegin();
|
||||
|
||||
//! Stop ignoring user input
|
||||
/*!
|
||||
Undoes whatever \c fakeInputBegin() did.
|
||||
*/
|
||||
void fakeInputEnd();
|
||||
|
||||
//@}
|
||||
//! @name accessors
|
||||
//@{
|
||||
|
||||
//! Get cursor position
|
||||
/*!
|
||||
Return the current position of the cursor in \c x and \c y.
|
||||
*/
|
||||
void getCursorPos(SInt32& x, SInt32& y) const;
|
||||
|
||||
//! Fake key press/release
|
||||
/*!
|
||||
Synthesize a press or release of key \c button.
|
||||
*/
|
||||
void fakeKeyEvent(KeyButton button, UINT virtualKey,
|
||||
bool press, bool isAutoRepeat) const;
|
||||
|
||||
//! Fake mouse press/release
|
||||
/*!
|
||||
Synthesize a press or release of mouse button \c id.
|
||||
*/
|
||||
void fakeMouseButton(ButtonID id, bool press) const;
|
||||
|
||||
//! Fake mouse move
|
||||
/*!
|
||||
Synthesize a mouse move to the absolute coordinates \c x,y.
|
||||
*/
|
||||
void fakeMouseMove(SInt32 x, SInt32 y) const;
|
||||
|
||||
//! Fake mouse move
|
||||
/*!
|
||||
Synthesize a mouse move to the relative coordinates \c dx,dy.
|
||||
*/
|
||||
void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const;
|
||||
|
||||
//! Fake mouse wheel
|
||||
/*!
|
||||
Synthesize a mouse wheel event of amount \c delta in direction \c axis.
|
||||
*/
|
||||
void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const;
|
||||
|
||||
//@}
|
||||
|
||||
private:
|
||||
class CDesk {
|
||||
public:
|
||||
CString m_name;
|
||||
CThread* m_thread;
|
||||
DWORD m_threadID;
|
||||
DWORD m_targetID;
|
||||
HDESK m_desk;
|
||||
HWND m_window;
|
||||
HWND m_foregroundWindow;
|
||||
bool m_lowLevel;
|
||||
};
|
||||
typedef std::map<CString, CDesk*> CDesks;
|
||||
|
||||
// initialization and shutdown operations
|
||||
void queryHookLibrary(HINSTANCE hookLibrary);
|
||||
HCURSOR createBlankCursor() const;
|
||||
void destroyCursor(HCURSOR cursor) const;
|
||||
ATOM createDeskWindowClass(bool isPrimary) const;
|
||||
void destroyClass(ATOM windowClass) const;
|
||||
HWND createWindow(ATOM windowClass, const char* name) const;
|
||||
void destroyWindow(HWND) const;
|
||||
|
||||
// message handlers
|
||||
void deskMouseMove(SInt32 x, SInt32 y) const;
|
||||
void deskMouseRelativeMove(SInt32 dx, SInt32 dy) const;
|
||||
void deskEnter(CDesk* desk);
|
||||
void deskLeave(CDesk* desk, HKL keyLayout);
|
||||
void deskThread(void* vdesk);
|
||||
|
||||
// desk switch checking and handling
|
||||
CDesk* addDesk(const CString& name, HDESK hdesk);
|
||||
void removeDesks();
|
||||
void checkDesk();
|
||||
bool isDeskAccessible(const CDesk* desk) const;
|
||||
void handleCheckDesk(const CEvent& event, void*);
|
||||
|
||||
// communication with desk threads
|
||||
void waitForDesk() const;
|
||||
void sendMessage(UINT, WPARAM, LPARAM) const;
|
||||
|
||||
// work around for messed up keyboard events from low-level hooks
|
||||
HWND getForegroundWindow() const;
|
||||
|
||||
// desk API wrappers
|
||||
HDESK openInputDesktop();
|
||||
void closeDesktop(HDESK);
|
||||
CString getDesktopName(HDESK);
|
||||
|
||||
// our desk window procs
|
||||
static LRESULT CALLBACK primaryDeskProc(HWND, UINT, WPARAM, LPARAM);
|
||||
static LRESULT CALLBACK secondaryDeskProc(HWND, UINT, WPARAM, LPARAM);
|
||||
|
||||
private:
|
||||
// true if screen is being used as a primary screen, false otherwise
|
||||
bool m_isPrimary;
|
||||
|
||||
// true if windows 95/98/me
|
||||
bool m_is95Family;
|
||||
|
||||
// true if windows 98/2k or higher (i.e. not 95/nt)
|
||||
bool m_isModernFamily;
|
||||
|
||||
// true if mouse has entered the screen
|
||||
bool m_isOnScreen;
|
||||
|
||||
// our resources
|
||||
ATOM m_deskClass;
|
||||
HCURSOR m_cursor;
|
||||
|
||||
// screen shape stuff
|
||||
SInt32 m_x, m_y;
|
||||
SInt32 m_w, m_h;
|
||||
SInt32 m_xCenter, m_yCenter;
|
||||
|
||||
// true if system appears to have multiple monitors
|
||||
bool m_multimon;
|
||||
|
||||
// the timer used to check for desktop switching
|
||||
CEventQueueTimer* m_timer;
|
||||
|
||||
// screen saver stuff
|
||||
DWORD m_threadID;
|
||||
const IScreenSaver* m_screensaver;
|
||||
bool m_screensaverNotify;
|
||||
|
||||
// the current desk and it's name
|
||||
CDesk* m_activeDesk;
|
||||
CString m_activeDeskName;
|
||||
|
||||
// one desk per desktop and a cond var to communicate with it
|
||||
CMutex m_mutex;
|
||||
CCondVar<bool> m_deskReady;
|
||||
CDesks m_desks;
|
||||
|
||||
// hook library stuff
|
||||
InstallFunc m_install;
|
||||
UninstallFunc m_uninstall;
|
||||
InstallScreenSaverFunc m_installScreensaver;
|
||||
UninstallScreenSaverFunc m_uninstallScreensaver;
|
||||
|
||||
// keyboard stuff
|
||||
IJob* m_updateKeys;
|
||||
HKL m_keyLayout;
|
||||
|
||||
// options
|
||||
bool m_leaveForegroundOption;
|
||||
};
|
||||
|
||||
#endif
|
||||
138
lib/platform/CMSWindowsEventQueueBuffer.cpp
Normal file
138
lib/platform/CMSWindowsEventQueueBuffer.cpp
Normal file
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* 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 "CMSWindowsEventQueueBuffer.h"
|
||||
#include "CThread.h"
|
||||
#include "IEventQueue.h"
|
||||
#include "CArchMiscWindows.h"
|
||||
|
||||
//
|
||||
// CEventQueueTimer
|
||||
//
|
||||
|
||||
class CEventQueueTimer { };
|
||||
|
||||
|
||||
//
|
||||
// CMSWindowsEventQueueBuffer
|
||||
//
|
||||
|
||||
CMSWindowsEventQueueBuffer::CMSWindowsEventQueueBuffer()
|
||||
{
|
||||
// remember thread. we'll be posting messages to it.
|
||||
m_thread = GetCurrentThreadId();
|
||||
|
||||
// create a message type for custom events
|
||||
m_userEvent = RegisterWindowMessage("SYNERGY_USER_EVENT");
|
||||
|
||||
// get message type for daemon quit
|
||||
m_daemonQuit = CArchMiscWindows::getDaemonQuitMessage();
|
||||
|
||||
// make sure this thread has a message queue
|
||||
MSG dummy;
|
||||
PeekMessage(&dummy, NULL, WM_USER, WM_USER, PM_NOREMOVE);
|
||||
}
|
||||
|
||||
CMSWindowsEventQueueBuffer::~CMSWindowsEventQueueBuffer()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsEventQueueBuffer::waitForEvent(double timeout)
|
||||
{
|
||||
// check if messages are available first. if we don't do this then
|
||||
// MsgWaitForMultipleObjects() will block even if the queue isn't
|
||||
// empty if the messages in the queue were there before the last
|
||||
// call to GetMessage()/PeekMessage().
|
||||
if (HIWORD(GetQueueStatus(QS_ALLINPUT)) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// convert timeout
|
||||
DWORD t;
|
||||
if (timeout < 0.0) {
|
||||
t = INFINITE;
|
||||
}
|
||||
else {
|
||||
t = (DWORD)(1000.0 * timeout);
|
||||
}
|
||||
|
||||
// wait for a message. we cannot be interrupted by thread
|
||||
// cancellation but that's okay because we're run in the main
|
||||
// thread and we never cancel that thread.
|
||||
HANDLE dummy[1];
|
||||
MsgWaitForMultipleObjects(0, dummy, FALSE, t, QS_ALLINPUT);
|
||||
}
|
||||
|
||||
IEventQueueBuffer::Type
|
||||
CMSWindowsEventQueueBuffer::getEvent(CEvent& event, UInt32& dataID)
|
||||
{
|
||||
// peek at messages first. waiting for QS_ALLINPUT will return
|
||||
// if a message has been sent to our window but GetMessage will
|
||||
// dispatch that message behind our backs and block. PeekMessage
|
||||
// will also dispatch behind our backs but won't block.
|
||||
if (!PeekMessage(&m_event, NULL, 0, 0, PM_NOREMOVE) &&
|
||||
!PeekMessage(&m_event, (HWND)-1, 0, 0, PM_NOREMOVE)) {
|
||||
return kNone;
|
||||
}
|
||||
|
||||
// BOOL. yeah, right.
|
||||
BOOL result = GetMessage(&m_event, NULL, 0, 0);
|
||||
if (result == -1) {
|
||||
return kNone;
|
||||
}
|
||||
else if (result == 0) {
|
||||
event = CEvent(CEvent::kQuit);
|
||||
return kSystem;
|
||||
}
|
||||
else if (m_daemonQuit != 0 && m_event.message == m_daemonQuit) {
|
||||
event = CEvent(CEvent::kQuit);
|
||||
return kSystem;
|
||||
}
|
||||
else if (m_event.message == m_userEvent) {
|
||||
dataID = static_cast<UInt32>(m_event.wParam);
|
||||
return kUser;
|
||||
}
|
||||
else {
|
||||
event = CEvent(CEvent::kSystem,
|
||||
IEventQueue::getSystemTarget(), &m_event);
|
||||
return kSystem;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CMSWindowsEventQueueBuffer::addEvent(UInt32 dataID)
|
||||
{
|
||||
return (PostThreadMessage(m_thread, m_userEvent,
|
||||
static_cast<WPARAM>(dataID), 0) != 0);
|
||||
}
|
||||
|
||||
bool
|
||||
CMSWindowsEventQueueBuffer::isEmpty() const
|
||||
{
|
||||
return (HIWORD(GetQueueStatus(QS_ALLINPUT)) == 0);
|
||||
}
|
||||
|
||||
CEventQueueTimer*
|
||||
CMSWindowsEventQueueBuffer::newTimer(double, bool) const
|
||||
{
|
||||
return new CEventQueueTimer;
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsEventQueueBuffer::deleteTimer(CEventQueueTimer* timer) const
|
||||
{
|
||||
delete timer;
|
||||
}
|
||||
44
lib/platform/CMSWindowsEventQueueBuffer.h
Normal file
44
lib/platform/CMSWindowsEventQueueBuffer.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef CMSWINDOWSEVENTQUEUEBUFFER_H
|
||||
#define CMSWINDOWSEVENTQUEUEBUFFER_H
|
||||
|
||||
#include "IEventQueueBuffer.h"
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
//! Event queue buffer for Win32
|
||||
class CMSWindowsEventQueueBuffer : public IEventQueueBuffer {
|
||||
public:
|
||||
CMSWindowsEventQueueBuffer();
|
||||
virtual ~CMSWindowsEventQueueBuffer();
|
||||
|
||||
// IEventQueueBuffer overrides
|
||||
virtual void waitForEvent(double timeout);
|
||||
virtual Type getEvent(CEvent& event, UInt32& dataID);
|
||||
virtual bool addEvent(UInt32 dataID);
|
||||
virtual bool isEmpty() const;
|
||||
virtual CEventQueueTimer*
|
||||
newTimer(double duration, bool oneShot) const;
|
||||
virtual void deleteTimer(CEventQueueTimer*) const;
|
||||
|
||||
private:
|
||||
DWORD m_thread;
|
||||
UINT m_userEvent;
|
||||
MSG m_event;
|
||||
UINT m_daemonQuit;
|
||||
};
|
||||
|
||||
#endif
|
||||
1420
lib/platform/CMSWindowsKeyState.cpp
Normal file
1420
lib/platform/CMSWindowsKeyState.cpp
Normal file
File diff suppressed because it is too large
Load Diff
216
lib/platform/CMSWindowsKeyState.h
Normal file
216
lib/platform/CMSWindowsKeyState.h
Normal file
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2003 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.
|
||||
*/
|
||||
|
||||
#ifndef CMSWINDOWSKEYSTATE_H
|
||||
#define CMSWINDOWSKEYSTATE_H
|
||||
|
||||
#include "CKeyState.h"
|
||||
#include "CString.h"
|
||||
#include "stdvector.h"
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
class CEvent;
|
||||
class CEventQueueTimer;
|
||||
class CMSWindowsDesks;
|
||||
|
||||
//! Microsoft Windows key mapper
|
||||
/*!
|
||||
This class maps KeyIDs to keystrokes.
|
||||
*/
|
||||
class CMSWindowsKeyState : public CKeyState {
|
||||
public:
|
||||
CMSWindowsKeyState(CMSWindowsDesks* desks, void* eventTarget);
|
||||
virtual ~CMSWindowsKeyState();
|
||||
|
||||
//! @name manipulators
|
||||
//@{
|
||||
|
||||
//! Handle screen disabling
|
||||
/*!
|
||||
Called when screen is disabled. This is needed to deal with platform
|
||||
brokenness.
|
||||
*/
|
||||
void disable();
|
||||
|
||||
//! Set the active keyboard layout
|
||||
/*!
|
||||
Uses \p keyLayout when querying the keyboard.
|
||||
*/
|
||||
void setKeyLayout(HKL keyLayout);
|
||||
|
||||
//! Test and set autorepeat state
|
||||
/*!
|
||||
Returns true if the given button is autorepeating and updates internal
|
||||
state.
|
||||
*/
|
||||
bool testAutoRepeat(bool press, bool isRepeat, KeyButton);
|
||||
|
||||
//! Remember modifier state
|
||||
/*!
|
||||
Records the current non-toggle modifier state.
|
||||
*/
|
||||
void saveModifiers();
|
||||
|
||||
//! Set effective modifier state
|
||||
/*!
|
||||
Temporarily sets the non-toggle modifier state to those saved by the
|
||||
last call to \c saveModifiers if \p enable is \c true. Restores the
|
||||
modifier state to the current modifier state if \p enable is \c false.
|
||||
This is for synthesizing keystrokes on the primary screen when the
|
||||
cursor is on a secondary screen. When on a secondary screen we capture
|
||||
all non-toggle modifier state, track the state internally and do not
|
||||
pass it on. So if Alt+F1 synthesizes Alt+X we need to synthesize
|
||||
not just X but also Alt, despite the fact that our internal modifier
|
||||
state indicates Alt is down, because local apps never saw the Alt down
|
||||
event.
|
||||
*/
|
||||
void useSavedModifiers(bool enable);
|
||||
|
||||
//@}
|
||||
//! @name accessors
|
||||
//@{
|
||||
|
||||
//! Map a virtual key to a button
|
||||
/*!
|
||||
Returns the button for the \p virtualKey.
|
||||
*/
|
||||
KeyButton virtualKeyToButton(UINT virtualKey) const;
|
||||
|
||||
//! Map key event to a key
|
||||
/*!
|
||||
Converts a key event into a KeyID and the shadow modifier state
|
||||
to a modifier mask.
|
||||
*/
|
||||
KeyID mapKeyFromEvent(WPARAM charAndVirtKey,
|
||||
LPARAM info, KeyModifierMask* maskOut) const;
|
||||
|
||||
//! Check if keyboard groups have changed
|
||||
/*!
|
||||
Returns true iff the number or order of the keyboard groups have
|
||||
changed since the last call to updateKeys().
|
||||
*/
|
||||
bool didGroupsChange() const;
|
||||
|
||||
//! Map key to virtual key
|
||||
/*!
|
||||
Returns the virtual key for key \p key or 0 if there's no such virtual
|
||||
key.
|
||||
*/
|
||||
UINT mapKeyToVirtualKey(KeyID key) const;
|
||||
|
||||
//! Map virtual key and button to KeyID
|
||||
/*!
|
||||
Returns the KeyID for virtual key \p virtualKey and button \p button
|
||||
(button should include the extended key bit), or kKeyNone if there is
|
||||
no such key.
|
||||
*/
|
||||
static KeyID getKeyID(UINT virtualKey, KeyButton button);
|
||||
|
||||
//@}
|
||||
|
||||
// IKeyState overrides
|
||||
virtual void fakeKeyDown(KeyID id, KeyModifierMask mask,
|
||||
KeyButton button);
|
||||
virtual void fakeKeyRepeat(KeyID id, KeyModifierMask mask,
|
||||
SInt32 count, KeyButton button);
|
||||
virtual bool fakeCtrlAltDel();
|
||||
virtual KeyModifierMask
|
||||
pollActiveModifiers() const;
|
||||
virtual SInt32 pollActiveGroup() const;
|
||||
virtual void pollPressedKeys(KeyButtonSet& pressedKeys) const;
|
||||
|
||||
// CKeyState overrides
|
||||
virtual void onKey(KeyButton button, bool down,
|
||||
KeyModifierMask newState);
|
||||
virtual void sendKeyEvent(void* target,
|
||||
bool press, bool isAutoRepeat,
|
||||
KeyID key, KeyModifierMask mask,
|
||||
SInt32 count, KeyButton button);
|
||||
|
||||
protected:
|
||||
// CKeyState overrides
|
||||
virtual void getKeyMap(CKeyMap& keyMap);
|
||||
virtual void fakeKey(const Keystroke& keystroke);
|
||||
virtual KeyModifierMask&
|
||||
getActiveModifiersRValue();
|
||||
|
||||
private:
|
||||
typedef std::vector<HKL> GroupList;
|
||||
|
||||
// send ctrl+alt+del hotkey event on NT family
|
||||
static void ctrlAltDelThread(void*);
|
||||
|
||||
bool getGroups(GroupList&) const;
|
||||
void setWindowGroup(SInt32 group);
|
||||
|
||||
void fixKeys();
|
||||
void handleFixKeys(const CEvent&, void*);
|
||||
|
||||
KeyID getIDForKey(CKeyMap::KeyItem& item,
|
||||
KeyButton button, UINT virtualKey,
|
||||
PBYTE keyState, HKL hkl) const;
|
||||
|
||||
void addKeyEntry(CKeyMap& keyMap, CKeyMap::KeyItem& item);
|
||||
|
||||
private:
|
||||
// not implemented
|
||||
CMSWindowsKeyState(const CMSWindowsKeyState&);
|
||||
CMSWindowsKeyState& operator=(const CMSWindowsKeyState&);
|
||||
|
||||
private:
|
||||
typedef std::map<HKL, SInt32> GroupMap;
|
||||
typedef std::map<KeyID, UINT> KeyToVKMap;
|
||||
|
||||
bool m_is95Family;
|
||||
void* m_eventTarget;
|
||||
CMSWindowsDesks* m_desks;
|
||||
HKL m_keyLayout;
|
||||
UINT m_buttonToVK[512];
|
||||
UINT m_buttonToNumpadVK[512];
|
||||
KeyButton m_virtualKeyToButton[256];
|
||||
KeyToVKMap m_keyToVKMap;
|
||||
|
||||
// the timer used to check for fixing key state
|
||||
CEventQueueTimer* m_fixTimer;
|
||||
|
||||
// the groups (keyboard layouts)
|
||||
GroupList m_groups;
|
||||
GroupMap m_groupMap;
|
||||
|
||||
// the last button that we generated a key down event for. this
|
||||
// is zero if the last key event was a key up. we use this to
|
||||
// synthesize key repeats since the low level keyboard hook can't
|
||||
// tell us if an event is a key repeat.
|
||||
KeyButton m_lastDown;
|
||||
|
||||
// modifier tracking
|
||||
bool m_useSavedModifiers;
|
||||
KeyModifierMask m_savedModifiers;
|
||||
KeyModifierMask m_originalSavedModifiers;
|
||||
|
||||
// pointer to ToUnicodeEx. on win95 family this will be NULL.
|
||||
typedef int (WINAPI *ToUnicodeEx_t)(UINT wVirtKey,
|
||||
UINT wScanCode,
|
||||
PBYTE lpKeyState,
|
||||
LPWSTR pwszBuff,
|
||||
int cchBuff,
|
||||
UINT wFlags,
|
||||
HKL dwhkl);
|
||||
ToUnicodeEx_t m_ToUnicodeEx;
|
||||
|
||||
static const KeyID s_virtualKey[];
|
||||
};
|
||||
|
||||
#endif
|
||||
1738
lib/platform/CMSWindowsScreen.cpp
Normal file
1738
lib/platform/CMSWindowsScreen.cpp
Normal file
File diff suppressed because it is too large
Load Diff
308
lib/platform/CMSWindowsScreen.h
Normal file
308
lib/platform/CMSWindowsScreen.h
Normal file
@@ -0,0 +1,308 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 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.
|
||||
*/
|
||||
|
||||
#ifndef CMSWINDOWSSCREEN_H
|
||||
#define CMSWINDOWSSCREEN_H
|
||||
|
||||
#include "CPlatformScreen.h"
|
||||
#include "CSynergyHook.h"
|
||||
#include "CCondVar.h"
|
||||
#include "CMutex.h"
|
||||
#include "CString.h"
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
class CEventQueueTimer;
|
||||
class CMSWindowsDesks;
|
||||
class CMSWindowsKeyState;
|
||||
class CMSWindowsScreenSaver;
|
||||
class CThread;
|
||||
|
||||
//! Implementation of IPlatformScreen for Microsoft Windows
|
||||
class CMSWindowsScreen : public CPlatformScreen {
|
||||
public:
|
||||
CMSWindowsScreen(bool isPrimary);
|
||||
virtual ~CMSWindowsScreen();
|
||||
|
||||
//! @name manipulators
|
||||
//@{
|
||||
|
||||
//! Initialize
|
||||
/*!
|
||||
Saves the application's HINSTANCE. This \b must be called by
|
||||
WinMain with the HINSTANCE it was passed.
|
||||
*/
|
||||
static void init(HINSTANCE);
|
||||
|
||||
//@}
|
||||
//! @name accessors
|
||||
//@{
|
||||
|
||||
//! Get instance
|
||||
/*!
|
||||
Returns the application instance handle passed to init().
|
||||
*/
|
||||
static HINSTANCE getInstance();
|
||||
|
||||
//@}
|
||||
|
||||
// IScreen overrides
|
||||
virtual void* getEventTarget() const;
|
||||
virtual bool getClipboard(ClipboardID id, IClipboard*) const;
|
||||
virtual void getShape(SInt32& x, SInt32& y,
|
||||
SInt32& width, SInt32& height) const;
|
||||
virtual void getCursorPos(SInt32& x, SInt32& y) const;
|
||||
|
||||
// IPrimaryScreen overrides
|
||||
virtual void reconfigure(UInt32 activeSides);
|
||||
virtual void warpCursor(SInt32 x, SInt32 y);
|
||||
virtual UInt32 registerHotKey(KeyID key,
|
||||
KeyModifierMask mask);
|
||||
virtual void unregisterHotKey(UInt32 id);
|
||||
virtual void fakeInputBegin();
|
||||
virtual void fakeInputEnd();
|
||||
virtual SInt32 getJumpZoneSize() const;
|
||||
virtual bool isAnyMouseButtonDown() const;
|
||||
virtual void getCursorCenter(SInt32& x, SInt32& y) const;
|
||||
|
||||
// ISecondaryScreen overrides
|
||||
virtual void fakeMouseButton(ButtonID id, bool press) const;
|
||||
virtual void fakeMouseMove(SInt32 x, SInt32 y) const;
|
||||
virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const;
|
||||
virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const;
|
||||
|
||||
// IKeyState overrides
|
||||
virtual void updateKeys();
|
||||
virtual void fakeKeyDown(KeyID id, KeyModifierMask mask,
|
||||
KeyButton button);
|
||||
virtual void fakeKeyRepeat(KeyID id, KeyModifierMask mask,
|
||||
SInt32 count, KeyButton button);
|
||||
virtual void fakeKeyUp(KeyButton button);
|
||||
virtual void fakeAllKeysUp();
|
||||
|
||||
// IPlatformScreen overrides
|
||||
virtual void enable();
|
||||
virtual void disable();
|
||||
virtual void enter();
|
||||
virtual bool leave();
|
||||
virtual bool setClipboard(ClipboardID, const IClipboard*);
|
||||
virtual void checkClipboards();
|
||||
virtual void openScreensaver(bool notify);
|
||||
virtual void closeScreensaver();
|
||||
virtual void screensaver(bool activate);
|
||||
virtual void resetOptions();
|
||||
virtual void setOptions(const COptionsList& options);
|
||||
virtual void setSequenceNumber(UInt32);
|
||||
virtual bool isPrimary() const;
|
||||
|
||||
protected:
|
||||
// IPlatformScreen overrides
|
||||
virtual void handleSystemEvent(const CEvent&, void*);
|
||||
virtual void updateButtons();
|
||||
virtual IKeyState* getKeyState() const;
|
||||
|
||||
private:
|
||||
// initialization and shutdown operations
|
||||
HINSTANCE openHookLibrary(const char* name);
|
||||
void closeHookLibrary(HINSTANCE hookLibrary) const;
|
||||
HCURSOR createBlankCursor() const;
|
||||
void destroyCursor(HCURSOR cursor) const;
|
||||
ATOM createWindowClass() const;
|
||||
ATOM createDeskWindowClass(bool isPrimary) const;
|
||||
void destroyClass(ATOM windowClass) const;
|
||||
HWND createWindow(ATOM windowClass, const char* name) const;
|
||||
void destroyWindow(HWND) const;
|
||||
|
||||
// convenience function to send events
|
||||
void sendEvent(CEvent::Type type, void* = NULL);
|
||||
void sendClipboardEvent(CEvent::Type type, ClipboardID id);
|
||||
|
||||
// handle message before it gets dispatched. returns true iff
|
||||
// the message should not be dispatched.
|
||||
bool onPreDispatch(HWND, UINT, WPARAM, LPARAM);
|
||||
|
||||
// handle message before it gets dispatched. returns true iff
|
||||
// the message should not be dispatched.
|
||||
bool onPreDispatchPrimary(HWND, UINT, WPARAM, LPARAM);
|
||||
|
||||
// handle message. returns true iff handled and optionally sets
|
||||
// \c *result (which defaults to 0).
|
||||
bool onEvent(HWND, UINT, WPARAM, LPARAM, LRESULT* result);
|
||||
|
||||
// message handlers
|
||||
bool onMark(UInt32 mark);
|
||||
bool onKey(WPARAM, LPARAM);
|
||||
bool onHotKey(WPARAM, LPARAM);
|
||||
bool onMouseButton(WPARAM, LPARAM);
|
||||
bool onMouseMove(SInt32 x, SInt32 y);
|
||||
bool onMouseWheel(SInt32 xDelta, SInt32 yDelta);
|
||||
bool onScreensaver(bool activated);
|
||||
bool onDisplayChange();
|
||||
bool onClipboardChange();
|
||||
|
||||
// warp cursor without discarding queued events
|
||||
void warpCursorNoFlush(SInt32 x, SInt32 y);
|
||||
|
||||
// discard posted messages
|
||||
void nextMark();
|
||||
|
||||
// test if event should be ignored
|
||||
bool ignore() const;
|
||||
|
||||
// update screen size cache
|
||||
void updateScreenShape();
|
||||
|
||||
// fix timer callback
|
||||
void handleFixes(const CEvent&, void*);
|
||||
|
||||
// fix the clipboard viewer chain
|
||||
void fixClipboardViewer();
|
||||
|
||||
// enable/disable special key combinations so we can catch/pass them
|
||||
void enableSpecialKeys(bool) const;
|
||||
|
||||
// map a button event to a button ID
|
||||
ButtonID mapButtonFromEvent(WPARAM msg, LPARAM button) const;
|
||||
|
||||
// map a button event to a press (true) or release (false)
|
||||
bool mapPressFromEvent(WPARAM msg, LPARAM button) const;
|
||||
|
||||
// job to update the key state
|
||||
void updateKeysCB(void*);
|
||||
|
||||
// determine whether the mouse is hidden by the system and force
|
||||
// it to be displayed if user has entered this secondary screen.
|
||||
void forceShowCursor();
|
||||
|
||||
// forceShowCursor uses MouseKeys to show the cursor. since we
|
||||
// don't actually want MouseKeys behavior we have to make sure
|
||||
// it applies when NumLock is in whatever state it's not in now.
|
||||
// this method does that.
|
||||
void updateForceShowCursor();
|
||||
|
||||
// our window proc
|
||||
static LRESULT CALLBACK wndProc(HWND, UINT, WPARAM, LPARAM);
|
||||
|
||||
private:
|
||||
struct CHotKeyItem {
|
||||
public:
|
||||
CHotKeyItem(UINT vk, UINT modifiers);
|
||||
|
||||
UINT getVirtualKey() const;
|
||||
|
||||
bool operator<(const CHotKeyItem&) const;
|
||||
|
||||
private:
|
||||
UINT m_keycode;
|
||||
UINT m_mask;
|
||||
};
|
||||
typedef std::map<UInt32, CHotKeyItem> HotKeyMap;
|
||||
typedef std::vector<UInt32> HotKeyIDList;
|
||||
typedef std::map<CHotKeyItem, UInt32> HotKeyToIDMap;
|
||||
|
||||
static HINSTANCE s_instance;
|
||||
|
||||
// true if screen is being used as a primary screen, false otherwise
|
||||
bool m_isPrimary;
|
||||
|
||||
// true if windows 95/98/me
|
||||
bool m_is95Family;
|
||||
|
||||
// true if mouse has entered the screen
|
||||
bool m_isOnScreen;
|
||||
|
||||
// our resources
|
||||
ATOM m_class;
|
||||
|
||||
// screen shape stuff
|
||||
SInt32 m_x, m_y;
|
||||
SInt32 m_w, m_h;
|
||||
SInt32 m_xCenter, m_yCenter;
|
||||
|
||||
// true if system appears to have multiple monitors
|
||||
bool m_multimon;
|
||||
|
||||
// last mouse position
|
||||
SInt32 m_xCursor, m_yCursor;
|
||||
|
||||
// last clipboard
|
||||
UInt32 m_sequenceNumber;
|
||||
|
||||
// used to discard queued messages that are no longer needed
|
||||
UInt32 m_mark;
|
||||
UInt32 m_markReceived;
|
||||
|
||||
// the main loop's thread id
|
||||
DWORD m_threadID;
|
||||
|
||||
// timer for periodically checking stuff that requires polling
|
||||
CEventQueueTimer* m_fixTimer;
|
||||
|
||||
// the keyboard layout to use when off primary screen
|
||||
HKL m_keyLayout;
|
||||
|
||||
// screen saver stuff
|
||||
CMSWindowsScreenSaver* m_screensaver;
|
||||
bool m_screensaverNotify;
|
||||
bool m_screensaverActive;
|
||||
|
||||
// clipboard stuff. our window is used mainly as a clipboard
|
||||
// owner and as a link in the clipboard viewer chain.
|
||||
HWND m_window;
|
||||
HWND m_nextClipboardWindow;
|
||||
bool m_ownClipboard;
|
||||
|
||||
// one desk per desktop and a cond var to communicate with it
|
||||
CMSWindowsDesks* m_desks;
|
||||
|
||||
// hook library stuff
|
||||
HINSTANCE m_hookLibrary;
|
||||
InitFunc m_init;
|
||||
CleanupFunc m_cleanup;
|
||||
SetSidesFunc m_setSides;
|
||||
SetZoneFunc m_setZone;
|
||||
SetModeFunc m_setMode;
|
||||
|
||||
// keyboard stuff
|
||||
CMSWindowsKeyState* m_keyState;
|
||||
|
||||
// hot key stuff
|
||||
HotKeyMap m_hotKeys;
|
||||
HotKeyIDList m_oldHotKeyIDs;
|
||||
HotKeyToIDMap m_hotKeyToIDMap;
|
||||
|
||||
// map of button state
|
||||
bool m_buttons[1 + kButtonExtra0 + 1];
|
||||
|
||||
// the system shows the mouse cursor when an internal display count
|
||||
// is >= 0. this count is maintained per application but there's
|
||||
// apparently a system wide count added to the application's count.
|
||||
// this system count is 0 if there's a mouse attached to the system
|
||||
// and -1 otherwise. the MouseKeys accessibility feature can modify
|
||||
// this system count by making the system appear to have a mouse.
|
||||
//
|
||||
// m_hasMouse is true iff there's a mouse attached to the system or
|
||||
// MouseKeys is simulating one. we track this so we can force the
|
||||
// cursor to be displayed when the user has entered this screen.
|
||||
// m_showingMouse is true when we're doing that.
|
||||
bool m_hasMouse;
|
||||
bool m_showingMouse;
|
||||
bool m_gotOldMouseKeys;
|
||||
MOUSEKEYS m_mouseKeys;
|
||||
MOUSEKEYS m_oldMouseKeys;
|
||||
|
||||
static CMSWindowsScreen* s_screen;
|
||||
};
|
||||
|
||||
#endif
|
||||
498
lib/platform/CMSWindowsScreenSaver.cpp
Normal file
498
lib/platform/CMSWindowsScreenSaver.cpp
Normal file
@@ -0,0 +1,498 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 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 "CMSWindowsScreenSaver.h"
|
||||
#include "CMSWindowsScreen.h"
|
||||
#include "CThread.h"
|
||||
#include "CLog.h"
|
||||
#include "TMethodJob.h"
|
||||
#include "CArch.h"
|
||||
#include "CArchMiscWindows.h"
|
||||
#include <malloc.h>
|
||||
#include <tchar.h>
|
||||
|
||||
#if !defined(SPI_GETSCREENSAVERRUNNING)
|
||||
#define SPI_GETSCREENSAVERRUNNING 114
|
||||
#endif
|
||||
|
||||
static const TCHAR* g_isSecureNT = "ScreenSaverIsSecure";
|
||||
static const TCHAR* g_isSecure9x = "ScreenSaveUsePassword";
|
||||
static const TCHAR* const g_pathScreenSaverIsSecure[] = {
|
||||
"Control Panel",
|
||||
"Desktop",
|
||||
NULL
|
||||
};
|
||||
|
||||
//
|
||||
// CMSWindowsScreenSaver
|
||||
//
|
||||
|
||||
CMSWindowsScreenSaver::CMSWindowsScreenSaver() :
|
||||
m_wasSecure(false),
|
||||
m_wasSecureAnInt(false),
|
||||
m_process(NULL),
|
||||
m_watch(NULL),
|
||||
m_threadID(0),
|
||||
m_active(false)
|
||||
{
|
||||
// detect OS
|
||||
m_is95Family = false;
|
||||
m_is95 = false;
|
||||
m_isNT = false;
|
||||
OSVERSIONINFO info;
|
||||
info.dwOSVersionInfoSize = sizeof(info);
|
||||
if (GetVersionEx(&info)) {
|
||||
m_is95Family = (info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
|
||||
if (info.dwPlatformId == VER_PLATFORM_WIN32_NT &&
|
||||
info.dwMajorVersion <= 4) {
|
||||
m_isNT = true;
|
||||
}
|
||||
else if (info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS &&
|
||||
info.dwMajorVersion == 4 &&
|
||||
info.dwMinorVersion == 0) {
|
||||
m_is95 = true;
|
||||
}
|
||||
}
|
||||
|
||||
// check if screen saver is enabled
|
||||
SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &m_wasEnabled, 0);
|
||||
}
|
||||
|
||||
CMSWindowsScreenSaver::~CMSWindowsScreenSaver()
|
||||
{
|
||||
unwatchProcess();
|
||||
}
|
||||
|
||||
bool
|
||||
CMSWindowsScreenSaver::checkStarted(UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
// if already started then say it didn't just start
|
||||
if (m_active) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// screen saver may have started. look for it and get
|
||||
// the process. if we can't find it then assume it
|
||||
// didn't really start. we wait a moment before
|
||||
// looking to give the screen saver a chance to start.
|
||||
// this shouldn't be a problem since we only get here
|
||||
// if the screen saver wants to kick in, meaning that
|
||||
// the system is idle or the user deliberately started
|
||||
// the screen saver.
|
||||
Sleep(250);
|
||||
|
||||
// set parameters common to all screen saver handling
|
||||
m_threadID = GetCurrentThreadId();
|
||||
m_msg = msg;
|
||||
m_wParam = wParam;
|
||||
m_lParam = lParam;
|
||||
|
||||
// we handle the screen saver differently for the windows
|
||||
// 95 and nt families.
|
||||
if (m_is95Family) {
|
||||
// on windows 95 we wait for the screen saver process
|
||||
// to terminate. get the process.
|
||||
DWORD processID = findScreenSaver();
|
||||
HANDLE process = OpenProcess(SYNCHRONIZE, FALSE, processID);
|
||||
if (process == NULL) {
|
||||
// didn't start
|
||||
LOG((CLOG_DEBUG2 "can't open screen saver process"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// watch for the process to exit
|
||||
watchProcess(process);
|
||||
}
|
||||
else {
|
||||
// on the windows nt family we wait for the desktop to
|
||||
// change until it's neither the Screen-Saver desktop
|
||||
// nor a desktop we can't open (the login desktop).
|
||||
// since windows will send the request-to-start-screen-
|
||||
// saver message even when the screen saver is disabled
|
||||
// we first check that the screen saver is indeed active
|
||||
// before watching for it to stop.
|
||||
if (!isActive()) {
|
||||
LOG((CLOG_DEBUG2 "can't open screen saver desktop"));
|
||||
return false;
|
||||
}
|
||||
|
||||
watchDesktop();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsScreenSaver::enable()
|
||||
{
|
||||
SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, m_wasEnabled, 0, 0);
|
||||
|
||||
// restore password protection
|
||||
if (m_wasSecure) {
|
||||
setSecure(true, m_wasSecureAnInt);
|
||||
}
|
||||
|
||||
// restore display power down
|
||||
CArchMiscWindows::removeBusyState(CArchMiscWindows::kDISPLAY);
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsScreenSaver::disable()
|
||||
{
|
||||
SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &m_wasEnabled, 0);
|
||||
SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, FALSE, 0, 0);
|
||||
|
||||
// disable password protected screensaver
|
||||
m_wasSecure = isSecure(&m_wasSecureAnInt);
|
||||
if (m_wasSecure) {
|
||||
setSecure(false, m_wasSecureAnInt);
|
||||
}
|
||||
|
||||
// disable display power down
|
||||
CArchMiscWindows::addBusyState(CArchMiscWindows::kDISPLAY);
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsScreenSaver::activate()
|
||||
{
|
||||
// don't activate if already active
|
||||
if (!isActive()) {
|
||||
// activate
|
||||
HWND hwnd = GetForegroundWindow();
|
||||
if (hwnd != NULL) {
|
||||
PostMessage(hwnd, WM_SYSCOMMAND, SC_SCREENSAVE, 0);
|
||||
}
|
||||
else {
|
||||
// no foreground window. pretend we got the event instead.
|
||||
DefWindowProc(NULL, WM_SYSCOMMAND, SC_SCREENSAVE, 0);
|
||||
}
|
||||
|
||||
// restore power save when screen saver activates
|
||||
CArchMiscWindows::removeBusyState(CArchMiscWindows::kDISPLAY);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsScreenSaver::deactivate()
|
||||
{
|
||||
bool killed = false;
|
||||
if (!m_is95Family) {
|
||||
// NT runs screen saver in another desktop
|
||||
HDESK desktop = OpenDesktop("Screen-saver", 0, FALSE,
|
||||
DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS);
|
||||
if (desktop != NULL) {
|
||||
EnumDesktopWindows(desktop,
|
||||
&CMSWindowsScreenSaver::killScreenSaverFunc,
|
||||
reinterpret_cast<LPARAM>(&killed));
|
||||
CloseDesktop(desktop);
|
||||
}
|
||||
}
|
||||
|
||||
// if above failed or wasn't tried, try the windows 95 way
|
||||
if (!killed) {
|
||||
// find screen saver window and close it
|
||||
HWND hwnd = FindWindow("WindowsScreenSaverClass", NULL);
|
||||
if (hwnd == NULL) {
|
||||
// win2k may use a different class
|
||||
hwnd = FindWindow("Default Screen Saver", NULL);
|
||||
}
|
||||
if (hwnd != NULL) {
|
||||
PostMessage(hwnd, WM_CLOSE, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// force timer to restart
|
||||
SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &m_wasEnabled, 0);
|
||||
SystemParametersInfo(SPI_SETSCREENSAVEACTIVE,
|
||||
!m_wasEnabled, 0, SPIF_SENDWININICHANGE);
|
||||
SystemParametersInfo(SPI_SETSCREENSAVEACTIVE,
|
||||
m_wasEnabled, 0, SPIF_SENDWININICHANGE);
|
||||
|
||||
// disable display power down
|
||||
CArchMiscWindows::removeBusyState(CArchMiscWindows::kDISPLAY);
|
||||
}
|
||||
|
||||
bool
|
||||
CMSWindowsScreenSaver::isActive() const
|
||||
{
|
||||
if (m_is95) {
|
||||
return (FindWindow("WindowsScreenSaverClass", NULL) != NULL);
|
||||
}
|
||||
else if (m_isNT) {
|
||||
// screen saver runs on a separate desktop
|
||||
HDESK desktop = OpenDesktop("Screen-saver", 0, FALSE, MAXIMUM_ALLOWED);
|
||||
if (desktop == NULL && GetLastError() != ERROR_ACCESS_DENIED) {
|
||||
// desktop doesn't exist so screen saver is not running
|
||||
return false;
|
||||
}
|
||||
|
||||
// desktop exists. this should indicate that the screen saver
|
||||
// is running but an OS bug can cause a valid handle to be
|
||||
// returned even if the screen saver isn't running (Q230117).
|
||||
// we'll try to enumerate the windows on the desktop and, if
|
||||
// there are any, we assume the screen saver is running. (note
|
||||
// that if we don't have permission to enumerate then we'll
|
||||
// assume that the screen saver is not running.) that'd be
|
||||
// easy enough except there's another OS bug (Q198590) that can
|
||||
// cause EnumDesktopWindows() to enumerate the windows of
|
||||
// another desktop if the requested desktop has no windows. to
|
||||
// work around that we have to verify that the enumerated
|
||||
// windows are, in fact, on the expected desktop.
|
||||
CFindScreenSaverInfo info;
|
||||
info.m_desktop = desktop;
|
||||
info.m_window = NULL;
|
||||
EnumDesktopWindows(desktop,
|
||||
&CMSWindowsScreenSaver::findScreenSaverFunc,
|
||||
reinterpret_cast<LPARAM>(&info));
|
||||
|
||||
// done with desktop
|
||||
CloseDesktop(desktop);
|
||||
|
||||
// screen saver is running if a window was found
|
||||
return (info.m_window != NULL);
|
||||
}
|
||||
else {
|
||||
BOOL running;
|
||||
SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, &running, 0);
|
||||
return (running != FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL CALLBACK
|
||||
CMSWindowsScreenSaver::findScreenSaverFunc(HWND hwnd, LPARAM arg)
|
||||
{
|
||||
CFindScreenSaverInfo* info = reinterpret_cast<CFindScreenSaverInfo*>(arg);
|
||||
|
||||
if (info->m_desktop != NULL) {
|
||||
DWORD threadID = GetWindowThreadProcessId(hwnd, NULL);
|
||||
HDESK desktop = GetThreadDesktop(threadID);
|
||||
if (desktop != NULL && desktop != info->m_desktop) {
|
||||
// stop enumerating -- wrong desktop
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// found a window
|
||||
info->m_window = hwnd;
|
||||
|
||||
// don't need to enumerate further
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL CALLBACK
|
||||
CMSWindowsScreenSaver::killScreenSaverFunc(HWND hwnd, LPARAM arg)
|
||||
{
|
||||
if (IsWindowVisible(hwnd)) {
|
||||
HINSTANCE instance = (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE);
|
||||
if (instance != CMSWindowsScreen::getInstance()) {
|
||||
PostMessage(hwnd, WM_CLOSE, 0, 0);
|
||||
*reinterpret_cast<bool*>(arg) = true;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
DWORD
|
||||
CMSWindowsScreenSaver::findScreenSaver()
|
||||
{
|
||||
// try windows 95 way
|
||||
HWND hwnd = FindWindow("WindowsScreenSaverClass", NULL);
|
||||
|
||||
// get process ID of process that owns the window, if found
|
||||
if (hwnd != NULL) {
|
||||
DWORD processID;
|
||||
GetWindowThreadProcessId(hwnd, &processID);
|
||||
return processID;
|
||||
}
|
||||
|
||||
// not found
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsScreenSaver::watchDesktop()
|
||||
{
|
||||
// stop watching previous process/desktop
|
||||
unwatchProcess();
|
||||
|
||||
// watch desktop in another thread
|
||||
LOG((CLOG_DEBUG "watching screen saver desktop"));
|
||||
m_active = true;
|
||||
m_watch = new CThread(new TMethodJob<CMSWindowsScreenSaver>(this,
|
||||
&CMSWindowsScreenSaver::watchDesktopThread));
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsScreenSaver::watchProcess(HANDLE process)
|
||||
{
|
||||
// stop watching previous process/desktop
|
||||
unwatchProcess();
|
||||
|
||||
// watch new process in another thread
|
||||
if (process != NULL) {
|
||||
LOG((CLOG_DEBUG "watching screen saver process"));
|
||||
m_process = process;
|
||||
m_active = true;
|
||||
m_watch = new CThread(new TMethodJob<CMSWindowsScreenSaver>(this,
|
||||
&CMSWindowsScreenSaver::watchProcessThread));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsScreenSaver::unwatchProcess()
|
||||
{
|
||||
if (m_watch != NULL) {
|
||||
LOG((CLOG_DEBUG "stopped watching screen saver process/desktop"));
|
||||
m_watch->cancel();
|
||||
m_watch->wait();
|
||||
delete m_watch;
|
||||
m_watch = NULL;
|
||||
m_active = false;
|
||||
}
|
||||
if (m_process != NULL) {
|
||||
CloseHandle(m_process);
|
||||
m_process = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsScreenSaver::watchDesktopThread(void*)
|
||||
{
|
||||
DWORD reserved = 0;
|
||||
TCHAR* name = NULL;
|
||||
|
||||
for (;;) {
|
||||
// wait a bit
|
||||
ARCH->sleep(0.2);
|
||||
|
||||
if (m_isNT) {
|
||||
// get current desktop
|
||||
HDESK desk = OpenInputDesktop(0, FALSE, GENERIC_READ);
|
||||
if (desk == NULL) {
|
||||
// can't open desktop so keep waiting
|
||||
continue;
|
||||
}
|
||||
|
||||
// get current desktop name length
|
||||
DWORD size;
|
||||
GetUserObjectInformation(desk, UOI_NAME, NULL, 0, &size);
|
||||
|
||||
// allocate more space for the name, if necessary
|
||||
if (size > reserved) {
|
||||
reserved = size;
|
||||
name = (TCHAR*)alloca(reserved + sizeof(TCHAR));
|
||||
}
|
||||
|
||||
// get current desktop name
|
||||
GetUserObjectInformation(desk, UOI_NAME, name, size, &size);
|
||||
CloseDesktop(desk);
|
||||
|
||||
// compare name to screen saver desktop name
|
||||
if (_tcsicmp(name, TEXT("Screen-saver")) == 0) {
|
||||
// still the screen saver desktop so keep waiting
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// 2000/XP have a sane way to detect a runnin screensaver.
|
||||
BOOL running;
|
||||
SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, &running, 0);
|
||||
if (running) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// send screen saver deactivation message
|
||||
m_active = false;
|
||||
PostThreadMessage(m_threadID, m_msg, m_wParam, m_lParam);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsScreenSaver::watchProcessThread(void*)
|
||||
{
|
||||
for (;;) {
|
||||
CThread::testCancel();
|
||||
if (WaitForSingleObject(m_process, 50) == WAIT_OBJECT_0) {
|
||||
// process terminated
|
||||
LOG((CLOG_DEBUG "screen saver died"));
|
||||
|
||||
// send screen saver deactivation message
|
||||
m_active = false;
|
||||
PostThreadMessage(m_threadID, m_msg, m_wParam, m_lParam);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsScreenSaver::setSecure(bool secure, bool saveSecureAsInt)
|
||||
{
|
||||
HKEY hkey =
|
||||
CArchMiscWindows::addKey(HKEY_CURRENT_USER, g_pathScreenSaverIsSecure);
|
||||
if (hkey == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
const TCHAR* isSecure = m_is95Family ? g_isSecure9x : g_isSecureNT;
|
||||
if (saveSecureAsInt) {
|
||||
CArchMiscWindows::setValue(hkey, isSecure, secure ? 1 : 0);
|
||||
}
|
||||
else {
|
||||
CArchMiscWindows::setValue(hkey, isSecure, secure ? "1" : "0");
|
||||
}
|
||||
|
||||
CArchMiscWindows::closeKey(hkey);
|
||||
}
|
||||
|
||||
bool
|
||||
CMSWindowsScreenSaver::isSecure(bool* wasSecureFlagAnInt) const
|
||||
{
|
||||
// get the password protection setting key
|
||||
HKEY hkey =
|
||||
CArchMiscWindows::openKey(HKEY_CURRENT_USER, g_pathScreenSaverIsSecure);
|
||||
if (hkey == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// get the value. the value may be an int or a string, depending
|
||||
// on the version of windows.
|
||||
bool result;
|
||||
const TCHAR* isSecure = m_is95Family ? g_isSecure9x : g_isSecureNT;
|
||||
switch (CArchMiscWindows::typeOfValue(hkey, isSecure)) {
|
||||
default:
|
||||
result = false;
|
||||
break;
|
||||
|
||||
case CArchMiscWindows::kUINT: {
|
||||
DWORD value =
|
||||
CArchMiscWindows::readValueInt(hkey, isSecure);
|
||||
*wasSecureFlagAnInt = true;
|
||||
result = (value != 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case CArchMiscWindows::kSTRING: {
|
||||
std::string value =
|
||||
CArchMiscWindows::readValueString(hkey, isSecure);
|
||||
*wasSecureFlagAnInt = false;
|
||||
result = (value != "0");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CArchMiscWindows::closeKey(hkey);
|
||||
return result;
|
||||
}
|
||||
92
lib/platform/CMSWindowsScreenSaver.h
Normal file
92
lib/platform/CMSWindowsScreenSaver.h
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 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.
|
||||
*/
|
||||
|
||||
#ifndef CMSWINDOWSSCREENSAVER_H
|
||||
#define CMSWINDOWSSCREENSAVER_H
|
||||
|
||||
#include "IScreenSaver.h"
|
||||
#include "CString.h"
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
class CThread;
|
||||
|
||||
//! Microsoft windows screen saver implementation
|
||||
class CMSWindowsScreenSaver : public IScreenSaver {
|
||||
public:
|
||||
CMSWindowsScreenSaver();
|
||||
virtual ~CMSWindowsScreenSaver();
|
||||
|
||||
//! @name manipulators
|
||||
//@{
|
||||
|
||||
//! Check if screen saver started
|
||||
/*!
|
||||
Check if the screen saver really started. Returns false if it
|
||||
hasn't, true otherwise. When the screen saver stops, \c msg will
|
||||
be posted to the current thread's message queue with the given
|
||||
parameters.
|
||||
*/
|
||||
bool checkStarted(UINT msg, WPARAM, LPARAM);
|
||||
|
||||
//@}
|
||||
|
||||
// IScreenSaver overrides
|
||||
virtual void enable();
|
||||
virtual void disable();
|
||||
virtual void activate();
|
||||
virtual void deactivate();
|
||||
virtual bool isActive() const;
|
||||
|
||||
private:
|
||||
class CFindScreenSaverInfo {
|
||||
public:
|
||||
HDESK m_desktop;
|
||||
HWND m_window;
|
||||
};
|
||||
|
||||
static BOOL CALLBACK findScreenSaverFunc(HWND hwnd, LPARAM lParam);
|
||||
static BOOL CALLBACK killScreenSaverFunc(HWND hwnd, LPARAM lParam);
|
||||
|
||||
DWORD findScreenSaver();
|
||||
void watchDesktop();
|
||||
void watchProcess(HANDLE process);
|
||||
void unwatchProcess();
|
||||
void watchDesktopThread(void*);
|
||||
void watchProcessThread(void*);
|
||||
|
||||
void setSecure(bool secure, bool saveSecureAsInt);
|
||||
bool isSecure(bool* wasSecureAnInt) const;
|
||||
|
||||
private:
|
||||
bool m_is95Family;
|
||||
bool m_is95;
|
||||
bool m_isNT;
|
||||
BOOL m_wasEnabled;
|
||||
bool m_wasSecure;
|
||||
bool m_wasSecureAnInt;
|
||||
|
||||
HANDLE m_process;
|
||||
CThread* m_watch;
|
||||
DWORD m_threadID;
|
||||
UINT m_msg;
|
||||
WPARAM m_wParam;
|
||||
LPARAM m_lParam;
|
||||
|
||||
// checkActive state. true if the screen saver is being watched
|
||||
// for deactivation (and is therefore active).
|
||||
bool m_active;
|
||||
};
|
||||
|
||||
#endif
|
||||
75
lib/platform/CMSWindowsUtil.cpp
Normal file
75
lib/platform/CMSWindowsUtil.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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 "CMSWindowsUtil.h"
|
||||
#include "CStringUtil.h"
|
||||
#include <stdio.h>
|
||||
|
||||
//
|
||||
// CMSWindowsUtil
|
||||
//
|
||||
|
||||
CString
|
||||
CMSWindowsUtil::getString(HINSTANCE instance, DWORD id)
|
||||
{
|
||||
char buffer[1024];
|
||||
int size = static_cast<int>(sizeof(buffer) / sizeof(buffer[0]));
|
||||
char* msg = buffer;
|
||||
|
||||
// load string
|
||||
int n = LoadString(instance, id, msg, size);
|
||||
msg[n] = '\0';
|
||||
if (n < size) {
|
||||
return msg;
|
||||
}
|
||||
|
||||
// not enough buffer space. keep trying larger buffers until
|
||||
// we get the whole string.
|
||||
msg = NULL;
|
||||
do {
|
||||
size <<= 1;
|
||||
delete[] msg;
|
||||
char* msg = new char[size];
|
||||
n = LoadString(instance, id, msg, size);
|
||||
} while (n == size);
|
||||
msg[n] = '\0';
|
||||
|
||||
CString result(msg);
|
||||
delete[] msg;
|
||||
return result;
|
||||
}
|
||||
|
||||
CString
|
||||
CMSWindowsUtil::getErrorString(HINSTANCE hinstance, DWORD error, DWORD id)
|
||||
{
|
||||
char* buffer;
|
||||
if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
0,
|
||||
error,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR)&buffer,
|
||||
0,
|
||||
NULL) == 0) {
|
||||
CString errorString = CStringUtil::print("%d", error);
|
||||
return CStringUtil::format(getString(hinstance, id).c_str(),
|
||||
errorString.c_str());
|
||||
}
|
||||
else {
|
||||
CString result(buffer);
|
||||
LocalFree(buffer);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
38
lib/platform/CMSWindowsUtil.h
Normal file
38
lib/platform/CMSWindowsUtil.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef CMSWINDOWSUTIL_H
|
||||
#define CMSWINDOWSUTIL_H
|
||||
|
||||
#include "CString.h"
|
||||
#define WINDOWS_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
class CMSWindowsUtil {
|
||||
public:
|
||||
//! Get message string
|
||||
/*!
|
||||
Gets a string for \p id from the string table of \p instance.
|
||||
*/
|
||||
static CString getString(HINSTANCE instance, DWORD id);
|
||||
|
||||
//! Get error string
|
||||
/*!
|
||||
Gets a system error message for \p error. If the error cannot be
|
||||
found return the string for \p id, replacing ${1} with \p error.
|
||||
*/
|
||||
static CString getErrorString(HINSTANCE, DWORD error, DWORD id);
|
||||
};
|
||||
|
||||
#endif
|
||||
220
lib/platform/COSXClipboard.cpp
Normal file
220
lib/platform/COSXClipboard.cpp
Normal file
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* 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 "COSXClipboard.h"
|
||||
#include "COSXClipboardUTF16Converter.h"
|
||||
#include "COSXClipboardTextConverter.h"
|
||||
#include "CLog.h"
|
||||
#include "XArch.h"
|
||||
|
||||
//
|
||||
// COSXClipboard
|
||||
//
|
||||
|
||||
COSXClipboard::COSXClipboard() :
|
||||
m_time(0),
|
||||
m_scrap(NULL)
|
||||
{
|
||||
m_converters.push_back(new COSXClipboardUTF16Converter);
|
||||
m_converters.push_back(new COSXClipboardTextConverter);
|
||||
}
|
||||
|
||||
COSXClipboard::~COSXClipboard()
|
||||
{
|
||||
clearConverters();
|
||||
}
|
||||
|
||||
bool
|
||||
COSXClipboard::empty()
|
||||
{
|
||||
LOG((CLOG_DEBUG "empty clipboard"));
|
||||
assert(m_scrap != NULL);
|
||||
|
||||
OSStatus err = ClearScrap(&m_scrap);
|
||||
if (err != noErr) {
|
||||
LOG((CLOG_DEBUG "failed to grab clipboard"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// we own the clipboard
|
||||
err = PutScrapFlavor(
|
||||
m_scrap,
|
||||
getOwnershipFlavor(),
|
||||
kScrapFlavorMaskNone,
|
||||
0,
|
||||
0);
|
||||
if (err != noErr) {
|
||||
LOG((CLOG_DEBUG "failed to grab clipboard"));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
COSXClipboard::add(EFormat format, const CString & data)
|
||||
{
|
||||
LOG((CLOG_DEBUG "add %d bytes to clipboard format: %d", data.size(), format));
|
||||
|
||||
for (ConverterList::const_iterator index = m_converters.begin();
|
||||
index != m_converters.end(); ++index) {
|
||||
|
||||
IOSXClipboardConverter* converter = *index;
|
||||
|
||||
// skip converters for other formats
|
||||
if (converter->getFormat() == format) {
|
||||
CString osXData = converter->fromIClipboard(data);
|
||||
ScrapFlavorType flavorType = converter->getOSXFormat();
|
||||
|
||||
PutScrapFlavor(
|
||||
m_scrap,
|
||||
flavorType,
|
||||
kScrapFlavorMaskNone,
|
||||
osXData.size(),
|
||||
osXData.data());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
COSXClipboard::open(Time time) const
|
||||
{
|
||||
LOG((CLOG_DEBUG "open clipboard"));
|
||||
m_time = time;
|
||||
OSStatus err = GetCurrentScrap(&m_scrap);
|
||||
return (err == noErr);
|
||||
}
|
||||
|
||||
void
|
||||
COSXClipboard::close() const
|
||||
{
|
||||
LOG((CLOG_DEBUG "close clipboard"));
|
||||
m_scrap = NULL;
|
||||
}
|
||||
|
||||
IClipboard::Time
|
||||
COSXClipboard::getTime() const
|
||||
{
|
||||
return m_time;
|
||||
}
|
||||
|
||||
bool
|
||||
COSXClipboard::has(EFormat format) const
|
||||
{
|
||||
assert(m_scrap != NULL);
|
||||
|
||||
for (ConverterList::const_iterator index = m_converters.begin();
|
||||
index != m_converters.end(); ++index) {
|
||||
IOSXClipboardConverter* converter = *index;
|
||||
if (converter->getFormat() == format) {
|
||||
ScrapFlavorFlags flags;
|
||||
ScrapFlavorType type = converter->getOSXFormat();
|
||||
|
||||
if (GetScrapFlavorFlags(m_scrap, type, &flags) == noErr) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
CString
|
||||
COSXClipboard::get(EFormat format) const
|
||||
{
|
||||
CString result;
|
||||
|
||||
// find the converter for the first clipboard format we can handle
|
||||
IOSXClipboardConverter* converter = NULL;
|
||||
for (ConverterList::const_iterator index = m_converters.begin();
|
||||
index != m_converters.end(); ++index) {
|
||||
converter = *index;
|
||||
|
||||
ScrapFlavorFlags flags;
|
||||
ScrapFlavorType type = converter->getOSXFormat();
|
||||
|
||||
if (converter->getFormat() == format &&
|
||||
GetScrapFlavorFlags(m_scrap, type, &flags) == noErr) {
|
||||
break;
|
||||
}
|
||||
converter = NULL;
|
||||
}
|
||||
|
||||
// if no converter then we don't recognize any formats
|
||||
if (converter == NULL) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// get the clipboard data.
|
||||
char* buffer = NULL;
|
||||
try {
|
||||
Size flavorSize;
|
||||
OSStatus err = GetScrapFlavorSize(m_scrap,
|
||||
converter->getOSXFormat(), &flavorSize);
|
||||
if (err != noErr) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
buffer = new char[flavorSize];
|
||||
if (buffer == NULL) {
|
||||
throw memFullErr;
|
||||
}
|
||||
|
||||
err = GetScrapFlavorData(m_scrap,
|
||||
converter->getOSXFormat(), &flavorSize, buffer);
|
||||
if (err != noErr) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
result = CString(buffer, flavorSize);
|
||||
}
|
||||
catch (OSStatus err) {
|
||||
LOG((CLOG_DEBUG "exception thrown in COSXClipboard::get MacError (%d)", err));
|
||||
}
|
||||
catch (...) {
|
||||
LOG((CLOG_DEBUG "unknown exception in COSXClipboard::get"));
|
||||
RETHROW_XTHREAD
|
||||
}
|
||||
delete[] buffer;
|
||||
|
||||
return converter->toIClipboard(result);
|
||||
}
|
||||
|
||||
void
|
||||
COSXClipboard::clearConverters()
|
||||
{
|
||||
for (ConverterList::iterator index = m_converters.begin();
|
||||
index != m_converters.end(); ++index) {
|
||||
delete *index;
|
||||
}
|
||||
m_converters.clear();
|
||||
}
|
||||
|
||||
bool
|
||||
COSXClipboard::isOwnedBySynergy()
|
||||
{
|
||||
ScrapFlavorFlags flags;
|
||||
ScrapRef scrap;
|
||||
OSStatus err = GetCurrentScrap(&scrap);
|
||||
if (err == noErr) {
|
||||
err = GetScrapFlavorFlags(scrap, getOwnershipFlavor() , &flags);
|
||||
}
|
||||
return (err == noErr);
|
||||
}
|
||||
|
||||
ScrapFlavorType
|
||||
COSXClipboard::getOwnershipFlavor()
|
||||
{
|
||||
return 'Syne';
|
||||
}
|
||||
94
lib/platform/COSXClipboard.h
Normal file
94
lib/platform/COSXClipboard.h
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef COSXCLIPBOARD_H
|
||||
#define COSXCLIPBOARD_H
|
||||
|
||||
#include "IClipboard.h"
|
||||
#include <vector>
|
||||
#include <Carbon/Carbon.h>
|
||||
|
||||
class IOSXClipboardConverter;
|
||||
|
||||
//! OS X clipboard implementation
|
||||
class COSXClipboard : public IClipboard {
|
||||
public:
|
||||
COSXClipboard();
|
||||
virtual ~COSXClipboard();
|
||||
|
||||
//! Test if clipboard is owned by synergy
|
||||
static bool isOwnedBySynergy();
|
||||
|
||||
// IClipboard overrides
|
||||
virtual bool empty();
|
||||
virtual void add(EFormat, const CString& data);
|
||||
virtual bool open(Time) const;
|
||||
virtual void close() const;
|
||||
virtual Time getTime() const;
|
||||
virtual bool has(EFormat) const;
|
||||
virtual CString get(EFormat) const;
|
||||
|
||||
private:
|
||||
void clearConverters();
|
||||
static ScrapFlavorType
|
||||
getOwnershipFlavor();
|
||||
|
||||
private:
|
||||
typedef std::vector<IOSXClipboardConverter*> ConverterList;
|
||||
|
||||
mutable Time m_time;
|
||||
ConverterList m_converters;
|
||||
mutable ScrapRef m_scrap;
|
||||
};
|
||||
|
||||
//! Clipboard format converter interface
|
||||
/*!
|
||||
This interface defines the methods common to all Scrap book format
|
||||
*/
|
||||
class IOSXClipboardConverter : public IInterface {
|
||||
public:
|
||||
//! @name accessors
|
||||
//@{
|
||||
|
||||
//! Get clipboard format
|
||||
/*!
|
||||
Return the clipboard format this object converts from/to.
|
||||
*/
|
||||
virtual IClipboard::EFormat
|
||||
getFormat() const = 0;
|
||||
|
||||
//! returns the scrap flavor type that this object converts from/to
|
||||
virtual ScrapFlavorType
|
||||
getOSXFormat() const = 0;
|
||||
|
||||
//! Convert from IClipboard format
|
||||
/*!
|
||||
Convert from the IClipboard format to the Carbon scrap format.
|
||||
The input data must be in the IClipboard format returned by
|
||||
getFormat(). The return data will be in the scrap
|
||||
format returned by getOSXFormat().
|
||||
*/
|
||||
virtual CString fromIClipboard(const CString&) const = 0;
|
||||
|
||||
//! Convert to IClipboard format
|
||||
/*!
|
||||
Convert from the carbon scrap format to the IClipboard format
|
||||
(i.e., the reverse of fromIClipboard()).
|
||||
*/
|
||||
virtual CString toIClipboard(const CString&) const = 0;
|
||||
|
||||
//@}
|
||||
};
|
||||
|
||||
#endif
|
||||
85
lib/platform/COSXClipboardAnyTextConverter.cpp
Normal file
85
lib/platform/COSXClipboardAnyTextConverter.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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 "COSXClipboardAnyTextConverter.h"
|
||||
#include <algorithm>
|
||||
|
||||
//
|
||||
// COSXClipboardAnyTextConverter
|
||||
//
|
||||
|
||||
COSXClipboardAnyTextConverter::COSXClipboardAnyTextConverter()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
COSXClipboardAnyTextConverter::~COSXClipboardAnyTextConverter()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
IClipboard::EFormat
|
||||
COSXClipboardAnyTextConverter::getFormat() const
|
||||
{
|
||||
return IClipboard::kText;
|
||||
}
|
||||
|
||||
CString
|
||||
COSXClipboardAnyTextConverter::fromIClipboard(const CString& data) const
|
||||
{
|
||||
// convert linefeeds and then convert to desired encoding
|
||||
return doFromIClipboard(convertLinefeedToMacOS(data));
|
||||
}
|
||||
|
||||
CString
|
||||
COSXClipboardAnyTextConverter::toIClipboard(const CString& data) const
|
||||
{
|
||||
// convert text then newlines
|
||||
return convertLinefeedToUnix(doToIClipboard(data));
|
||||
}
|
||||
|
||||
static
|
||||
bool
|
||||
isLF(char ch)
|
||||
{
|
||||
return (ch == '\n');
|
||||
}
|
||||
|
||||
static
|
||||
bool
|
||||
isCR(char ch)
|
||||
{
|
||||
return (ch == '\r');
|
||||
}
|
||||
|
||||
CString
|
||||
COSXClipboardAnyTextConverter::convertLinefeedToMacOS(const CString& src)
|
||||
{
|
||||
// note -- we assume src is a valid UTF-8 string
|
||||
CString copy = src;
|
||||
|
||||
std::replace_if(copy.begin(), copy.end(), isLF, '\r');
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
CString
|
||||
COSXClipboardAnyTextConverter::convertLinefeedToUnix(const CString& src)
|
||||
{
|
||||
CString copy = src;
|
||||
|
||||
std::replace_if(copy.begin(), copy.end(), isCR, '\n');
|
||||
|
||||
return copy;
|
||||
}
|
||||
52
lib/platform/COSXClipboardAnyTextConverter.h
Normal file
52
lib/platform/COSXClipboardAnyTextConverter.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef COSXCLIPBOARDANYTEXTCONVERTER_H
|
||||
#define COSXCLIPBOARDANYTEXTCONVERTER_H
|
||||
|
||||
#include "COSXClipboard.h"
|
||||
|
||||
//! Convert to/from some text encoding
|
||||
class COSXClipboardAnyTextConverter : public IOSXClipboardConverter {
|
||||
public:
|
||||
COSXClipboardAnyTextConverter();
|
||||
virtual ~COSXClipboardAnyTextConverter();
|
||||
|
||||
// IOSXClipboardConverter overrides
|
||||
virtual IClipboard::EFormat
|
||||
getFormat() const;
|
||||
virtual ScrapFlavorType
|
||||
getOSXFormat() const = 0;
|
||||
virtual CString fromIClipboard(const CString &) const;
|
||||
virtual CString toIClipboard(const CString &) const;
|
||||
|
||||
protected:
|
||||
//! Convert from IClipboard format
|
||||
/*!
|
||||
Do UTF-8 conversion and linefeed conversion.
|
||||
*/
|
||||
virtual CString doFromIClipboard(const CString&) const = 0;
|
||||
|
||||
//! Convert to IClipboard format
|
||||
/*!
|
||||
Do UTF-8 conversion and Linefeed conversion.
|
||||
*/
|
||||
virtual CString doToIClipboard(const CString&) const = 0;
|
||||
|
||||
private:
|
||||
static CString convertLinefeedToMacOS(const CString&);
|
||||
static CString convertLinefeedToUnix(const CString&);
|
||||
};
|
||||
|
||||
#endif
|
||||
88
lib/platform/COSXClipboardTextConverter.cpp
Normal file
88
lib/platform/COSXClipboardTextConverter.cpp
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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 "COSXClipboardTextConverter.h"
|
||||
#include "CUnicode.h"
|
||||
|
||||
//
|
||||
// COSXClipboardTextConverter
|
||||
//
|
||||
|
||||
COSXClipboardTextConverter::COSXClipboardTextConverter()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
COSXClipboardTextConverter::~COSXClipboardTextConverter()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
ScrapFlavorType
|
||||
COSXClipboardTextConverter::getOSXFormat() const
|
||||
{
|
||||
return kScrapFlavorTypeText;
|
||||
}
|
||||
|
||||
CString
|
||||
COSXClipboardTextConverter::convertString(
|
||||
const CString& data,
|
||||
CFStringEncoding fromEncoding,
|
||||
CFStringEncoding toEncoding)
|
||||
{
|
||||
CFStringRef stringRef =
|
||||
CFStringCreateWithCString(kCFAllocatorDefault,
|
||||
data.c_str(), fromEncoding);
|
||||
|
||||
if (stringRef == NULL) {
|
||||
return CString();
|
||||
}
|
||||
|
||||
CFIndex buffSize;
|
||||
CFRange entireString = CFRangeMake(0, CFStringGetLength(stringRef));
|
||||
|
||||
CFStringGetBytes(stringRef, entireString, toEncoding,
|
||||
0, false, NULL, 0, &buffSize);
|
||||
|
||||
char* buffer = new char[buffSize];
|
||||
|
||||
if (buffer == NULL) {
|
||||
CFRelease(stringRef);
|
||||
return CString();
|
||||
}
|
||||
|
||||
CFStringGetBytes(stringRef, entireString, toEncoding,
|
||||
0, false, (UInt8*)buffer, buffSize, NULL);
|
||||
|
||||
CString result(buffer, buffSize);
|
||||
|
||||
delete[] buffer;
|
||||
CFRelease(stringRef);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
CString
|
||||
COSXClipboardTextConverter::doFromIClipboard(const CString& data) const
|
||||
{
|
||||
return convertString(data, kCFStringEncodingUTF8,
|
||||
CFStringGetSystemEncoding());
|
||||
}
|
||||
|
||||
CString
|
||||
COSXClipboardTextConverter::doToIClipboard(const CString& data) const
|
||||
{
|
||||
return convertString(data, CFStringGetSystemEncoding(),
|
||||
kCFStringEncodingUTF8);
|
||||
}
|
||||
41
lib/platform/COSXClipboardTextConverter.h
Normal file
41
lib/platform/COSXClipboardTextConverter.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef COSXCLIPBOARDTEXTCONVERTER_H
|
||||
#define COSXCLIPBOARDTEXTCONVERTER_H
|
||||
|
||||
#include "COSXClipboardAnyTextConverter.h"
|
||||
|
||||
//! Convert to/from locale text encoding
|
||||
class COSXClipboardTextConverter : public COSXClipboardAnyTextConverter {
|
||||
public:
|
||||
COSXClipboardTextConverter();
|
||||
virtual ~COSXClipboardTextConverter();
|
||||
|
||||
// IOSXClipboardAnyTextConverter overrides
|
||||
virtual ScrapFlavorType
|
||||
getOSXFormat() const;
|
||||
|
||||
protected:
|
||||
// COSXClipboardAnyTextConverter overrides
|
||||
virtual CString doFromIClipboard(const CString&) const;
|
||||
virtual CString doToIClipboard(const CString&) const;
|
||||
|
||||
// generic encoding converter
|
||||
static CString convertString(const CString& data,
|
||||
CFStringEncoding fromEncoding,
|
||||
CFStringEncoding toEncoding);
|
||||
};
|
||||
|
||||
#endif
|
||||
50
lib/platform/COSXClipboardUTF16Converter.cpp
Normal file
50
lib/platform/COSXClipboardUTF16Converter.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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 "COSXClipboardUTF16Converter.h"
|
||||
#include "CUnicode.h"
|
||||
|
||||
//
|
||||
// COSXClipboardUTF16Converter
|
||||
//
|
||||
|
||||
COSXClipboardUTF16Converter::COSXClipboardUTF16Converter()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
COSXClipboardUTF16Converter::~COSXClipboardUTF16Converter()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
ScrapFlavorType
|
||||
COSXClipboardUTF16Converter::getOSXFormat() const
|
||||
{
|
||||
return kScrapFlavorTypeUnicode;
|
||||
}
|
||||
|
||||
CString
|
||||
COSXClipboardUTF16Converter::doFromIClipboard(const CString& data) const
|
||||
{
|
||||
// convert and add nul terminator
|
||||
return CUnicode::UTF8ToUTF16(data);
|
||||
}
|
||||
|
||||
CString
|
||||
COSXClipboardUTF16Converter::doToIClipboard(const CString& data) const
|
||||
{
|
||||
// convert and strip nul terminator
|
||||
return CUnicode::UTF16ToUTF8(data);
|
||||
}
|
||||
36
lib/platform/COSXClipboardUTF16Converter.h
Normal file
36
lib/platform/COSXClipboardUTF16Converter.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef COSXCLIPBOARDUTF16CONVERTER_H
|
||||
#define COSXCLIPBOARDUTF16CONVERTER_H
|
||||
|
||||
#include "COSXClipboardAnyTextConverter.h"
|
||||
|
||||
//! Convert to/from UTF-16 encoding
|
||||
class COSXClipboardUTF16Converter : public COSXClipboardAnyTextConverter {
|
||||
public:
|
||||
COSXClipboardUTF16Converter();
|
||||
virtual ~COSXClipboardUTF16Converter();
|
||||
|
||||
// IOSXClipboardAnyTextConverter overrides
|
||||
virtual ScrapFlavorType
|
||||
getOSXFormat() const;
|
||||
|
||||
protected:
|
||||
// COSXClipboardAnyTextConverter overrides
|
||||
virtual CString doFromIClipboard(const CString&) const;
|
||||
virtual CString doToIClipboard(const CString&) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
124
lib/platform/COSXEventQueueBuffer.cpp
Normal file
124
lib/platform/COSXEventQueueBuffer.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* 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 "COSXEventQueueBuffer.h"
|
||||
#include "CEvent.h"
|
||||
#include "IEventQueue.h"
|
||||
|
||||
//
|
||||
// CEventQueueTimer
|
||||
//
|
||||
|
||||
class CEventQueueTimer { };
|
||||
|
||||
//
|
||||
// COSXEventQueueBuffer
|
||||
//
|
||||
|
||||
COSXEventQueueBuffer::COSXEventQueueBuffer() :
|
||||
m_event(NULL)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
COSXEventQueueBuffer::~COSXEventQueueBuffer()
|
||||
{
|
||||
// release the last event
|
||||
if (m_event != NULL) {
|
||||
ReleaseEvent(m_event);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
COSXEventQueueBuffer::waitForEvent(double timeout)
|
||||
{
|
||||
EventRef event;
|
||||
ReceiveNextEvent(0, NULL, timeout, false, &event);
|
||||
}
|
||||
|
||||
IEventQueueBuffer::Type
|
||||
COSXEventQueueBuffer::getEvent(CEvent& event, UInt32& dataID)
|
||||
{
|
||||
// release the previous event
|
||||
if (m_event != NULL) {
|
||||
ReleaseEvent(m_event);
|
||||
m_event = NULL;
|
||||
}
|
||||
|
||||
// get the next event
|
||||
OSStatus error = ReceiveNextEvent(0, NULL, 0.0, true, &m_event);
|
||||
|
||||
// handle the event
|
||||
if (error == eventLoopQuitErr) {
|
||||
event = CEvent(CEvent::kQuit);
|
||||
return kSystem;
|
||||
}
|
||||
else if (error != noErr) {
|
||||
return kNone;
|
||||
}
|
||||
else {
|
||||
UInt32 eventClass = GetEventClass(m_event);
|
||||
switch (eventClass) {
|
||||
case 'Syne':
|
||||
dataID = GetEventKind(m_event);
|
||||
return kUser;
|
||||
|
||||
default:
|
||||
event = CEvent(CEvent::kSystem,
|
||||
IEventQueue::getSystemTarget(), &m_event);
|
||||
return kSystem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
COSXEventQueueBuffer::addEvent(UInt32 dataID)
|
||||
{
|
||||
EventRef event;
|
||||
OSStatus error = CreateEvent(
|
||||
kCFAllocatorDefault,
|
||||
'Syne',
|
||||
dataID,
|
||||
0,
|
||||
kEventAttributeNone,
|
||||
&event);
|
||||
|
||||
if (error == noErr) {
|
||||
error = PostEventToQueue(GetMainEventQueue(), event,
|
||||
kEventPriorityStandard);
|
||||
ReleaseEvent(event);
|
||||
}
|
||||
|
||||
return (error == noErr);
|
||||
}
|
||||
|
||||
bool
|
||||
COSXEventQueueBuffer::isEmpty() const
|
||||
{
|
||||
EventRef event;
|
||||
OSStatus status = ReceiveNextEvent(0, NULL, 0.0, false, &event);
|
||||
return (status == eventLoopTimedOutErr);
|
||||
}
|
||||
|
||||
CEventQueueTimer*
|
||||
COSXEventQueueBuffer::newTimer(double, bool) const
|
||||
{
|
||||
return new CEventQueueTimer;
|
||||
}
|
||||
|
||||
void
|
||||
COSXEventQueueBuffer::deleteTimer(CEventQueueTimer* timer) const
|
||||
{
|
||||
delete timer;
|
||||
}
|
||||
40
lib/platform/COSXEventQueueBuffer.h
Normal file
40
lib/platform/COSXEventQueueBuffer.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef COSXEVENTQUEUEBUFFER_H
|
||||
#define COSXEVENTQUEUEBUFFER_H
|
||||
|
||||
#include "IEventQueueBuffer.h"
|
||||
#include <Carbon/Carbon.h>
|
||||
|
||||
//! Event queue buffer for OS X
|
||||
class COSXEventQueueBuffer : public IEventQueueBuffer {
|
||||
public:
|
||||
COSXEventQueueBuffer();
|
||||
virtual ~COSXEventQueueBuffer();
|
||||
|
||||
// IEventQueueBuffer overrides
|
||||
virtual void waitForEvent(double timeout);
|
||||
virtual Type getEvent(CEvent& event, UInt32& dataID);
|
||||
virtual bool addEvent(UInt32 dataID);
|
||||
virtual bool isEmpty() const;
|
||||
virtual CEventQueueTimer*
|
||||
newTimer(double duration, bool oneShot) const;
|
||||
virtual void deleteTimer(CEventQueueTimer*) const;
|
||||
|
||||
private:
|
||||
EventRef m_event;
|
||||
};
|
||||
|
||||
#endif
|
||||
1237
lib/platform/COSXKeyState.cpp
Normal file
1237
lib/platform/COSXKeyState.cpp
Normal file
File diff suppressed because it is too large
Load Diff
235
lib/platform/COSXKeyState.h
Normal file
235
lib/platform/COSXKeyState.h
Normal file
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef COSXKEYSTATE_H
|
||||
#define COSXKEYSTATE_H
|
||||
|
||||
#include "CKeyState.h"
|
||||
#include "stdmap.h"
|
||||
#include "stdset.h"
|
||||
#include "stdvector.h"
|
||||
#include <Carbon/Carbon.h>
|
||||
|
||||
//! OS X key state
|
||||
/*!
|
||||
A key state for OS X.
|
||||
*/
|
||||
class COSXKeyState : public CKeyState {
|
||||
public:
|
||||
typedef std::vector<KeyID> CKeyIDs;
|
||||
|
||||
COSXKeyState();
|
||||
virtual ~COSXKeyState();
|
||||
|
||||
//! @name modifiers
|
||||
//@{
|
||||
|
||||
//! Handle modifier key change
|
||||
/*!
|
||||
Determines which modifier keys have changed and updates the modifier
|
||||
state and sends key events as appropriate.
|
||||
*/
|
||||
void handleModifierKeys(void* target,
|
||||
KeyModifierMask oldMask, KeyModifierMask newMask);
|
||||
|
||||
//@}
|
||||
//! @name accessors
|
||||
//@{
|
||||
|
||||
//! Convert OS X modifier mask to synergy mask
|
||||
/*!
|
||||
Returns the synergy modifier mask corresponding to the OS X modifier
|
||||
mask in \p mask.
|
||||
*/
|
||||
KeyModifierMask mapModifiersFromOSX(UInt32 mask) const;
|
||||
|
||||
//! Map key event to keys
|
||||
/*!
|
||||
Converts a key event into a sequence of KeyIDs and the shadow modifier
|
||||
state to a modifier mask. The KeyIDs list, in order, the characters
|
||||
generated by the key press/release. It returns the id of the button
|
||||
that was pressed or released, or 0 if the button doesn't map to a known
|
||||
KeyID.
|
||||
*/
|
||||
KeyButton mapKeyFromEvent(CKeyIDs& ids,
|
||||
KeyModifierMask* maskOut, EventRef event) const;
|
||||
|
||||
//! Map key and mask to native values
|
||||
/*!
|
||||
Calculates mac virtual key and mask for a key \p key and modifiers
|
||||
\p mask. Returns \c true if the key can be mapped, \c false otherwise.
|
||||
*/
|
||||
bool mapSynergyHotKeyToMac(KeyID key, KeyModifierMask mask,
|
||||
UInt32& macVirtualKey,
|
||||
UInt32& macModifierMask) const;
|
||||
|
||||
//@}
|
||||
|
||||
// IKeyState overrides
|
||||
virtual bool fakeCtrlAltDel();
|
||||
virtual KeyModifierMask
|
||||
pollActiveModifiers() const;
|
||||
virtual SInt32 pollActiveGroup() const;
|
||||
virtual void pollPressedKeys(KeyButtonSet& pressedKeys) const;
|
||||
|
||||
protected:
|
||||
// CKeyState overrides
|
||||
virtual void getKeyMap(CKeyMap& keyMap);
|
||||
virtual void fakeKey(const Keystroke& keystroke);
|
||||
|
||||
private:
|
||||
class CKeyResource;
|
||||
typedef std::vector<KeyboardLayoutRef> GroupList;
|
||||
|
||||
// Add hard coded special keys to a CKeyMap.
|
||||
void getKeyMapForSpecialKeys(
|
||||
CKeyMap& keyMap, SInt32 group) const;
|
||||
|
||||
// Convert keyboard resource to a key map
|
||||
bool getKeyMap(CKeyMap& keyMap,
|
||||
SInt32 group, const CKeyResource& r) const;
|
||||
|
||||
// Get the available keyboard groups
|
||||
bool getGroups(GroupList&) const;
|
||||
|
||||
// Change active keyboard group to group
|
||||
void setGroup(SInt32 group);
|
||||
|
||||
// Check if the keyboard layout has changed and update keyboard state
|
||||
// if so.
|
||||
void checkKeyboardLayout();
|
||||
|
||||
// Send an event for the given modifier key
|
||||
void handleModifierKey(void* target,
|
||||
UInt32 virtualKey, KeyID id,
|
||||
bool down, KeyModifierMask newMask);
|
||||
|
||||
// Checks if any in \p ids is a glyph key and if \p isCommand is false.
|
||||
// If so it adds the AltGr modifier to \p mask. This allows OS X
|
||||
// servers to use the option key both as AltGr and as a modifier. If
|
||||
// option is acting as AltGr (i.e. it generates a glyph and there are
|
||||
// no command modifiers active) then we don't send the super modifier
|
||||
// to clients because they'd try to match it as a command modifier.
|
||||
void adjustAltGrModifier(const CKeyIDs& ids,
|
||||
KeyModifierMask* mask, bool isCommand) const;
|
||||
|
||||
// Maps an OS X virtual key id to a KeyButton. This simply remaps
|
||||
// the ids so we don't use KeyButton 0.
|
||||
static KeyButton mapVirtualKeyToKeyButton(UInt32 keyCode);
|
||||
|
||||
// Maps a KeyButton to an OS X key code. This is the inverse of
|
||||
// mapVirtualKeyToKeyButton.
|
||||
static UInt32 mapKeyButtonToVirtualKey(KeyButton keyButton);
|
||||
|
||||
private:
|
||||
class CKeyResource : public IInterface {
|
||||
public:
|
||||
virtual bool isValid() const = 0;
|
||||
virtual UInt32 getNumModifierCombinations() const = 0;
|
||||
virtual UInt32 getNumTables() const = 0;
|
||||
virtual UInt32 getNumButtons() const = 0;
|
||||
virtual UInt32 getTableForModifier(UInt32 mask) const = 0;
|
||||
virtual KeyID getKey(UInt32 table, UInt32 button) const = 0;
|
||||
|
||||
// Convert a character in the current script to the equivalent KeyID
|
||||
static KeyID getKeyID(UInt8);
|
||||
|
||||
// Convert a unicode character to the equivalent KeyID.
|
||||
static KeyID unicharToKeyID(UniChar);
|
||||
};
|
||||
|
||||
class CKCHRKeyResource : public CKeyResource {
|
||||
public:
|
||||
CKCHRKeyResource(const void*);
|
||||
|
||||
// CKeyResource overrides
|
||||
virtual bool isValid() const;
|
||||
virtual UInt32 getNumModifierCombinations() const;
|
||||
virtual UInt32 getNumTables() const;
|
||||
virtual UInt32 getNumButtons() const;
|
||||
virtual UInt32 getTableForModifier(UInt32 mask) const;
|
||||
virtual KeyID getKey(UInt32 table, UInt32 button) const;
|
||||
|
||||
private:
|
||||
struct KCHRResource {
|
||||
public:
|
||||
SInt16 m_version;
|
||||
UInt8 m_tableSelectionIndex[256];
|
||||
SInt16 m_numTables;
|
||||
UInt8 m_characterTables[1][128];
|
||||
};
|
||||
struct CKCHRDeadKeyRecord {
|
||||
public:
|
||||
UInt8 m_tableIndex;
|
||||
UInt8 m_virtualKey;
|
||||
SInt16 m_numCompletions;
|
||||
UInt8 m_completion[1][2];
|
||||
};
|
||||
struct CKCHRDeadKeys {
|
||||
public:
|
||||
SInt16 m_numRecords;
|
||||
CKCHRDeadKeyRecord m_records[1];
|
||||
};
|
||||
|
||||
const KCHRResource* m_resource;
|
||||
};
|
||||
|
||||
class CUCHRKeyResource : public CKeyResource {
|
||||
public:
|
||||
CUCHRKeyResource(const void*, UInt32 keyboardType);
|
||||
|
||||
// CKeyResource overrides
|
||||
virtual bool isValid() const;
|
||||
virtual UInt32 getNumModifierCombinations() const;
|
||||
virtual UInt32 getNumTables() const;
|
||||
virtual UInt32 getNumButtons() const;
|
||||
virtual UInt32 getTableForModifier(UInt32 mask) const;
|
||||
virtual KeyID getKey(UInt32 table, UInt32 button) const;
|
||||
|
||||
private:
|
||||
typedef std::vector<KeyID> KeySequence;
|
||||
|
||||
bool getDeadKey(KeySequence& keys, UInt16 index) const;
|
||||
bool getKeyRecord(KeySequence& keys,
|
||||
UInt16 index, UInt16& state) const;
|
||||
bool addSequence(KeySequence& keys, UCKeyCharSeq c) const;
|
||||
|
||||
private:
|
||||
const UCKeyboardLayout* m_resource;
|
||||
const UCKeyModifiersToTableNum* m_m;
|
||||
const UCKeyToCharTableIndex* m_cti;
|
||||
const UCKeySequenceDataIndex* m_sdi;
|
||||
const UCKeyStateRecordsIndex* m_sri;
|
||||
const UCKeyStateTerminators* m_st;
|
||||
UInt16 m_spaceOutput;
|
||||
};
|
||||
|
||||
// OS X uses a physical key if 0 for the 'A' key. synergy reserves
|
||||
// KeyButton 0 so we offset all OS X physical key ids by this much
|
||||
// when used as a KeyButton and by minus this much to map a KeyButton
|
||||
// to a physical button.
|
||||
enum {
|
||||
KeyButtonOffset = 1
|
||||
};
|
||||
|
||||
typedef std::map<KeyboardLayoutRef, SInt32> GroupMap;
|
||||
typedef std::map<UInt32, KeyID> CVirtualKeyMap;
|
||||
|
||||
CVirtualKeyMap m_virtualKeyMap;
|
||||
mutable UInt32 m_deadKeyState;
|
||||
GroupList m_groups;
|
||||
GroupMap m_groupMap;
|
||||
};
|
||||
|
||||
#endif
|
||||
1699
lib/platform/COSXScreen.cpp
Normal file
1699
lib/platform/COSXScreen.cpp
Normal file
File diff suppressed because it is too large
Load Diff
252
lib/platform/COSXScreen.h
Normal file
252
lib/platform/COSXScreen.h
Normal file
@@ -0,0 +1,252 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef COSXSCREEN_H
|
||||
#define COSXSCREEN_H
|
||||
|
||||
#include "CPlatformScreen.h"
|
||||
#include "stdmap.h"
|
||||
#include "stdvector.h"
|
||||
#include <Carbon/Carbon.h>
|
||||
|
||||
#include <mach/mach_port.h>
|
||||
#include <mach/mach_interface.h>
|
||||
#include <mach/mach_init.h>
|
||||
#include <IOKit/pwr_mgt/IOPMLib.h>
|
||||
#include <IOKit/IOMessage.h>
|
||||
|
||||
template <class T>
|
||||
class CCondVar;
|
||||
class CEventQueueTimer;
|
||||
class CMutex;
|
||||
class CThread;
|
||||
class COSXKeyState;
|
||||
class COSXScreenSaver;
|
||||
|
||||
//! Implementation of IPlatformScreen for OS X
|
||||
class COSXScreen : public CPlatformScreen {
|
||||
public:
|
||||
COSXScreen(bool isPrimary);
|
||||
virtual ~COSXScreen();
|
||||
|
||||
// IScreen overrides
|
||||
virtual void* getEventTarget() const;
|
||||
virtual bool getClipboard(ClipboardID id, IClipboard*) const;
|
||||
virtual void getShape(SInt32& x, SInt32& y,
|
||||
SInt32& width, SInt32& height) const;
|
||||
virtual void getCursorPos(SInt32& x, SInt32& y) const;
|
||||
|
||||
// IPrimaryScreen overrides
|
||||
virtual void reconfigure(UInt32 activeSides);
|
||||
virtual void warpCursor(SInt32 x, SInt32 y);
|
||||
virtual UInt32 registerHotKey(KeyID key, KeyModifierMask mask);
|
||||
virtual void unregisterHotKey(UInt32 id);
|
||||
virtual void fakeInputBegin();
|
||||
virtual void fakeInputEnd();
|
||||
virtual SInt32 getJumpZoneSize() const;
|
||||
virtual bool isAnyMouseButtonDown() const;
|
||||
virtual void getCursorCenter(SInt32& x, SInt32& y) const;
|
||||
|
||||
// ISecondaryScreen overrides
|
||||
virtual void fakeMouseButton(ButtonID id, bool press) const;
|
||||
virtual void fakeMouseMove(SInt32 x, SInt32 y) const;
|
||||
virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const;
|
||||
virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const;
|
||||
|
||||
// IPlatformScreen overrides
|
||||
virtual void enable();
|
||||
virtual void disable();
|
||||
virtual void enter();
|
||||
virtual bool leave();
|
||||
virtual bool setClipboard(ClipboardID, const IClipboard*);
|
||||
virtual void checkClipboards();
|
||||
virtual void openScreensaver(bool notify);
|
||||
virtual void closeScreensaver();
|
||||
virtual void screensaver(bool activate);
|
||||
virtual void resetOptions();
|
||||
virtual void setOptions(const COptionsList& options);
|
||||
virtual void setSequenceNumber(UInt32);
|
||||
virtual bool isPrimary() const;
|
||||
|
||||
protected:
|
||||
// IPlatformScreen overrides
|
||||
virtual void handleSystemEvent(const CEvent&, void*);
|
||||
virtual void updateButtons();
|
||||
virtual IKeyState* getKeyState() const;
|
||||
|
||||
private:
|
||||
void updateScreenShape();
|
||||
void postMouseEvent(CGPoint&) const;
|
||||
|
||||
// convenience function to send events
|
||||
void sendEvent(CEvent::Type type, void* = NULL) const;
|
||||
void sendClipboardEvent(CEvent::Type type, ClipboardID id) const;
|
||||
|
||||
// message handlers
|
||||
bool onMouseMove(SInt32 x, SInt32 y);
|
||||
// mouse button handler. pressed is true if this is a mousedown
|
||||
// event, false if it is a mouseup event. macButton is the index
|
||||
// of the button pressed using the mac button mapping.
|
||||
bool onMouseButton(bool pressed, UInt16 macButton);
|
||||
bool onMouseWheel(SInt32 xDelta, SInt32 yDelta) const;
|
||||
|
||||
bool onDisplayChange();
|
||||
|
||||
bool onKey(EventRef event);
|
||||
bool onHotKey(EventRef event) const;
|
||||
|
||||
// map mac mouse button to synergy buttons
|
||||
ButtonID mapMacButtonToSynergy(UInt16) const;
|
||||
|
||||
// map mac scroll wheel value to a synergy scroll wheel value
|
||||
SInt32 mapScrollWheelToSynergy(SInt32) const;
|
||||
|
||||
// map synergy scroll wheel value to a mac scroll wheel value
|
||||
SInt32 mapScrollWheelFromSynergy(SInt32) const;
|
||||
|
||||
// get the current scroll wheel speed
|
||||
double getScrollSpeed() const;
|
||||
|
||||
// get the current scroll wheel speed
|
||||
double getScrollSpeedFactor() const;
|
||||
|
||||
// enable/disable drag handling for buttons 3 and up
|
||||
void enableDragTimer(bool enable);
|
||||
|
||||
// drag timer handler
|
||||
void handleDrag(const CEvent&, void*);
|
||||
|
||||
// clipboard check timer handler
|
||||
void handleClipboardCheck(const CEvent&, void*);
|
||||
|
||||
// Resolution switch callback
|
||||
static pascal void displayManagerCallback(void* inUserData,
|
||||
SInt16 inMessage, void* inNotifyData);
|
||||
|
||||
// fast user switch callback
|
||||
static pascal OSStatus
|
||||
userSwitchCallback(EventHandlerCallRef nextHandler,
|
||||
EventRef theEvent, void* inUserData);
|
||||
|
||||
// sleep / wakeup support
|
||||
void watchSystemPowerThread(void*);
|
||||
static void testCanceled(CFRunLoopTimerRef timer, void*info);
|
||||
static void powerChangeCallback(void* refcon, io_service_t service,
|
||||
natural_t messageType, void* messageArgument);
|
||||
void handlePowerChangeRequest(natural_t messageType,
|
||||
void* messageArgument);
|
||||
|
||||
static CEvent::Type getConfirmSleepEvent();
|
||||
void handleConfirmSleep(const CEvent& event, void*);
|
||||
|
||||
// global hotkey operating mode
|
||||
static bool isGlobalHotKeyOperatingModeAvailable();
|
||||
static void setGlobalHotKeysEnabled(bool enabled);
|
||||
static bool getGlobalHotKeysEnabled();
|
||||
|
||||
private:
|
||||
struct CHotKeyItem {
|
||||
public:
|
||||
CHotKeyItem(UInt32, UInt32);
|
||||
CHotKeyItem(EventHotKeyRef, UInt32, UInt32);
|
||||
|
||||
EventHotKeyRef getRef() const;
|
||||
|
||||
bool operator<(const CHotKeyItem&) const;
|
||||
|
||||
private:
|
||||
EventHotKeyRef m_ref;
|
||||
UInt32 m_keycode;
|
||||
UInt32 m_mask;
|
||||
};
|
||||
typedef std::map<UInt32, CHotKeyItem> HotKeyMap;
|
||||
typedef std::vector<UInt32> HotKeyIDList;
|
||||
typedef std::map<KeyModifierMask, UInt32> ModifierHotKeyMap;
|
||||
typedef std::map<CHotKeyItem, UInt32> HotKeyToIDMap;
|
||||
|
||||
// true if screen is being used as a primary screen, false otherwise
|
||||
bool m_isPrimary;
|
||||
|
||||
// true if mouse has entered the screen
|
||||
bool m_isOnScreen;
|
||||
|
||||
// the display
|
||||
CGDirectDisplayID m_displayID;
|
||||
|
||||
// screen shape stuff
|
||||
SInt32 m_x, m_y;
|
||||
SInt32 m_w, m_h;
|
||||
SInt32 m_xCenter, m_yCenter;
|
||||
|
||||
// mouse state
|
||||
mutable SInt32 m_xCursor, m_yCursor;
|
||||
mutable bool m_cursorPosValid;
|
||||
mutable boolean_t m_buttons[5];
|
||||
bool m_cursorHidden;
|
||||
SInt32 m_dragNumButtonsDown;
|
||||
Point m_dragLastPoint;
|
||||
CEventQueueTimer* m_dragTimer;
|
||||
|
||||
// keyboard stuff
|
||||
COSXKeyState* m_keyState;
|
||||
|
||||
// clipboards
|
||||
UInt32 m_sequenceNumber;
|
||||
|
||||
// screen saver stuff
|
||||
COSXScreenSaver* m_screensaver;
|
||||
bool m_screensaverNotify;
|
||||
|
||||
// clipboard stuff
|
||||
bool m_ownClipboard;
|
||||
CEventQueueTimer* m_clipboardTimer;
|
||||
|
||||
// window object that gets user input events when the server
|
||||
// has focus.
|
||||
WindowRef m_hiddenWindow;
|
||||
// window object that gets user input events when the server
|
||||
// does not have focus.
|
||||
WindowRef m_userInputWindow;
|
||||
|
||||
// display manager stuff (to get screen resolution switches).
|
||||
DMExtendedNotificationUPP m_displayManagerNotificationUPP;
|
||||
ProcessSerialNumber m_PSN;
|
||||
|
||||
// fast user switching
|
||||
EventHandlerRef m_switchEventHandlerRef;
|
||||
|
||||
// sleep / wakeup
|
||||
CMutex* m_pmMutex;
|
||||
CThread* m_pmWatchThread;
|
||||
CCondVar<bool>* m_pmThreadReady;
|
||||
CFRunLoopRef m_pmRunloop;
|
||||
io_connect_t m_pmRootPort;
|
||||
|
||||
// hot key stuff
|
||||
HotKeyMap m_hotKeys;
|
||||
HotKeyIDList m_oldHotKeyIDs;
|
||||
ModifierHotKeyMap m_modifierHotKeys;
|
||||
UInt32 m_activeModifierHotKey;
|
||||
KeyModifierMask m_activeModifierHotKeyMask;
|
||||
HotKeyToIDMap m_hotKeyToIDMap;
|
||||
|
||||
// global hotkey operating mode
|
||||
static bool s_testedForGHOM;
|
||||
static bool s_hasGHOM;
|
||||
|
||||
// events
|
||||
static CEvent::Type s_confirmSleepEvent;
|
||||
};
|
||||
|
||||
#endif
|
||||
175
lib/platform/COSXScreenSaver.cpp
Normal file
175
lib/platform/COSXScreenSaver.cpp
Normal file
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#import "COSXScreenSaver.h"
|
||||
#import "COSXScreenSaverUtil.h"
|
||||
#import "CLog.h"
|
||||
#import "IEventQueue.h"
|
||||
#import "IPrimaryScreen.h"
|
||||
#import <string.h>
|
||||
|
||||
//
|
||||
// COSXScreenSaver
|
||||
//
|
||||
|
||||
COSXScreenSaver::COSXScreenSaver(void* eventTarget) :
|
||||
m_eventTarget(eventTarget),
|
||||
m_enabled(true)
|
||||
{
|
||||
m_autoReleasePool = screenSaverUtilCreatePool();
|
||||
m_screenSaverController = screenSaverUtilCreateController();
|
||||
|
||||
// install launch/termination event handlers
|
||||
EventTypeSpec launchEventTypes[2];
|
||||
launchEventTypes[0].eventClass = kEventClassApplication;
|
||||
launchEventTypes[0].eventKind = kEventAppLaunched;
|
||||
launchEventTypes[1].eventClass = kEventClassApplication;
|
||||
launchEventTypes[1].eventKind = kEventAppTerminated;
|
||||
|
||||
EventHandlerUPP launchTerminationEventHandler =
|
||||
NewEventHandlerUPP(launchTerminationCallback);
|
||||
InstallApplicationEventHandler(launchTerminationEventHandler, 2,
|
||||
launchEventTypes, this,
|
||||
&m_launchTerminationEventHandlerRef);
|
||||
DisposeEventHandlerUPP(launchTerminationEventHandler);
|
||||
|
||||
m_screenSaverPSN.highLongOfPSN = 0;
|
||||
m_screenSaverPSN.lowLongOfPSN = 0;
|
||||
|
||||
// test if screensaver is running and find process number
|
||||
if (isActive()) {
|
||||
ProcessInfoRec procInfo;
|
||||
Str31 procName; // pascal string. first byte holds length.
|
||||
memset(&procInfo, 0, sizeof(procInfo));
|
||||
procInfo.processName = procName;
|
||||
procInfo.processInfoLength = sizeof(ProcessInfoRec);
|
||||
|
||||
ProcessSerialNumber psn;
|
||||
OSErr err = GetNextProcess(&psn);
|
||||
while (err == 0) {
|
||||
memset(procName, 0, sizeof(procName));
|
||||
err = GetProcessInformation(&psn, &procInfo);
|
||||
if (err != 0) {
|
||||
break;
|
||||
}
|
||||
if (strcmp("ScreenSaverEngine", (const char*)&procName[1]) == 0) {
|
||||
m_screenSaverPSN = psn;
|
||||
break;
|
||||
}
|
||||
err = GetNextProcess(&psn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
COSXScreenSaver::~COSXScreenSaver()
|
||||
{
|
||||
RemoveEventHandler(m_launchTerminationEventHandlerRef);
|
||||
// screenSaverUtilReleaseController(m_screenSaverController);
|
||||
screenSaverUtilReleasePool(m_autoReleasePool);
|
||||
}
|
||||
|
||||
void
|
||||
COSXScreenSaver::enable()
|
||||
{
|
||||
m_enabled = true;
|
||||
screenSaverUtilEnable(m_screenSaverController);
|
||||
}
|
||||
|
||||
void
|
||||
COSXScreenSaver::disable()
|
||||
{
|
||||
m_enabled = false;
|
||||
screenSaverUtilDisable(m_screenSaverController);
|
||||
}
|
||||
|
||||
void
|
||||
COSXScreenSaver::activate()
|
||||
{
|
||||
screenSaverUtilActivate(m_screenSaverController);
|
||||
}
|
||||
|
||||
void
|
||||
COSXScreenSaver::deactivate()
|
||||
{
|
||||
screenSaverUtilDeactivate(m_screenSaverController, m_enabled);
|
||||
}
|
||||
|
||||
bool
|
||||
COSXScreenSaver::isActive() const
|
||||
{
|
||||
return (screenSaverUtilIsActive(m_screenSaverController) != 0);
|
||||
}
|
||||
|
||||
void
|
||||
COSXScreenSaver::processLaunched(ProcessSerialNumber psn)
|
||||
{
|
||||
CFStringRef processName;
|
||||
OSStatus err = CopyProcessName(&psn, &processName);
|
||||
|
||||
if (err == 0 && CFEqual(CFSTR("ScreenSaverEngine"), processName)) {
|
||||
m_screenSaverPSN = psn;
|
||||
LOG((CLOG_DEBUG1 "ScreenSaverEngine launched. Enabled=%d", m_enabled));
|
||||
if (m_enabled) {
|
||||
EVENTQUEUE->addEvent(
|
||||
CEvent(IPrimaryScreen::getScreensaverActivatedEvent(),
|
||||
m_eventTarget));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
COSXScreenSaver::processTerminated(ProcessSerialNumber psn)
|
||||
{
|
||||
if (m_screenSaverPSN.highLongOfPSN == psn.highLongOfPSN &&
|
||||
m_screenSaverPSN.lowLongOfPSN == psn.lowLongOfPSN) {
|
||||
LOG((CLOG_DEBUG1 "ScreenSaverEngine terminated. Enabled=%d", m_enabled));
|
||||
if (m_enabled) {
|
||||
EVENTQUEUE->addEvent(
|
||||
CEvent(IPrimaryScreen::getScreensaverDeactivatedEvent(),
|
||||
m_eventTarget));
|
||||
}
|
||||
|
||||
m_screenSaverPSN.highLongOfPSN = 0;
|
||||
m_screenSaverPSN.lowLongOfPSN = 0;
|
||||
}
|
||||
}
|
||||
|
||||
pascal OSStatus
|
||||
COSXScreenSaver::launchTerminationCallback(
|
||||
EventHandlerCallRef nextHandler,
|
||||
EventRef theEvent, void* userData)
|
||||
{
|
||||
OSStatus result;
|
||||
ProcessSerialNumber psn;
|
||||
EventParamType actualType;
|
||||
UInt32 actualSize;
|
||||
|
||||
result = GetEventParameter(theEvent, kEventParamProcessID,
|
||||
typeProcessSerialNumber, &actualType,
|
||||
sizeof(psn), &actualSize, &psn);
|
||||
|
||||
if ((result == noErr) &&
|
||||
(actualSize > 0) &&
|
||||
(actualType == typeProcessSerialNumber)) {
|
||||
COSXScreenSaver* screenSaver = (COSXScreenSaver*)userData;
|
||||
UInt32 eventKind = GetEventKind(theEvent);
|
||||
if (eventKind == kEventAppLaunched) {
|
||||
screenSaver->processLaunched(psn);
|
||||
}
|
||||
else if (eventKind == kEventAppTerminated) {
|
||||
screenSaver->processTerminated(psn);
|
||||
}
|
||||
}
|
||||
return (CallNextEventHandler(nextHandler, theEvent));
|
||||
}
|
||||
54
lib/platform/COSXScreenSaver.h
Normal file
54
lib/platform/COSXScreenSaver.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 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.
|
||||
*/
|
||||
|
||||
#ifndef COSXSCREENSAVER_H
|
||||
#define COSXSCREENSAVER_H
|
||||
|
||||
#include "IScreenSaver.h"
|
||||
#include <Carbon/Carbon.h>
|
||||
|
||||
//! OSX screen saver implementation
|
||||
class COSXScreenSaver : public IScreenSaver {
|
||||
public:
|
||||
COSXScreenSaver(void* eventTarget);
|
||||
virtual ~COSXScreenSaver();
|
||||
|
||||
// IScreenSaver overrides
|
||||
virtual void enable();
|
||||
virtual void disable();
|
||||
virtual void activate();
|
||||
virtual void deactivate();
|
||||
virtual bool isActive() const;
|
||||
|
||||
private:
|
||||
void processLaunched(ProcessSerialNumber psn);
|
||||
void processTerminated(ProcessSerialNumber psn);
|
||||
|
||||
static pascal OSStatus
|
||||
launchTerminationCallback(
|
||||
EventHandlerCallRef nextHandler,
|
||||
EventRef theEvent, void* userData);
|
||||
|
||||
private:
|
||||
// the target for the events we generate
|
||||
void* m_eventTarget;
|
||||
|
||||
bool m_enabled;
|
||||
void* m_screenSaverController;
|
||||
void* m_autoReleasePool;
|
||||
EventHandlerRef m_launchTerminationEventHandlerRef;
|
||||
ProcessSerialNumber m_screenSaverPSN;
|
||||
};
|
||||
|
||||
#endif
|
||||
39
lib/platform/COSXScreenSaverUtil.h
Normal file
39
lib/platform/COSXScreenSaverUtil.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 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.
|
||||
*/
|
||||
|
||||
#ifndef COSXSCREENSAVERUTIL_H
|
||||
#define COSXSCREENSAVERUTIL_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void* screenSaverUtilCreatePool();
|
||||
void screenSaverUtilReleasePool(void*);
|
||||
|
||||
void* screenSaverUtilCreateController();
|
||||
void screenSaverUtilReleaseController(void*);
|
||||
void screenSaverUtilEnable(void*);
|
||||
void screenSaverUtilDisable(void*);
|
||||
void screenSaverUtilActivate(void*);
|
||||
void screenSaverUtilDeactivate(void*, int isEnabled);
|
||||
int screenSaverUtilIsActive(void*);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
81
lib/platform/COSXScreenSaverUtil.m
Normal file
81
lib/platform/COSXScreenSaverUtil.m
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#import "COSXScreenSaverUtil.h"
|
||||
#import "OSXScreenSaverControl.h"
|
||||
#import <Foundation/NSAutoreleasePool.h>
|
||||
|
||||
//
|
||||
// screenSaverUtil functions
|
||||
//
|
||||
// Note: these helper functions exist only so we can avoid using ObjC++.
|
||||
// autoconf/automake don't know about ObjC++ and I don't know how to
|
||||
// teach them about it.
|
||||
//
|
||||
|
||||
void*
|
||||
screenSaverUtilCreatePool()
|
||||
{
|
||||
return [[NSAutoreleasePool alloc] init];
|
||||
}
|
||||
|
||||
void
|
||||
screenSaverUtilReleasePool(void* pool)
|
||||
{
|
||||
[(NSAutoreleasePool*)pool release];
|
||||
}
|
||||
|
||||
void*
|
||||
screenSaverUtilCreateController()
|
||||
{
|
||||
return [[ScreenSaverController controller] retain];
|
||||
}
|
||||
|
||||
void
|
||||
screenSaverUtilReleaseController(void* controller)
|
||||
{
|
||||
[(ScreenSaverController*)controller release];
|
||||
}
|
||||
|
||||
void
|
||||
screenSaverUtilEnable(void* controller)
|
||||
{
|
||||
[(ScreenSaverController*)controller setScreenSaverCanRun:YES];
|
||||
}
|
||||
|
||||
void
|
||||
screenSaverUtilDisable(void* controller)
|
||||
{
|
||||
[(ScreenSaverController*)controller setScreenSaverCanRun:NO];
|
||||
}
|
||||
|
||||
void
|
||||
screenSaverUtilActivate(void* controller)
|
||||
{
|
||||
[(ScreenSaverController*)controller setScreenSaverCanRun:YES];
|
||||
[(ScreenSaverController*)controller screenSaverStartNow];
|
||||
}
|
||||
|
||||
void
|
||||
screenSaverUtilDeactivate(void* controller, int isEnabled)
|
||||
{
|
||||
[(ScreenSaverController*)controller screenSaverStopNow];
|
||||
[(ScreenSaverController*)controller setScreenSaverCanRun:isEnabled];
|
||||
}
|
||||
|
||||
int
|
||||
screenSaverUtilIsActive(void* controller)
|
||||
{
|
||||
return [(ScreenSaverController*)controller screenSaverIsRunning];
|
||||
}
|
||||
1110
lib/platform/CSynergyHook.cpp
Normal file
1110
lib/platform/CSynergyHook.cpp
Normal file
File diff suppressed because it is too large
Load Diff
81
lib/platform/CSynergyHook.h
Normal file
81
lib/platform/CSynergyHook.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 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.
|
||||
*/
|
||||
|
||||
#ifndef CSYNERGYHOOK_H
|
||||
#define CSYNERGYHOOK_H
|
||||
|
||||
#include "BasicTypes.h"
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
#if defined(SYNRGYHK_EXPORTS)
|
||||
#define CSYNERGYHOOK_API __declspec(dllexport)
|
||||
#else
|
||||
#define CSYNERGYHOOK_API __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
#define SYNERGY_MSG_MARK WM_APP + 0x0011 // mark id; <unused>
|
||||
#define SYNERGY_MSG_KEY WM_APP + 0x0012 // vk code; key data
|
||||
#define SYNERGY_MSG_MOUSE_BUTTON WM_APP + 0x0013 // button msg; <unused>
|
||||
#define SYNERGY_MSG_MOUSE_WHEEL WM_APP + 0x0014 // delta; <unused>
|
||||
#define SYNERGY_MSG_MOUSE_MOVE WM_APP + 0x0015 // x; y
|
||||
#define SYNERGY_MSG_POST_WARP WM_APP + 0x0016 // <unused>; <unused>
|
||||
#define SYNERGY_MSG_PRE_WARP WM_APP + 0x0017 // x; y
|
||||
#define SYNERGY_MSG_SCREEN_SAVER WM_APP + 0x0018 // activated; <unused>
|
||||
#define SYNERGY_MSG_DEBUG WM_APP + 0x0019 // data, data
|
||||
#define SYNERGY_MSG_INPUT_FIRST SYNERGY_MSG_KEY
|
||||
#define SYNERGY_MSG_INPUT_LAST SYNERGY_MSG_PRE_WARP
|
||||
#define SYNERGY_HOOK_LAST_MSG SYNERGY_MSG_DEBUG
|
||||
|
||||
#define SYNERGY_HOOK_FAKE_INPUT_VIRTUAL_KEY VK_CANCEL
|
||||
#define SYNERGY_HOOK_FAKE_INPUT_SCANCODE 0
|
||||
|
||||
extern "C" {
|
||||
|
||||
enum EHookResult {
|
||||
kHOOK_FAILED,
|
||||
kHOOK_OKAY,
|
||||
kHOOK_OKAY_LL
|
||||
};
|
||||
|
||||
enum EHookMode {
|
||||
kHOOK_DISABLE,
|
||||
kHOOK_WATCH_JUMP_ZONE,
|
||||
kHOOK_RELAY_EVENTS
|
||||
};
|
||||
|
||||
typedef int (*InitFunc)(DWORD targetQueueThreadID);
|
||||
typedef int (*CleanupFunc)(void);
|
||||
typedef EHookResult (*InstallFunc)(void);
|
||||
typedef int (*UninstallFunc)(void);
|
||||
typedef int (*InstallScreenSaverFunc)(void);
|
||||
typedef int (*UninstallScreenSaverFunc)(void);
|
||||
typedef void (*SetSidesFunc)(UInt32);
|
||||
typedef void (*SetZoneFunc)(SInt32, SInt32, SInt32, SInt32, SInt32);
|
||||
typedef void (*SetModeFunc)(int);
|
||||
|
||||
CSYNERGYHOOK_API int init(DWORD);
|
||||
CSYNERGYHOOK_API int cleanup(void);
|
||||
CSYNERGYHOOK_API EHookResult install(void);
|
||||
CSYNERGYHOOK_API int uninstall(void);
|
||||
CSYNERGYHOOK_API int installScreenSaver(void);
|
||||
CSYNERGYHOOK_API int uninstallScreenSaver(void);
|
||||
CSYNERGYHOOK_API void setSides(UInt32 sides);
|
||||
CSYNERGYHOOK_API void setZone(SInt32 x, SInt32 y, SInt32 w, SInt32 h,
|
||||
SInt32 jumpZoneSize);
|
||||
CSYNERGYHOOK_API void setMode(EHookMode mode);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
1507
lib/platform/CXWindowsClipboard.cpp
Normal file
1507
lib/platform/CXWindowsClipboard.cpp
Normal file
File diff suppressed because it is too large
Load Diff
376
lib/platform/CXWindowsClipboard.h
Normal file
376
lib/platform/CXWindowsClipboard.h
Normal file
@@ -0,0 +1,376 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 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.
|
||||
*/
|
||||
|
||||
#ifndef CXWINDOWSCLIPBOARD_H
|
||||
#define CXWINDOWSCLIPBOARD_H
|
||||
|
||||
#include "IClipboard.h"
|
||||
#include "ClipboardTypes.h"
|
||||
#include "stdmap.h"
|
||||
#include "stdlist.h"
|
||||
#include "stdvector.h"
|
||||
#if X_DISPLAY_MISSING
|
||||
# error X11 is required to build synergy
|
||||
#else
|
||||
# include <X11/Xlib.h>
|
||||
#endif
|
||||
|
||||
class IXWindowsClipboardConverter;
|
||||
|
||||
//! X11 clipboard implementation
|
||||
class CXWindowsClipboard : public IClipboard {
|
||||
public:
|
||||
/*!
|
||||
Use \c window as the window that owns or interacts with the
|
||||
clipboard identified by \c id.
|
||||
*/
|
||||
CXWindowsClipboard(Display*, Window window, ClipboardID id);
|
||||
virtual ~CXWindowsClipboard();
|
||||
|
||||
//! Notify clipboard was lost
|
||||
/*!
|
||||
Tells clipboard it lost ownership at the given time.
|
||||
*/
|
||||
void lost(Time);
|
||||
|
||||
//! Add clipboard request
|
||||
/*!
|
||||
Adds a selection request to the request list. If the given
|
||||
owner window isn't this clipboard's window then this simply
|
||||
sends a failure event to the requestor.
|
||||
*/
|
||||
void addRequest(Window owner,
|
||||
Window requestor, Atom target,
|
||||
::Time time, Atom property);
|
||||
|
||||
//! Process clipboard request
|
||||
/*!
|
||||
Continues processing a selection request. Returns true if the
|
||||
request was handled, false if the request was unknown.
|
||||
*/
|
||||
bool processRequest(Window requestor,
|
||||
::Time time, Atom property);
|
||||
|
||||
//! Cancel clipboard request
|
||||
/*!
|
||||
Terminate a selection request. Returns true iff the request
|
||||
was known and handled.
|
||||
*/
|
||||
bool destroyRequest(Window requestor);
|
||||
|
||||
//! Get window
|
||||
/*!
|
||||
Returns the clipboard's window (passed the c'tor).
|
||||
*/
|
||||
Window getWindow() const;
|
||||
|
||||
//! Get selection atom
|
||||
/*!
|
||||
Returns the selection atom that identifies the clipboard to X11
|
||||
(e.g. XA_PRIMARY).
|
||||
*/
|
||||
Atom getSelection() const;
|
||||
|
||||
// IClipboard overrides
|
||||
virtual bool empty();
|
||||
virtual void add(EFormat, const CString& data);
|
||||
virtual bool open(Time) const;
|
||||
virtual void close() const;
|
||||
virtual Time getTime() const;
|
||||
virtual bool has(EFormat) const;
|
||||
virtual CString get(EFormat) const;
|
||||
|
||||
private:
|
||||
// remove all converters from our list
|
||||
void clearConverters();
|
||||
|
||||
// get the converter for a clipboard format. returns NULL if no
|
||||
// suitable converter. iff onlyIfNotAdded is true then also
|
||||
// return NULL if a suitable converter was found but we already
|
||||
// have data of the converter's clipboard format.
|
||||
IXWindowsClipboardConverter*
|
||||
getConverter(Atom target,
|
||||
bool onlyIfNotAdded = false) const;
|
||||
|
||||
// convert target atom to clipboard format
|
||||
EFormat getFormat(Atom target) const;
|
||||
|
||||
// add a non-MULTIPLE request. does not verify that the selection
|
||||
// was owned at the given time. returns true if the conversion
|
||||
// could be performed, false otherwise. in either case, the
|
||||
// reply is inserted.
|
||||
bool addSimpleRequest(
|
||||
Window requestor, Atom target,
|
||||
::Time time, Atom property);
|
||||
|
||||
// if not already checked then see if the cache is stale and, if so,
|
||||
// clear it. this has the side effect of updating m_timeOwned.
|
||||
void checkCache() const;
|
||||
|
||||
// clear the cache, resetting the cached flag and the added flag for
|
||||
// each format.
|
||||
void clearCache() const;
|
||||
void doClearCache();
|
||||
|
||||
// cache all formats of the selection
|
||||
void fillCache() const;
|
||||
void doFillCache();
|
||||
|
||||
//
|
||||
// helper classes
|
||||
//
|
||||
|
||||
// read an ICCCM conforming selection
|
||||
class CICCCMGetClipboard {
|
||||
public:
|
||||
CICCCMGetClipboard(Window requestor, Time time, Atom property);
|
||||
~CICCCMGetClipboard();
|
||||
|
||||
// convert the given selection to the given type. returns
|
||||
// true iff the conversion was successful or the conversion
|
||||
// cannot be performed (in which case *actualTarget == None).
|
||||
bool readClipboard(Display* display,
|
||||
Atom selection, Atom target,
|
||||
Atom* actualTarget, CString* data);
|
||||
|
||||
private:
|
||||
bool processEvent(Display* display, XEvent* event);
|
||||
|
||||
private:
|
||||
Window m_requestor;
|
||||
Time m_time;
|
||||
Atom m_property;
|
||||
bool m_incr;
|
||||
bool m_failed;
|
||||
bool m_done;
|
||||
|
||||
// atoms needed for the protocol
|
||||
Atom m_atomNone; // NONE, not None
|
||||
Atom m_atomIncr;
|
||||
|
||||
// true iff we've received the selection notify
|
||||
bool m_reading;
|
||||
|
||||
// the converted selection data
|
||||
CString* m_data;
|
||||
|
||||
// the actual type of the data. if this is None then the
|
||||
// selection owner cannot convert to the requested type.
|
||||
Atom* m_actualTarget;
|
||||
|
||||
public:
|
||||
// true iff the selection owner didn't follow ICCCM conventions
|
||||
bool m_error;
|
||||
};
|
||||
|
||||
// Motif structure IDs
|
||||
enum { kMotifClipFormat = 1, kMotifClipItem, kMotifClipHeader };
|
||||
|
||||
// _MOTIF_CLIP_HEADER structure
|
||||
class CMotifClipHeader {
|
||||
public:
|
||||
SInt32 m_id; // kMotifClipHeader
|
||||
SInt32 m_pad1[3];
|
||||
SInt32 m_item;
|
||||
SInt32 m_pad2[4];
|
||||
SInt32 m_numItems;
|
||||
SInt32 m_pad3[3];
|
||||
SInt32 m_selectionOwner; // a Window
|
||||
SInt32 m_pad4[2];
|
||||
};
|
||||
|
||||
// Motif clip item structure
|
||||
class CMotifClipItem {
|
||||
public:
|
||||
SInt32 m_id; // kMotifClipItem
|
||||
SInt32 m_pad1[5];
|
||||
SInt32 m_size;
|
||||
SInt32 m_numFormats;
|
||||
SInt32 m_numDeletedFormats;
|
||||
SInt32 m_pad2[6];
|
||||
};
|
||||
|
||||
// Motif clip format structure
|
||||
class CMotifClipFormat {
|
||||
public:
|
||||
SInt32 m_id; // kMotifClipFormat
|
||||
SInt32 m_pad1[6];
|
||||
SInt32 m_length;
|
||||
SInt32 m_data;
|
||||
SInt32 m_type; // an Atom
|
||||
SInt32 m_pad2[1];
|
||||
SInt32 m_deleted;
|
||||
SInt32 m_pad3[4];
|
||||
};
|
||||
|
||||
// stores data needed to respond to a selection request
|
||||
class CReply {
|
||||
public:
|
||||
CReply(Window, Atom target, ::Time);
|
||||
CReply(Window, Atom target, ::Time, Atom property,
|
||||
const CString& data, Atom type, int format);
|
||||
|
||||
public:
|
||||
// information about the request
|
||||
Window m_requestor;
|
||||
Atom m_target;
|
||||
::Time m_time;
|
||||
Atom m_property;
|
||||
|
||||
// true iff we've sent the notification for this reply
|
||||
bool m_replied;
|
||||
|
||||
// true iff the reply has sent its last message
|
||||
bool m_done;
|
||||
|
||||
// the data to send and its type and format
|
||||
CString m_data;
|
||||
Atom m_type;
|
||||
int m_format;
|
||||
|
||||
// index of next byte in m_data to send
|
||||
UInt32 m_ptr;
|
||||
};
|
||||
typedef std::list<CReply*> CReplyList;
|
||||
typedef std::map<Window, CReplyList> CReplyMap;
|
||||
typedef std::map<Window, long> CReplyEventMask;
|
||||
|
||||
// ICCCM interoperability methods
|
||||
void icccmFillCache();
|
||||
bool icccmGetSelection(Atom target,
|
||||
Atom* actualTarget, CString* data) const;
|
||||
Time icccmGetTime() const;
|
||||
|
||||
// motif interoperability methods
|
||||
bool motifLockClipboard() const;
|
||||
void motifUnlockClipboard() const;
|
||||
bool motifOwnsClipboard() const;
|
||||
void motifFillCache();
|
||||
bool motifGetSelection(const CMotifClipFormat*,
|
||||
Atom* actualTarget, CString* data) const;
|
||||
Time motifGetTime() const;
|
||||
|
||||
// reply methods
|
||||
bool insertMultipleReply(Window, ::Time, Atom);
|
||||
void insertReply(CReply*);
|
||||
void pushReplies();
|
||||
void pushReplies(CReplyMap::iterator&,
|
||||
CReplyList&, CReplyList::iterator);
|
||||
bool sendReply(CReply*);
|
||||
void clearReplies();
|
||||
void clearReplies(CReplyList&);
|
||||
void sendNotify(Window requestor, Atom selection,
|
||||
Atom target, Atom property, Time time);
|
||||
bool wasOwnedAtTime(::Time) const;
|
||||
|
||||
// data conversion methods
|
||||
Atom getTargetsData(CString&, int* format) const;
|
||||
Atom getTimestampData(CString&, int* format) const;
|
||||
|
||||
private:
|
||||
typedef std::vector<IXWindowsClipboardConverter*> ConverterList;
|
||||
|
||||
Display* m_display;
|
||||
Window m_window;
|
||||
ClipboardID m_id;
|
||||
Atom m_selection;
|
||||
mutable bool m_open;
|
||||
mutable Time m_time;
|
||||
bool m_owner;
|
||||
mutable Time m_timeOwned;
|
||||
Time m_timeLost;
|
||||
|
||||
// true iff open and clipboard owned by a motif app
|
||||
mutable bool m_motif;
|
||||
|
||||
// the added/cached clipboard data
|
||||
mutable bool m_checkCache;
|
||||
bool m_cached;
|
||||
Time m_cacheTime;
|
||||
bool m_added[kNumFormats];
|
||||
CString m_data[kNumFormats];
|
||||
|
||||
// conversion request replies
|
||||
CReplyMap m_replies;
|
||||
CReplyEventMask m_eventMasks;
|
||||
|
||||
// clipboard format converters
|
||||
ConverterList m_converters;
|
||||
|
||||
// atoms we'll need
|
||||
Atom m_atomTargets;
|
||||
Atom m_atomMultiple;
|
||||
Atom m_atomTimestamp;
|
||||
Atom m_atomInteger;
|
||||
Atom m_atomAtom;
|
||||
Atom m_atomAtomPair;
|
||||
Atom m_atomData;
|
||||
Atom m_atomINCR;
|
||||
Atom m_atomMotifClipLock;
|
||||
Atom m_atomMotifClipHeader;
|
||||
Atom m_atomMotifClipAccess;
|
||||
Atom m_atomGDKSelection;
|
||||
};
|
||||
|
||||
//! Clipboard format converter interface
|
||||
/*!
|
||||
This interface defines the methods common to all X11 clipboard format
|
||||
converters.
|
||||
*/
|
||||
class IXWindowsClipboardConverter : public IInterface {
|
||||
public:
|
||||
//! @name accessors
|
||||
//@{
|
||||
|
||||
//! Get clipboard format
|
||||
/*!
|
||||
Return the clipboard format this object converts from/to.
|
||||
*/
|
||||
virtual IClipboard::EFormat
|
||||
getFormat() const = 0;
|
||||
|
||||
//! Get X11 format atom
|
||||
/*!
|
||||
Return the atom representing the X selection format that
|
||||
this object converts from/to.
|
||||
*/
|
||||
virtual Atom getAtom() const = 0;
|
||||
|
||||
//! Get X11 property datum size
|
||||
/*!
|
||||
Return the size (in bits) of data elements returned by
|
||||
toIClipboard().
|
||||
*/
|
||||
virtual int getDataSize() const = 0;
|
||||
|
||||
//! Convert from IClipboard format
|
||||
/*!
|
||||
Convert from the IClipboard format to the X selection format.
|
||||
The input data must be in the IClipboard format returned by
|
||||
getFormat(). The return data will be in the X selection
|
||||
format returned by getAtom().
|
||||
*/
|
||||
virtual CString fromIClipboard(const CString&) const = 0;
|
||||
|
||||
//! Convert to IClipboard format
|
||||
/*!
|
||||
Convert from the X selection format to the IClipboard format
|
||||
(i.e., the reverse of fromIClipboard()).
|
||||
*/
|
||||
virtual CString toIClipboard(const CString&) const = 0;
|
||||
|
||||
//@}
|
||||
};
|
||||
|
||||
#endif
|
||||
187
lib/platform/CXWindowsClipboardAnyBitmapConverter.cpp
Normal file
187
lib/platform/CXWindowsClipboardAnyBitmapConverter.cpp
Normal file
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* 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 "CXWindowsClipboardAnyBitmapConverter.h"
|
||||
|
||||
// BMP info header structure
|
||||
struct CBMPInfoHeader {
|
||||
public:
|
||||
UInt32 biSize;
|
||||
SInt32 biWidth;
|
||||
SInt32 biHeight;
|
||||
UInt16 biPlanes;
|
||||
UInt16 biBitCount;
|
||||
UInt32 biCompression;
|
||||
UInt32 biSizeImage;
|
||||
SInt32 biXPelsPerMeter;
|
||||
SInt32 biYPelsPerMeter;
|
||||
UInt32 biClrUsed;
|
||||
UInt32 biClrImportant;
|
||||
};
|
||||
|
||||
// BMP is little-endian
|
||||
|
||||
static
|
||||
void
|
||||
toLE(UInt8*& dst, UInt16 src)
|
||||
{
|
||||
dst[0] = static_cast<UInt8>(src & 0xffu);
|
||||
dst[1] = static_cast<UInt8>((src >> 8) & 0xffu);
|
||||
dst += 2;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
toLE(UInt8*& dst, SInt32 src)
|
||||
{
|
||||
dst[0] = static_cast<UInt8>(src & 0xffu);
|
||||
dst[1] = static_cast<UInt8>((src >> 8) & 0xffu);
|
||||
dst[2] = static_cast<UInt8>((src >> 16) & 0xffu);
|
||||
dst[3] = static_cast<UInt8>((src >> 24) & 0xffu);
|
||||
dst += 4;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
toLE(UInt8*& dst, UInt32 src)
|
||||
{
|
||||
dst[0] = static_cast<UInt8>(src & 0xffu);
|
||||
dst[1] = static_cast<UInt8>((src >> 8) & 0xffu);
|
||||
dst[2] = static_cast<UInt8>((src >> 16) & 0xffu);
|
||||
dst[3] = static_cast<UInt8>((src >> 24) & 0xffu);
|
||||
dst += 4;
|
||||
}
|
||||
|
||||
static inline
|
||||
UInt16
|
||||
fromLEU16(const UInt8* data)
|
||||
{
|
||||
return static_cast<UInt16>(data[0]) |
|
||||
(static_cast<UInt16>(data[1]) << 8);
|
||||
}
|
||||
|
||||
static inline
|
||||
SInt32
|
||||
fromLES32(const UInt8* data)
|
||||
{
|
||||
return static_cast<SInt32>(static_cast<UInt32>(data[0]) |
|
||||
(static_cast<UInt32>(data[1]) << 8) |
|
||||
(static_cast<UInt32>(data[2]) << 16) |
|
||||
(static_cast<UInt32>(data[3]) << 24));
|
||||
}
|
||||
|
||||
static inline
|
||||
UInt32
|
||||
fromLEU32(const UInt8* data)
|
||||
{
|
||||
return static_cast<UInt32>(data[0]) |
|
||||
(static_cast<UInt32>(data[1]) << 8) |
|
||||
(static_cast<UInt32>(data[2]) << 16) |
|
||||
(static_cast<UInt32>(data[3]) << 24);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// CXWindowsClipboardAnyBitmapConverter
|
||||
//
|
||||
|
||||
CXWindowsClipboardAnyBitmapConverter::CXWindowsClipboardAnyBitmapConverter()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
CXWindowsClipboardAnyBitmapConverter::~CXWindowsClipboardAnyBitmapConverter()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
IClipboard::EFormat
|
||||
CXWindowsClipboardAnyBitmapConverter::getFormat() const
|
||||
{
|
||||
return IClipboard::kBitmap;
|
||||
}
|
||||
|
||||
int
|
||||
CXWindowsClipboardAnyBitmapConverter::getDataSize() const
|
||||
{
|
||||
return 8;
|
||||
}
|
||||
|
||||
CString
|
||||
CXWindowsClipboardAnyBitmapConverter::fromIClipboard(const CString& bmp) const
|
||||
{
|
||||
// fill BMP info header with native-endian data
|
||||
CBMPInfoHeader infoHeader;
|
||||
const UInt8* rawBMPInfoHeader = reinterpret_cast<const UInt8*>(bmp.data());
|
||||
infoHeader.biSize = fromLEU32(rawBMPInfoHeader + 0);
|
||||
infoHeader.biWidth = fromLES32(rawBMPInfoHeader + 4);
|
||||
infoHeader.biHeight = fromLES32(rawBMPInfoHeader + 8);
|
||||
infoHeader.biPlanes = fromLEU16(rawBMPInfoHeader + 12);
|
||||
infoHeader.biBitCount = fromLEU16(rawBMPInfoHeader + 14);
|
||||
infoHeader.biCompression = fromLEU32(rawBMPInfoHeader + 16);
|
||||
infoHeader.biSizeImage = fromLEU32(rawBMPInfoHeader + 20);
|
||||
infoHeader.biXPelsPerMeter = fromLES32(rawBMPInfoHeader + 24);
|
||||
infoHeader.biYPelsPerMeter = fromLES32(rawBMPInfoHeader + 28);
|
||||
infoHeader.biClrUsed = fromLEU32(rawBMPInfoHeader + 32);
|
||||
infoHeader.biClrImportant = fromLEU32(rawBMPInfoHeader + 36);
|
||||
|
||||
// check that format is acceptable
|
||||
if (infoHeader.biSize != 40 ||
|
||||
infoHeader.biWidth == 0 || infoHeader.biHeight == 0 ||
|
||||
infoHeader.biPlanes != 0 || infoHeader.biCompression != 0 ||
|
||||
(infoHeader.biBitCount != 24 && infoHeader.biBitCount != 32)) {
|
||||
return CString();
|
||||
}
|
||||
|
||||
// convert to image format
|
||||
const UInt8* rawBMPPixels = rawBMPInfoHeader + 40;
|
||||
if (infoHeader.biBitCount == 24) {
|
||||
return doBGRFromIClipboard(rawBMPPixels,
|
||||
infoHeader.biWidth, infoHeader.biHeight);
|
||||
}
|
||||
else {
|
||||
return doBGRAFromIClipboard(rawBMPPixels,
|
||||
infoHeader.biWidth, infoHeader.biHeight);
|
||||
}
|
||||
}
|
||||
|
||||
CString
|
||||
CXWindowsClipboardAnyBitmapConverter::toIClipboard(const CString& image) const
|
||||
{
|
||||
// convert to raw BMP data
|
||||
UInt32 w, h, depth;
|
||||
CString rawBMP = doToIClipboard(image, w, h, depth);
|
||||
if (rawBMP.empty() || w == 0 || h == 0 || (depth != 24 && depth != 32)) {
|
||||
return CString();
|
||||
}
|
||||
|
||||
// fill BMP info header with little-endian data
|
||||
UInt8 infoHeader[40];
|
||||
UInt8* dst = infoHeader;
|
||||
toLE(dst, static_cast<UInt32>(40));
|
||||
toLE(dst, static_cast<SInt32>(w));
|
||||
toLE(dst, static_cast<SInt32>(h));
|
||||
toLE(dst, static_cast<UInt16>(1));
|
||||
toLE(dst, static_cast<UInt16>(depth));
|
||||
toLE(dst, static_cast<UInt32>(0)); // BI_RGB
|
||||
toLE(dst, static_cast<UInt32>(image.size()));
|
||||
toLE(dst, static_cast<SInt32>(2834)); // 72 dpi
|
||||
toLE(dst, static_cast<SInt32>(2834)); // 72 dpi
|
||||
toLE(dst, static_cast<UInt32>(0));
|
||||
toLE(dst, static_cast<UInt32>(0));
|
||||
|
||||
// construct image
|
||||
return CString(reinterpret_cast<const char*>(infoHeader),
|
||||
sizeof(infoHeader)) + rawBMP;
|
||||
}
|
||||
59
lib/platform/CXWindowsClipboardAnyBitmapConverter.h
Normal file
59
lib/platform/CXWindowsClipboardAnyBitmapConverter.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef CXWINDOWSCLIPBOARDANYBITMAPCONVERTER_H
|
||||
#define CXWINDOWSCLIPBOARDANYBITMAPCONVERTER_H
|
||||
|
||||
#include "CXWindowsClipboard.h"
|
||||
|
||||
//! Convert to/from some text encoding
|
||||
class CXWindowsClipboardAnyBitmapConverter :
|
||||
public IXWindowsClipboardConverter {
|
||||
public:
|
||||
CXWindowsClipboardAnyBitmapConverter();
|
||||
virtual ~CXWindowsClipboardAnyBitmapConverter();
|
||||
|
||||
// IXWindowsClipboardConverter overrides
|
||||
virtual IClipboard::EFormat
|
||||
getFormat() const;
|
||||
virtual Atom getAtom() const = 0;
|
||||
virtual int getDataSize() const;
|
||||
virtual CString fromIClipboard(const CString&) const;
|
||||
virtual CString toIClipboard(const CString&) const;
|
||||
|
||||
protected:
|
||||
//! Convert from IClipboard format
|
||||
/*!
|
||||
Convert raw BGR pixel data to another image format.
|
||||
*/
|
||||
virtual CString doBGRFromIClipboard(const UInt8* bgrData,
|
||||
UInt32 w, UInt32 h) const = 0;
|
||||
|
||||
//! Convert from IClipboard format
|
||||
/*!
|
||||
Convert raw BGRA pixel data to another image format.
|
||||
*/
|
||||
virtual CString doBGRAFromIClipboard(const UInt8* bgrData,
|
||||
UInt32 w, UInt32 h) const = 0;
|
||||
|
||||
//! Convert to IClipboard format
|
||||
/*!
|
||||
Convert an image into raw BGR or BGRA image data and store the
|
||||
width, height, and image depth (24 or 32).
|
||||
*/
|
||||
virtual CString doToIClipboard(const CString&,
|
||||
UInt32& w, UInt32& h, UInt32& depth) const = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
139
lib/platform/CXWindowsClipboardBMPConverter.cpp
Normal file
139
lib/platform/CXWindowsClipboardBMPConverter.cpp
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* 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 "CXWindowsClipboardBMPConverter.h"
|
||||
|
||||
// BMP file header structure
|
||||
struct CBMPHeader {
|
||||
public:
|
||||
UInt16 type;
|
||||
UInt32 size;
|
||||
UInt16 reserved1;
|
||||
UInt16 reserved2;
|
||||
UInt32 offset;
|
||||
};
|
||||
|
||||
// BMP is little-endian
|
||||
static inline
|
||||
UInt32
|
||||
fromLEU32(const UInt8* data)
|
||||
{
|
||||
return static_cast<UInt32>(data[0]) |
|
||||
(static_cast<UInt32>(data[1]) << 8) |
|
||||
(static_cast<UInt32>(data[2]) << 16) |
|
||||
(static_cast<UInt32>(data[3]) << 24);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
toLE(UInt8*& dst, char src)
|
||||
{
|
||||
dst[0] = static_cast<UInt8>(src);
|
||||
dst += 1;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
toLE(UInt8*& dst, UInt16 src)
|
||||
{
|
||||
dst[0] = static_cast<UInt8>(src & 0xffu);
|
||||
dst[1] = static_cast<UInt8>((src >> 8) & 0xffu);
|
||||
dst += 2;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
toLE(UInt8*& dst, UInt32 src)
|
||||
{
|
||||
dst[0] = static_cast<UInt8>(src & 0xffu);
|
||||
dst[1] = static_cast<UInt8>((src >> 8) & 0xffu);
|
||||
dst[2] = static_cast<UInt8>((src >> 16) & 0xffu);
|
||||
dst[3] = static_cast<UInt8>((src >> 24) & 0xffu);
|
||||
dst += 4;
|
||||
}
|
||||
|
||||
//
|
||||
// CXWindowsClipboardBMPConverter
|
||||
//
|
||||
|
||||
CXWindowsClipboardBMPConverter::CXWindowsClipboardBMPConverter(
|
||||
Display* display) :
|
||||
m_atom(XInternAtom(display, "image/bmp", False))
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
CXWindowsClipboardBMPConverter::~CXWindowsClipboardBMPConverter()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
IClipboard::EFormat
|
||||
CXWindowsClipboardBMPConverter::getFormat() const
|
||||
{
|
||||
return IClipboard::kBitmap;
|
||||
}
|
||||
|
||||
Atom
|
||||
CXWindowsClipboardBMPConverter::getAtom() const
|
||||
{
|
||||
return m_atom;
|
||||
}
|
||||
|
||||
int
|
||||
CXWindowsClipboardBMPConverter::getDataSize() const
|
||||
{
|
||||
return 8;
|
||||
}
|
||||
|
||||
CString
|
||||
CXWindowsClipboardBMPConverter::fromIClipboard(const CString& bmp) const
|
||||
{
|
||||
// create BMP image
|
||||
UInt8 header[14];
|
||||
UInt8* dst = header;
|
||||
toLE(dst, 'B');
|
||||
toLE(dst, 'M');
|
||||
toLE(dst, static_cast<UInt32>(14 + bmp.size()));
|
||||
toLE(dst, static_cast<UInt16>(0));
|
||||
toLE(dst, static_cast<UInt16>(0));
|
||||
toLE(dst, static_cast<UInt32>(14 + 40));
|
||||
return CString(reinterpret_cast<const char*>(header), 14) + bmp;
|
||||
}
|
||||
|
||||
CString
|
||||
CXWindowsClipboardBMPConverter::toIClipboard(const CString& bmp) const
|
||||
{
|
||||
// make sure data is big enough for a BMP file
|
||||
if (bmp.size() <= 14 + 40) {
|
||||
return CString();
|
||||
}
|
||||
|
||||
// check BMP file header
|
||||
const UInt8* rawBMPHeader = reinterpret_cast<const UInt8*>(bmp.data());
|
||||
if (rawBMPHeader[0] != 'B' || rawBMPHeader[1] != 'M') {
|
||||
return CString();
|
||||
}
|
||||
|
||||
// get offset to image data
|
||||
UInt32 offset = fromLEU32(rawBMPHeader + 10);
|
||||
|
||||
// construct BMP
|
||||
if (offset == 14 + 40) {
|
||||
return bmp.substr(14);
|
||||
}
|
||||
else {
|
||||
return bmp.substr(14, 40) + bmp.substr(offset, bmp.size() - offset);
|
||||
}
|
||||
}
|
||||
39
lib/platform/CXWindowsClipboardBMPConverter.h
Normal file
39
lib/platform/CXWindowsClipboardBMPConverter.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef CXWINDOWSCLIPBOARDBMPCONVERTER_H
|
||||
#define CXWINDOWSCLIPBOARDBMPCONVERTER_H
|
||||
|
||||
#include "CXWindowsClipboard.h"
|
||||
|
||||
//! Convert to/from some text encoding
|
||||
class CXWindowsClipboardBMPConverter :
|
||||
public IXWindowsClipboardConverter {
|
||||
public:
|
||||
CXWindowsClipboardBMPConverter(Display* display);
|
||||
virtual ~CXWindowsClipboardBMPConverter();
|
||||
|
||||
// IXWindowsClipboardConverter overrides
|
||||
virtual IClipboard::EFormat
|
||||
getFormat() const;
|
||||
virtual Atom getAtom() const;
|
||||
virtual int getDataSize() const;
|
||||
virtual CString fromIClipboard(const CString&) const;
|
||||
virtual CString toIClipboard(const CString&) const;
|
||||
|
||||
private:
|
||||
Atom m_atom;
|
||||
};
|
||||
|
||||
#endif
|
||||
62
lib/platform/CXWindowsClipboardHTMLConverter.cpp
Normal file
62
lib/platform/CXWindowsClipboardHTMLConverter.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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 "CXWindowsClipboardHTMLConverter.h"
|
||||
#include "CUnicode.h"
|
||||
|
||||
//
|
||||
// CXWindowsClipboardHTMLConverter
|
||||
//
|
||||
|
||||
CXWindowsClipboardHTMLConverter::CXWindowsClipboardHTMLConverter(
|
||||
Display* display, const char* name) :
|
||||
m_atom(XInternAtom(display, name, False))
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
CXWindowsClipboardHTMLConverter::~CXWindowsClipboardHTMLConverter()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
IClipboard::EFormat
|
||||
CXWindowsClipboardHTMLConverter::getFormat() const
|
||||
{
|
||||
return IClipboard::kHTML;
|
||||
}
|
||||
|
||||
Atom
|
||||
CXWindowsClipboardHTMLConverter::getAtom() const
|
||||
{
|
||||
return m_atom;
|
||||
}
|
||||
|
||||
int
|
||||
CXWindowsClipboardHTMLConverter::getDataSize() const
|
||||
{
|
||||
return 8;
|
||||
}
|
||||
|
||||
CString
|
||||
CXWindowsClipboardHTMLConverter::fromIClipboard(const CString& data) const
|
||||
{
|
||||
return CUnicode::UTF8ToUTF16(data);
|
||||
}
|
||||
|
||||
CString
|
||||
CXWindowsClipboardHTMLConverter::toIClipboard(const CString& data) const
|
||||
{
|
||||
return CUnicode::UTF16ToUTF8(data);
|
||||
}
|
||||
41
lib/platform/CXWindowsClipboardHTMLConverter.h
Normal file
41
lib/platform/CXWindowsClipboardHTMLConverter.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef CXWINDOWSCLIPBOARDHTMLCONVERTER_H
|
||||
#define CXWINDOWSCLIPBOARDHTMLCONVERTER_H
|
||||
|
||||
#include "CXWindowsClipboard.h"
|
||||
|
||||
//! Convert to/from HTML encoding
|
||||
class CXWindowsClipboardHTMLConverter : public IXWindowsClipboardConverter {
|
||||
public:
|
||||
/*!
|
||||
\c name is converted to an atom and that is reported by getAtom().
|
||||
*/
|
||||
CXWindowsClipboardHTMLConverter(Display* display, const char* name);
|
||||
virtual ~CXWindowsClipboardHTMLConverter();
|
||||
|
||||
// IXWindowsClipboardConverter overrides
|
||||
virtual IClipboard::EFormat
|
||||
getFormat() const;
|
||||
virtual Atom getAtom() const;
|
||||
virtual int getDataSize() const;
|
||||
virtual CString fromIClipboard(const CString&) const;
|
||||
virtual CString toIClipboard(const CString&) const;
|
||||
|
||||
private:
|
||||
Atom m_atom;
|
||||
};
|
||||
|
||||
#endif
|
||||
74
lib/platform/CXWindowsClipboardTextConverter.cpp
Normal file
74
lib/platform/CXWindowsClipboardTextConverter.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 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 "CXWindowsClipboardTextConverter.h"
|
||||
#include "CUnicode.h"
|
||||
|
||||
//
|
||||
// CXWindowsClipboardTextConverter
|
||||
//
|
||||
|
||||
CXWindowsClipboardTextConverter::CXWindowsClipboardTextConverter(
|
||||
Display* display, const char* name) :
|
||||
m_atom(XInternAtom(display, name, False))
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
CXWindowsClipboardTextConverter::~CXWindowsClipboardTextConverter()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
IClipboard::EFormat
|
||||
CXWindowsClipboardTextConverter::getFormat() const
|
||||
{
|
||||
return IClipboard::kText;
|
||||
}
|
||||
|
||||
Atom
|
||||
CXWindowsClipboardTextConverter::getAtom() const
|
||||
{
|
||||
return m_atom;
|
||||
}
|
||||
|
||||
int
|
||||
CXWindowsClipboardTextConverter::getDataSize() const
|
||||
{
|
||||
return 8;
|
||||
}
|
||||
|
||||
CString
|
||||
CXWindowsClipboardTextConverter::fromIClipboard(const CString& data) const
|
||||
{
|
||||
return CUnicode::UTF8ToText(data);
|
||||
}
|
||||
|
||||
CString
|
||||
CXWindowsClipboardTextConverter::toIClipboard(const CString& data) const
|
||||
{
|
||||
// convert to UTF-8
|
||||
bool errors;
|
||||
CString utf8 = CUnicode::textToUTF8(data, &errors);
|
||||
|
||||
// if there were decoding errors then, to support old applications
|
||||
// that don't understand UTF-8 but can report the exact binary
|
||||
// UTF-8 representation, see if the data appears to be UTF-8. if
|
||||
// so then use it as is.
|
||||
if (errors && CUnicode::isUTF8(data)) {
|
||||
return data;
|
||||
}
|
||||
|
||||
return utf8;
|
||||
}
|
||||
41
lib/platform/CXWindowsClipboardTextConverter.h
Normal file
41
lib/platform/CXWindowsClipboardTextConverter.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 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.
|
||||
*/
|
||||
|
||||
#ifndef CXWINDOWSCLIPBOARDTEXTCONVERTER_H
|
||||
#define CXWINDOWSCLIPBOARDTEXTCONVERTER_H
|
||||
|
||||
#include "CXWindowsClipboard.h"
|
||||
|
||||
//! Convert to/from locale text encoding
|
||||
class CXWindowsClipboardTextConverter : public IXWindowsClipboardConverter {
|
||||
public:
|
||||
/*!
|
||||
\c name is converted to an atom and that is reported by getAtom().
|
||||
*/
|
||||
CXWindowsClipboardTextConverter(Display* display, const char* name);
|
||||
virtual ~CXWindowsClipboardTextConverter();
|
||||
|
||||
// IXWindowsClipboardConverter overrides
|
||||
virtual IClipboard::EFormat
|
||||
getFormat() const;
|
||||
virtual Atom getAtom() const;
|
||||
virtual int getDataSize() const;
|
||||
virtual CString fromIClipboard(const CString&) const;
|
||||
virtual CString toIClipboard(const CString&) const;
|
||||
|
||||
private:
|
||||
Atom m_atom;
|
||||
};
|
||||
|
||||
#endif
|
||||
62
lib/platform/CXWindowsClipboardUCS2Converter.cpp
Normal file
62
lib/platform/CXWindowsClipboardUCS2Converter.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 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 "CXWindowsClipboardUCS2Converter.h"
|
||||
#include "CUnicode.h"
|
||||
|
||||
//
|
||||
// CXWindowsClipboardUCS2Converter
|
||||
//
|
||||
|
||||
CXWindowsClipboardUCS2Converter::CXWindowsClipboardUCS2Converter(
|
||||
Display* display, const char* name) :
|
||||
m_atom(XInternAtom(display, name, False))
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
CXWindowsClipboardUCS2Converter::~CXWindowsClipboardUCS2Converter()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
IClipboard::EFormat
|
||||
CXWindowsClipboardUCS2Converter::getFormat() const
|
||||
{
|
||||
return IClipboard::kText;
|
||||
}
|
||||
|
||||
Atom
|
||||
CXWindowsClipboardUCS2Converter::getAtom() const
|
||||
{
|
||||
return m_atom;
|
||||
}
|
||||
|
||||
int
|
||||
CXWindowsClipboardUCS2Converter::getDataSize() const
|
||||
{
|
||||
return 16;
|
||||
}
|
||||
|
||||
CString
|
||||
CXWindowsClipboardUCS2Converter::fromIClipboard(const CString& data) const
|
||||
{
|
||||
return CUnicode::UTF8ToUCS2(data);
|
||||
}
|
||||
|
||||
CString
|
||||
CXWindowsClipboardUCS2Converter::toIClipboard(const CString& data) const
|
||||
{
|
||||
return CUnicode::UCS2ToUTF8(data);
|
||||
}
|
||||
41
lib/platform/CXWindowsClipboardUCS2Converter.h
Normal file
41
lib/platform/CXWindowsClipboardUCS2Converter.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 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.
|
||||
*/
|
||||
|
||||
#ifndef CXWINDOWSCLIPBOARDUCS2CONVERTER_H
|
||||
#define CXWINDOWSCLIPBOARDUCS2CONVERTER_H
|
||||
|
||||
#include "CXWindowsClipboard.h"
|
||||
|
||||
//! Convert to/from UCS-2 encoding
|
||||
class CXWindowsClipboardUCS2Converter : public IXWindowsClipboardConverter {
|
||||
public:
|
||||
/*!
|
||||
\c name is converted to an atom and that is reported by getAtom().
|
||||
*/
|
||||
CXWindowsClipboardUCS2Converter(Display* display, const char* name);
|
||||
virtual ~CXWindowsClipboardUCS2Converter();
|
||||
|
||||
// IXWindowsClipboardConverter overrides
|
||||
virtual IClipboard::EFormat
|
||||
getFormat() const;
|
||||
virtual Atom getAtom() const;
|
||||
virtual int getDataSize() const;
|
||||
virtual CString fromIClipboard(const CString&) const;
|
||||
virtual CString toIClipboard(const CString&) const;
|
||||
|
||||
private:
|
||||
Atom m_atom;
|
||||
};
|
||||
|
||||
#endif
|
||||
61
lib/platform/CXWindowsClipboardUTF8Converter.cpp
Normal file
61
lib/platform/CXWindowsClipboardUTF8Converter.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 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 "CXWindowsClipboardUTF8Converter.h"
|
||||
|
||||
//
|
||||
// CXWindowsClipboardUTF8Converter
|
||||
//
|
||||
|
||||
CXWindowsClipboardUTF8Converter::CXWindowsClipboardUTF8Converter(
|
||||
Display* display, const char* name) :
|
||||
m_atom(XInternAtom(display, name, False))
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
CXWindowsClipboardUTF8Converter::~CXWindowsClipboardUTF8Converter()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
IClipboard::EFormat
|
||||
CXWindowsClipboardUTF8Converter::getFormat() const
|
||||
{
|
||||
return IClipboard::kText;
|
||||
}
|
||||
|
||||
Atom
|
||||
CXWindowsClipboardUTF8Converter::getAtom() const
|
||||
{
|
||||
return m_atom;
|
||||
}
|
||||
|
||||
int
|
||||
CXWindowsClipboardUTF8Converter::getDataSize() const
|
||||
{
|
||||
return 8;
|
||||
}
|
||||
|
||||
CString
|
||||
CXWindowsClipboardUTF8Converter::fromIClipboard(const CString& data) const
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
CString
|
||||
CXWindowsClipboardUTF8Converter::toIClipboard(const CString& data) const
|
||||
{
|
||||
return data;
|
||||
}
|
||||
41
lib/platform/CXWindowsClipboardUTF8Converter.h
Normal file
41
lib/platform/CXWindowsClipboardUTF8Converter.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 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.
|
||||
*/
|
||||
|
||||
#ifndef CXWINDOWSCLIPBOARDUTF8CONVERTER_H
|
||||
#define CXWINDOWSCLIPBOARDUTF8CONVERTER_H
|
||||
|
||||
#include "CXWindowsClipboard.h"
|
||||
|
||||
//! Convert to/from UTF-8 encoding
|
||||
class CXWindowsClipboardUTF8Converter : public IXWindowsClipboardConverter {
|
||||
public:
|
||||
/*!
|
||||
\c name is converted to an atom and that is reported by getAtom().
|
||||
*/
|
||||
CXWindowsClipboardUTF8Converter(Display* display, const char* name);
|
||||
virtual ~CXWindowsClipboardUTF8Converter();
|
||||
|
||||
// IXWindowsClipboardConverter overrides
|
||||
virtual IClipboard::EFormat
|
||||
getFormat() const;
|
||||
virtual Atom getAtom() const;
|
||||
virtual int getDataSize() const;
|
||||
virtual CString fromIClipboard(const CString&) const;
|
||||
virtual CString toIClipboard(const CString&) const;
|
||||
|
||||
private:
|
||||
Atom m_atom;
|
||||
};
|
||||
|
||||
#endif
|
||||
208
lib/platform/CXWindowsEventQueueBuffer.cpp
Normal file
208
lib/platform/CXWindowsEventQueueBuffer.cpp
Normal file
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* 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 "CXWindowsEventQueueBuffer.h"
|
||||
#include "CLock.h"
|
||||
#include "CThread.h"
|
||||
#include "CEvent.h"
|
||||
#include "IEventQueue.h"
|
||||
#if HAVE_POLL
|
||||
# include <poll.h>
|
||||
#else
|
||||
# if HAVE_SYS_SELECT_H
|
||||
# include <sys/select.h>
|
||||
# endif
|
||||
# if HAVE_SYS_TIME_H
|
||||
# include <sys/time.h>
|
||||
# endif
|
||||
# if HAVE_SYS_TYPES_H
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# if HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
//
|
||||
// CEventQueueTimer
|
||||
//
|
||||
|
||||
class CEventQueueTimer { };
|
||||
|
||||
|
||||
//
|
||||
// CXWindowsEventQueueBuffer
|
||||
//
|
||||
|
||||
CXWindowsEventQueueBuffer::CXWindowsEventQueueBuffer(
|
||||
Display* display, Window window) :
|
||||
m_display(display),
|
||||
m_window(window),
|
||||
m_waiting(false)
|
||||
{
|
||||
assert(m_display != NULL);
|
||||
assert(m_window != None);
|
||||
|
||||
m_userEvent = XInternAtom(m_display, "SYNERGY_USER_EVENT", False);
|
||||
}
|
||||
|
||||
CXWindowsEventQueueBuffer::~CXWindowsEventQueueBuffer()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsEventQueueBuffer::waitForEvent(double dtimeout)
|
||||
{
|
||||
CThread::testCancel();
|
||||
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
// we're now waiting for events
|
||||
m_waiting = true;
|
||||
|
||||
// push out pending events
|
||||
flush();
|
||||
}
|
||||
|
||||
// use poll() to wait for a message from the X server or for timeout.
|
||||
// this is a good deal more efficient than polling and sleeping.
|
||||
#if HAVE_POLL
|
||||
struct pollfd pfds[1];
|
||||
pfds[0].fd = ConnectionNumber(m_display);
|
||||
pfds[0].events = POLLIN;
|
||||
int timeout = (dtimeout < 0.0) ? -1 :
|
||||
static_cast<int>(1000.0 * dtimeout);
|
||||
#else
|
||||
struct timeval timeout;
|
||||
struct timeval* timeoutPtr;
|
||||
if (dtimeout < 0.0) {
|
||||
timeoutPtr = NULL;
|
||||
}
|
||||
else {
|
||||
timeout.tv_sec = static_cast<int>(dtimeout);
|
||||
timeout.tv_usec = static_cast<int>(1.0e+6 *
|
||||
(dtimeout - timeout.tv_sec));
|
||||
timeoutPtr = &timeout;
|
||||
}
|
||||
|
||||
// initialize file descriptor sets
|
||||
fd_set rfds;
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(ConnectionNumber(m_display), &rfds);
|
||||
#endif
|
||||
|
||||
// wait for message from X server or for timeout. also check
|
||||
// if the thread has been cancelled. poll() should return -1
|
||||
// with EINTR when the thread is cancelled.
|
||||
#if HAVE_POLL
|
||||
poll(pfds, 1, timeout);
|
||||
#else
|
||||
select(ConnectionNumber(m_display) + 1,
|
||||
SELECT_TYPE_ARG234 &rfds,
|
||||
SELECT_TYPE_ARG234 NULL,
|
||||
SELECT_TYPE_ARG234 NULL,
|
||||
SELECT_TYPE_ARG5 timeoutPtr);
|
||||
#endif
|
||||
|
||||
{
|
||||
// we're no longer waiting for events
|
||||
CLock lock(&m_mutex);
|
||||
m_waiting = false;
|
||||
}
|
||||
|
||||
CThread::testCancel();
|
||||
}
|
||||
|
||||
IEventQueueBuffer::Type
|
||||
CXWindowsEventQueueBuffer::getEvent(CEvent& event, UInt32& dataID)
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
|
||||
// push out pending events
|
||||
flush();
|
||||
|
||||
// get next event
|
||||
XNextEvent(m_display, &m_event);
|
||||
|
||||
// process event
|
||||
if (m_event.xany.type == ClientMessage &&
|
||||
m_event.xclient.message_type == m_userEvent) {
|
||||
dataID = static_cast<UInt32>(m_event.xclient.data.l[0]);
|
||||
return kUser;
|
||||
}
|
||||
else {
|
||||
event = CEvent(CEvent::kSystem,
|
||||
IEventQueue::getSystemTarget(), &m_event);
|
||||
return kSystem;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CXWindowsEventQueueBuffer::addEvent(UInt32 dataID)
|
||||
{
|
||||
// prepare a message
|
||||
XEvent xevent;
|
||||
xevent.xclient.type = ClientMessage;
|
||||
xevent.xclient.window = m_window;
|
||||
xevent.xclient.message_type = m_userEvent;
|
||||
xevent.xclient.format = 32;
|
||||
xevent.xclient.data.l[0] = static_cast<long>(dataID);
|
||||
|
||||
// save the message
|
||||
CLock lock(&m_mutex);
|
||||
m_postedEvents.push_back(xevent);
|
||||
|
||||
// if we're currently waiting for an event then send saved events to
|
||||
// the X server now. if we're not waiting then some other thread
|
||||
// might be using the display connection so we can't safely use it
|
||||
// too.
|
||||
if (m_waiting) {
|
||||
flush();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CXWindowsEventQueueBuffer::isEmpty() const
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
return (XPending(m_display) == 0);
|
||||
}
|
||||
|
||||
CEventQueueTimer*
|
||||
CXWindowsEventQueueBuffer::newTimer(double, bool) const
|
||||
{
|
||||
return new CEventQueueTimer;
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsEventQueueBuffer::deleteTimer(CEventQueueTimer* timer) const
|
||||
{
|
||||
delete timer;
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsEventQueueBuffer::flush()
|
||||
{
|
||||
// note -- m_mutex must be locked on entry
|
||||
|
||||
// flush the posted event list to the X server
|
||||
for (size_t i = 0; i < m_postedEvents.size(); ++i) {
|
||||
XSendEvent(m_display, m_window, False, 0, &m_postedEvents[i]);
|
||||
}
|
||||
XFlush(m_display);
|
||||
m_postedEvents.clear();
|
||||
}
|
||||
57
lib/platform/CXWindowsEventQueueBuffer.h
Normal file
57
lib/platform/CXWindowsEventQueueBuffer.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef CXWINDOWSEVENTQUEUEBUFFER_H
|
||||
#define CXWINDOWSEVENTQUEUEBUFFER_H
|
||||
|
||||
#include "IEventQueueBuffer.h"
|
||||
#include "CMutex.h"
|
||||
#include "stdvector.h"
|
||||
#if X_DISPLAY_MISSING
|
||||
# error X11 is required to build synergy
|
||||
#else
|
||||
# include <X11/Xlib.h>
|
||||
#endif
|
||||
|
||||
//! Event queue buffer for X11
|
||||
class CXWindowsEventQueueBuffer : public IEventQueueBuffer {
|
||||
public:
|
||||
CXWindowsEventQueueBuffer(Display*, Window);
|
||||
virtual ~CXWindowsEventQueueBuffer();
|
||||
|
||||
// IEventQueueBuffer overrides
|
||||
virtual void waitForEvent(double timeout);
|
||||
virtual Type getEvent(CEvent& event, UInt32& dataID);
|
||||
virtual bool addEvent(UInt32 dataID);
|
||||
virtual bool isEmpty() const;
|
||||
virtual CEventQueueTimer*
|
||||
newTimer(double duration, bool oneShot) const;
|
||||
virtual void deleteTimer(CEventQueueTimer*) const;
|
||||
|
||||
private:
|
||||
void flush();
|
||||
|
||||
private:
|
||||
typedef std::vector<XEvent> CEventList;
|
||||
|
||||
CMutex m_mutex;
|
||||
Display* m_display;
|
||||
Window m_window;
|
||||
Atom m_userEvent;
|
||||
XEvent m_event;
|
||||
CEventList m_postedEvents;
|
||||
bool m_waiting;
|
||||
};
|
||||
|
||||
#endif
|
||||
826
lib/platform/CXWindowsKeyState.cpp
Normal file
826
lib/platform/CXWindowsKeyState.cpp
Normal file
@@ -0,0 +1,826 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2003 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 "CXWindowsKeyState.h"
|
||||
#include "CXWindowsUtil.h"
|
||||
#include "CLog.h"
|
||||
#include "CStringUtil.h"
|
||||
#include "stdmap.h"
|
||||
#if X_DISPLAY_MISSING
|
||||
# error X11 is required to build synergy
|
||||
#else
|
||||
# include <X11/X.h>
|
||||
# include <X11/Xutil.h>
|
||||
# define XK_MISCELLANY
|
||||
# define XK_XKB_KEYS
|
||||
# include <X11/keysymdef.h>
|
||||
#if HAVE_XKB_EXTENSION
|
||||
# include <X11/XKBlib.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
CXWindowsKeyState::CXWindowsKeyState(Display* display, bool useXKB) :
|
||||
m_display(display)
|
||||
{
|
||||
XGetKeyboardControl(m_display, &m_keyboardState);
|
||||
#if HAVE_XKB_EXTENSION
|
||||
if (useXKB) {
|
||||
m_xkb = XkbGetMap(m_display, XkbKeyActionsMask | XkbKeyBehaviorsMask |
|
||||
XkbAllClientInfoMask, XkbUseCoreKbd);
|
||||
}
|
||||
else {
|
||||
m_xkb = NULL;
|
||||
}
|
||||
#endif
|
||||
setActiveGroup(kGroupPollAndSet);
|
||||
}
|
||||
|
||||
CXWindowsKeyState::~CXWindowsKeyState()
|
||||
{
|
||||
#if HAVE_XKB_EXTENSION
|
||||
if (m_xkb != NULL) {
|
||||
XkbFreeKeyboard(m_xkb, 0, True);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsKeyState::setActiveGroup(SInt32 group)
|
||||
{
|
||||
if (group == kGroupPollAndSet) {
|
||||
m_group = -1;
|
||||
m_group = pollActiveGroup();
|
||||
}
|
||||
else if (group == kGroupPoll) {
|
||||
m_group = -1;
|
||||
}
|
||||
else {
|
||||
assert(group >= 0);
|
||||
m_group = group;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsKeyState::setAutoRepeat(const XKeyboardState& state)
|
||||
{
|
||||
m_keyboardState = state;
|
||||
}
|
||||
|
||||
KeyModifierMask
|
||||
CXWindowsKeyState::mapModifiersFromX(unsigned int state) const
|
||||
{
|
||||
UInt32 offset = 8 * getGroupFromState(state);
|
||||
KeyModifierMask mask = 0;
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
if ((state & (1u << i)) != 0) {
|
||||
mask |= m_modifierFromX[offset + i];
|
||||
}
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
|
||||
bool
|
||||
CXWindowsKeyState::mapModifiersToX(KeyModifierMask mask,
|
||||
unsigned int& modifiers) const
|
||||
{
|
||||
modifiers = 0;
|
||||
|
||||
for (SInt32 i = 0; i < kKeyModifierNumBits; ++i) {
|
||||
KeyModifierMask bit = (1u << i);
|
||||
if ((mask & bit) != 0) {
|
||||
KeyModifierToXMask::const_iterator j = m_modifierToX.find(bit);
|
||||
if (j == m_modifierToX.end()) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
modifiers |= j->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsKeyState::mapKeyToKeycodes(KeyID key, CKeycodeList& keycodes) const
|
||||
{
|
||||
keycodes.clear();
|
||||
std::pair<KeyToKeyCodeMap::const_iterator,
|
||||
KeyToKeyCodeMap::const_iterator> range =
|
||||
m_keyCodeFromKey.equal_range(key);
|
||||
for (KeyToKeyCodeMap::const_iterator i = range.first;
|
||||
i != range.second; ++i) {
|
||||
keycodes.push_back(i->second);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CXWindowsKeyState::fakeCtrlAltDel()
|
||||
{
|
||||
// pass keys through unchanged
|
||||
return false;
|
||||
}
|
||||
|
||||
KeyModifierMask
|
||||
CXWindowsKeyState::pollActiveModifiers() const
|
||||
{
|
||||
Window root = DefaultRootWindow(m_display), window;
|
||||
int xRoot, yRoot, xWindow, yWindow;
|
||||
unsigned int state;
|
||||
if (!XQueryPointer(m_display, root, &root, &window,
|
||||
&xRoot, &yRoot, &xWindow, &yWindow, &state)) {
|
||||
state = 0;
|
||||
}
|
||||
return mapModifiersFromX(state);
|
||||
}
|
||||
|
||||
SInt32
|
||||
CXWindowsKeyState::pollActiveGroup() const
|
||||
{
|
||||
if (m_group != -1) {
|
||||
assert(m_group >= 0);
|
||||
return m_group;
|
||||
}
|
||||
|
||||
#if HAVE_XKB_EXTENSION
|
||||
if (m_xkb != NULL) {
|
||||
XkbStateRec state;
|
||||
if (XkbGetState(m_display, XkbUseCoreKbd, &state)) {
|
||||
return state.group;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsKeyState::pollPressedKeys(KeyButtonSet& pressedKeys) const
|
||||
{
|
||||
char keys[32];
|
||||
XQueryKeymap(m_display, keys);
|
||||
for (UInt32 i = 0; i < 32; ++i) {
|
||||
for (UInt32 j = 0; j < 8; ++j) {
|
||||
if ((keys[i] & (1u << j)) != 0) {
|
||||
pressedKeys.insert(8 * i + j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsKeyState::getKeyMap(CKeyMap& keyMap)
|
||||
{
|
||||
// get autorepeat info. we must use the global_auto_repeat told to
|
||||
// us because it may have modified by synergy.
|
||||
int oldGlobalAutoRepeat = m_keyboardState.global_auto_repeat;
|
||||
XGetKeyboardControl(m_display, &m_keyboardState);
|
||||
m_keyboardState.global_auto_repeat = oldGlobalAutoRepeat;
|
||||
|
||||
#if HAVE_XKB_EXTENSION
|
||||
if (m_xkb != NULL) {
|
||||
XkbGetUpdatedMap(m_display, XkbKeyActionsMask | XkbKeyBehaviorsMask |
|
||||
XkbAllClientInfoMask, m_xkb);
|
||||
updateKeysymMapXKB(keyMap);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
updateKeysymMap(keyMap);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsKeyState::fakeKey(const Keystroke& keystroke)
|
||||
{
|
||||
switch (keystroke.m_type) {
|
||||
case Keystroke::kButton:
|
||||
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"));
|
||||
if (keystroke.m_data.m_button.m_repeat) {
|
||||
int c = keystroke.m_data.m_button.m_button;
|
||||
int i = (c >> 3);
|
||||
int b = 1 << (c & 7);
|
||||
if (m_keyboardState.global_auto_repeat == AutoRepeatModeOff ||
|
||||
(m_keyboardState.auto_repeats[i] & b) == 0) {
|
||||
LOG((CLOG_DEBUG1 " discard autorepeat"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
XTestFakeKeyEvent(m_display, keystroke.m_data.m_button.m_button,
|
||||
keystroke.m_data.m_button.m_press ? True : False,
|
||||
CurrentTime);
|
||||
break;
|
||||
|
||||
case Keystroke::kGroup:
|
||||
if (keystroke.m_data.m_group.m_absolute) {
|
||||
LOG((CLOG_DEBUG1 " group %d", keystroke.m_data.m_group.m_group));
|
||||
#if HAVE_XKB_EXTENSION
|
||||
if (m_xkb != NULL) {
|
||||
XkbLockGroup(m_display, XkbUseCoreKbd,
|
||||
keystroke.m_data.m_group.m_group);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
LOG((CLOG_DEBUG1 " ignored"));
|
||||
}
|
||||
}
|
||||
else {
|
||||
LOG((CLOG_DEBUG1 " group %+d", keystroke.m_data.m_group.m_group));
|
||||
#if HAVE_XKB_EXTENSION
|
||||
if (m_xkb != NULL) {
|
||||
XkbLockGroup(m_display, XkbUseCoreKbd,
|
||||
getEffectiveGroup(pollActiveGroup(),
|
||||
keystroke.m_data.m_group.m_group));
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
LOG((CLOG_DEBUG1 " ignored"));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
XFlush(m_display);
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsKeyState::updateKeysymMap(CKeyMap& keyMap)
|
||||
{
|
||||
// there are up to 4 keysyms per keycode
|
||||
static const int maxKeysyms = 4;
|
||||
|
||||
LOG((CLOG_DEBUG1 "non-XKB mapping"));
|
||||
|
||||
// prepare map from X modifier to KeyModifierMask. certain bits
|
||||
// are predefined.
|
||||
m_modifierFromX.clear();
|
||||
m_modifierFromX.resize(8);
|
||||
m_modifierFromX[ShiftMapIndex] = KeyModifierShift;
|
||||
m_modifierFromX[LockMapIndex] = KeyModifierCapsLock;
|
||||
m_modifierFromX[ControlMapIndex] = KeyModifierControl;
|
||||
m_modifierToX.clear();
|
||||
m_modifierToX[KeyModifierShift] = ShiftMask;
|
||||
m_modifierToX[KeyModifierCapsLock] = LockMask;
|
||||
m_modifierToX[KeyModifierControl] = ControlMask;
|
||||
|
||||
// prepare map from KeyID to KeyCode
|
||||
m_keyCodeFromKey.clear();
|
||||
|
||||
// get the number of keycodes
|
||||
int minKeycode, maxKeycode;
|
||||
XDisplayKeycodes(m_display, &minKeycode, &maxKeycode);
|
||||
int numKeycodes = maxKeycode - minKeycode + 1;
|
||||
|
||||
// get the keyboard mapping for all keys
|
||||
int keysymsPerKeycode;
|
||||
KeySym* allKeysyms = XGetKeyboardMapping(m_display,
|
||||
minKeycode, numKeycodes,
|
||||
&keysymsPerKeycode);
|
||||
|
||||
// it's more convenient to always have maxKeysyms KeySyms per key
|
||||
{
|
||||
KeySym* tmpKeysyms = new KeySym[maxKeysyms * numKeycodes];
|
||||
for (int i = 0; i < numKeycodes; ++i) {
|
||||
for (int j = 0; j < maxKeysyms; ++j) {
|
||||
if (j < keysymsPerKeycode) {
|
||||
tmpKeysyms[maxKeysyms * i + j] =
|
||||
allKeysyms[keysymsPerKeycode * i + j];
|
||||
}
|
||||
else {
|
||||
tmpKeysyms[maxKeysyms * i + j] = NoSymbol;
|
||||
}
|
||||
}
|
||||
}
|
||||
XFree(allKeysyms);
|
||||
allKeysyms = tmpKeysyms;
|
||||
}
|
||||
|
||||
// get the buttons assigned to modifiers. X11 does not predefine
|
||||
// the meaning of any modifiers except shift, caps lock, and the
|
||||
// control key. the meaning of a modifier bit (other than those)
|
||||
// depends entirely on the KeySyms mapped to that bit. unfortunately
|
||||
// you cannot map a bit back to the KeySym used to produce it.
|
||||
// for example, let's say button 1 maps to Alt_L without shift and
|
||||
// Meta_L with shift. now if mod1 is mapped to button 1 that could
|
||||
// mean the user used Alt or Meta to turn on that modifier and there's
|
||||
// no way to know which. it's also possible for one button to be
|
||||
// mapped to multiple bits so both mod1 and mod2 could be generated
|
||||
// by button 1.
|
||||
//
|
||||
// we're going to ignore any modifier for a button except the first.
|
||||
// with the above example, that means we'll ignore the mod2 modifier
|
||||
// bit unless it's also mapped to some other button. we're also
|
||||
// going to ignore all KeySyms except the first modifier KeySym,
|
||||
// which means button 1 above won't map to Meta, just Alt.
|
||||
std::map<KeyCode, unsigned int> modifierButtons;
|
||||
XModifierKeymap* modifiers = XGetModifierMapping(m_display);
|
||||
for (unsigned int i = 0; i < 8; ++i) {
|
||||
const KeyCode* buttons =
|
||||
modifiers->modifiermap + i * modifiers->max_keypermod;
|
||||
for (int j = 0; j < modifiers->max_keypermod; ++j) {
|
||||
modifierButtons.insert(std::make_pair(buttons[j], i));
|
||||
}
|
||||
}
|
||||
XFreeModifiermap(modifiers);
|
||||
modifierButtons.erase(0);
|
||||
|
||||
// Hack to deal with VMware. When a VMware client grabs input the
|
||||
// player clears out the X modifier map for whatever reason. We're
|
||||
// notified of the change and arrive here to discover that there
|
||||
// are no modifiers at all. Since this prevents the modifiers from
|
||||
// working in the VMware client we'll use the last known good set
|
||||
// of modifiers when there are no modifiers. If there are modifiers
|
||||
// we update the last known good set.
|
||||
if (!modifierButtons.empty()) {
|
||||
m_lastGoodNonXKBModifiers = modifierButtons;
|
||||
}
|
||||
else {
|
||||
modifierButtons = m_lastGoodNonXKBModifiers;
|
||||
}
|
||||
|
||||
// add entries for each keycode
|
||||
CKeyMap::KeyItem item;
|
||||
for (int i = 0; i < numKeycodes; ++i) {
|
||||
KeySym* keysyms = allKeysyms + maxKeysyms * i;
|
||||
KeyCode keycode = static_cast<KeyCode>(i + minKeycode);
|
||||
item.m_button = static_cast<KeyButton>(keycode);
|
||||
item.m_client = 0;
|
||||
|
||||
// determine modifier sensitivity
|
||||
item.m_sensitive = 0;
|
||||
|
||||
// if the keysyms in levels 2 or 3 exist and differ from levels
|
||||
// 0 and 1 then the key is sensitive AltGr (Mode_switch)
|
||||
if ((keysyms[2] != NoSymbol && keysyms[2] != keysyms[0]) ||
|
||||
(keysyms[3] != NoSymbol && keysyms[2] != keysyms[1])) {
|
||||
item.m_sensitive |= KeyModifierAltGr;
|
||||
}
|
||||
|
||||
// check if the key is caps-lock sensitive. some systems only
|
||||
// provide one keysym for keys sensitive to caps-lock. if we
|
||||
// find that then fill in the missing keysym.
|
||||
if (keysyms[0] != NoSymbol && keysyms[1] == NoSymbol &&
|
||||
keysyms[2] == NoSymbol && keysyms[3] == NoSymbol) {
|
||||
KeySym lKeysym, uKeysym;
|
||||
XConvertCase(keysyms[0], &lKeysym, &uKeysym);
|
||||
if (lKeysym != uKeysym) {
|
||||
keysyms[0] = lKeysym;
|
||||
keysyms[1] = uKeysym;
|
||||
item.m_sensitive |= KeyModifierCapsLock;
|
||||
}
|
||||
}
|
||||
else if (keysyms[0] != NoSymbol && keysyms[1] != NoSymbol) {
|
||||
KeySym lKeysym, uKeysym;
|
||||
XConvertCase(keysyms[0], &lKeysym, &uKeysym);
|
||||
if (lKeysym != uKeysym &&
|
||||
lKeysym == keysyms[0] &&
|
||||
uKeysym == keysyms[1]) {
|
||||
item.m_sensitive |= KeyModifierCapsLock;
|
||||
}
|
||||
else if (keysyms[2] != NoSymbol && keysyms[3] != NoSymbol) {
|
||||
XConvertCase(keysyms[2], &lKeysym, &uKeysym);
|
||||
if (lKeysym != uKeysym &&
|
||||
lKeysym == keysyms[2] &&
|
||||
uKeysym == keysyms[3]) {
|
||||
item.m_sensitive |= KeyModifierCapsLock;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// key is sensitive to shift if keysyms in levels 0 and 1 or
|
||||
// levels 2 and 3 don't match. it's also sensitive to shift
|
||||
// if it's sensitive to caps-lock.
|
||||
if ((item.m_sensitive & KeyModifierCapsLock) != 0) {
|
||||
item.m_sensitive |= KeyModifierShift;
|
||||
}
|
||||
else if ((keysyms[0] != NoSymbol && keysyms[1] != NoSymbol &&
|
||||
keysyms[0] != keysyms[1]) ||
|
||||
(keysyms[2] != NoSymbol && keysyms[3] != NoSymbol &&
|
||||
keysyms[2] != keysyms[3])) {
|
||||
item.m_sensitive |= KeyModifierShift;
|
||||
}
|
||||
|
||||
// key is sensitive to numlock if any keysym on it is
|
||||
if (IsKeypadKey(keysyms[0]) || IsPrivateKeypadKey(keysyms[0]) ||
|
||||
IsKeypadKey(keysyms[1]) || IsPrivateKeypadKey(keysyms[1]) ||
|
||||
IsKeypadKey(keysyms[2]) || IsPrivateKeypadKey(keysyms[2]) ||
|
||||
IsKeypadKey(keysyms[3]) || IsPrivateKeypadKey(keysyms[3])) {
|
||||
item.m_sensitive |= KeyModifierNumLock;
|
||||
}
|
||||
|
||||
// do each keysym (shift level)
|
||||
for (int j = 0; j < maxKeysyms; ++j) {
|
||||
item.m_id = CXWindowsUtil::mapKeySymToKeyID(keysyms[j]);
|
||||
if (item.m_id == kKeyNone) {
|
||||
if (j != 0 && modifierButtons.count(keycode) > 0) {
|
||||
// pretend the modifier works in other shift levels
|
||||
// because it probably does.
|
||||
if (keysyms[1] == NoSymbol || j != 3) {
|
||||
item.m_id = CXWindowsUtil::mapKeySymToKeyID(keysyms[0]);
|
||||
}
|
||||
else {
|
||||
item.m_id = CXWindowsUtil::mapKeySymToKeyID(keysyms[1]);
|
||||
}
|
||||
}
|
||||
if (item.m_id == kKeyNone) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// group is 0 for levels 0 and 1 and 1 for levels 2 and 3
|
||||
item.m_group = (j >= 2) ? 1 : 0;
|
||||
|
||||
// compute required modifiers
|
||||
item.m_required = 0;
|
||||
if ((j & 1) != 0) {
|
||||
item.m_required |= KeyModifierShift;
|
||||
}
|
||||
if ((j & 2) != 0) {
|
||||
item.m_required |= KeyModifierAltGr;
|
||||
}
|
||||
|
||||
item.m_generates = 0;
|
||||
item.m_lock = false;
|
||||
if (modifierButtons.count(keycode) > 0) {
|
||||
// get flags for modifier keys
|
||||
CKeyMap::initModifierKey(item);
|
||||
|
||||
// add mapping from X (unless we already have)
|
||||
if (item.m_generates != 0) {
|
||||
unsigned int bit = modifierButtons[keycode];
|
||||
if (m_modifierFromX[bit] == 0) {
|
||||
m_modifierFromX[bit] = item.m_generates;
|
||||
m_modifierToX[item.m_generates] = (1u << bit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add key
|
||||
keyMap.addKeyEntry(item);
|
||||
m_keyCodeFromKey.insert(std::make_pair(item.m_id, keycode));
|
||||
|
||||
// add other ways to synthesize the key
|
||||
if ((j & 1) != 0) {
|
||||
// add capslock version of key is sensitive to capslock
|
||||
KeySym lKeysym, uKeysym;
|
||||
XConvertCase(keysyms[j], &lKeysym, &uKeysym);
|
||||
if (lKeysym != uKeysym &&
|
||||
lKeysym == keysyms[j - 1] &&
|
||||
uKeysym == keysyms[j]) {
|
||||
item.m_required &= ~KeyModifierShift;
|
||||
item.m_required |= KeyModifierCapsLock;
|
||||
keyMap.addKeyEntry(item);
|
||||
item.m_required |= KeyModifierShift;
|
||||
item.m_required &= ~KeyModifierCapsLock;
|
||||
}
|
||||
|
||||
// add numlock version of key if sensitive to numlock
|
||||
if (IsKeypadKey(keysyms[j]) || IsPrivateKeypadKey(keysyms[j])) {
|
||||
item.m_required &= ~KeyModifierShift;
|
||||
item.m_required |= KeyModifierNumLock;
|
||||
keyMap.addKeyEntry(item);
|
||||
item.m_required |= KeyModifierShift;
|
||||
item.m_required &= ~KeyModifierNumLock;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete[] allKeysyms;
|
||||
}
|
||||
|
||||
#if HAVE_XKB_EXTENSION
|
||||
void
|
||||
CXWindowsKeyState::updateKeysymMapXKB(CKeyMap& keyMap)
|
||||
{
|
||||
static const XkbKTMapEntryRec defMapEntry = {
|
||||
True, // active
|
||||
0, // level
|
||||
{
|
||||
0, // mods.mask
|
||||
0, // mods.real_mods
|
||||
0 // mods.vmods
|
||||
}
|
||||
};
|
||||
|
||||
LOG((CLOG_DEBUG1 "XKB mapping"));
|
||||
|
||||
// find the number of groups
|
||||
int maxNumGroups = 0;
|
||||
for (int i = m_xkb->min_key_code; i <= m_xkb->max_key_code; ++i) {
|
||||
int numGroups = XkbKeyNumGroups(m_xkb, static_cast<KeyCode>(i));
|
||||
if (numGroups > maxNumGroups) {
|
||||
maxNumGroups = numGroups;
|
||||
}
|
||||
}
|
||||
|
||||
// prepare map from X modifier to KeyModifierMask
|
||||
std::vector<int> modifierLevel(maxNumGroups * 8, 4);
|
||||
m_modifierFromX.clear();
|
||||
m_modifierFromX.resize(maxNumGroups * 8);
|
||||
m_modifierToX.clear();
|
||||
|
||||
// prepare map from KeyID to KeyCode
|
||||
m_keyCodeFromKey.clear();
|
||||
|
||||
// Hack to deal with VMware. When a VMware client grabs input the
|
||||
// player clears out the X modifier map for whatever reason. We're
|
||||
// notified of the change and arrive here to discover that there
|
||||
// are no modifiers at all. Since this prevents the modifiers from
|
||||
// working in the VMware client we'll use the last known good set
|
||||
// of modifiers when there are no modifiers. If there are modifiers
|
||||
// we update the last known good set.
|
||||
bool useLastGoodModifiers = !hasModifiersXKB();
|
||||
if (!useLastGoodModifiers) {
|
||||
m_lastGoodXKBModifiers.clear();
|
||||
}
|
||||
|
||||
// check every button. on this pass we save all modifiers as native
|
||||
// X modifier masks.
|
||||
CKeyMap::KeyItem item;
|
||||
for (int i = m_xkb->min_key_code; i <= m_xkb->max_key_code; ++i) {
|
||||
KeyCode keycode = static_cast<KeyCode>(i);
|
||||
item.m_button = static_cast<KeyButton>(keycode);
|
||||
item.m_client = 0;
|
||||
|
||||
// skip keys with no groups (they generate no symbols)
|
||||
if (XkbKeyNumGroups(m_xkb, keycode) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// note half-duplex keys
|
||||
const XkbBehavior& b = m_xkb->server->behaviors[keycode];
|
||||
if ((b.type & XkbKB_OpMask) == XkbKB_Lock) {
|
||||
keyMap.addHalfDuplexButton(item.m_button);
|
||||
}
|
||||
|
||||
// iterate over all groups
|
||||
for (int group = 0; group < maxNumGroups; ++group) {
|
||||
item.m_group = group;
|
||||
int eGroup = getEffectiveGroup(keycode, group);
|
||||
|
||||
// get key info
|
||||
XkbKeyTypePtr type = XkbKeyKeyType(m_xkb, keycode, eGroup);
|
||||
|
||||
// set modifiers the item is sensitive to
|
||||
item.m_sensitive = type->mods.mask;
|
||||
|
||||
// iterate over all shift levels for the button (including none)
|
||||
for (int j = -1; j < type->map_count; ++j) {
|
||||
const XkbKTMapEntryRec* mapEntry =
|
||||
((j == -1) ? &defMapEntry : type->map + j);
|
||||
if (!mapEntry->active) {
|
||||
continue;
|
||||
}
|
||||
int level = mapEntry->level;
|
||||
|
||||
// set required modifiers for this item
|
||||
item.m_required = mapEntry->mods.mask;
|
||||
if ((item.m_required & LockMask) != 0 &&
|
||||
j != -1 && type->preserve != NULL &&
|
||||
(type->preserve[j].mask & LockMask) != 0) {
|
||||
// sensitive caps lock and we preserve caps-lock.
|
||||
// preserving caps-lock means we Xlib functions would
|
||||
// yield the capitialized KeySym so we'll adjust the
|
||||
// level accordingly.
|
||||
if ((level ^ 1) < type->num_levels) {
|
||||
level ^= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// get the keysym for this item
|
||||
KeySym keysym = XkbKeySymEntry(m_xkb, keycode, level, eGroup);
|
||||
|
||||
// check for group change actions, locking modifiers, and
|
||||
// modifier masks.
|
||||
item.m_lock = false;
|
||||
bool isModifier = false;
|
||||
UInt32 modifierMask = m_xkb->map->modmap[keycode];
|
||||
if (XkbKeyHasActions(m_xkb, keycode)) {
|
||||
XkbAction* action =
|
||||
XkbKeyActionEntry(m_xkb, keycode, level, eGroup);
|
||||
if (action->type == XkbSA_SetMods ||
|
||||
action->type == XkbSA_LockMods) {
|
||||
isModifier = true;
|
||||
|
||||
// note toggles
|
||||
item.m_lock = (action->type == XkbSA_LockMods);
|
||||
|
||||
// maybe use action's mask
|
||||
if ((action->mods.flags & XkbSA_UseModMapMods) == 0) {
|
||||
modifierMask = action->mods.mask;
|
||||
}
|
||||
}
|
||||
else if (action->type == XkbSA_SetGroup ||
|
||||
action->type == XkbSA_LatchGroup ||
|
||||
action->type == XkbSA_LockGroup) {
|
||||
// ignore group change key
|
||||
continue;
|
||||
}
|
||||
}
|
||||
level = mapEntry->level;
|
||||
|
||||
// VMware modifier hack
|
||||
if (useLastGoodModifiers) {
|
||||
XKBModifierMap::const_iterator k =
|
||||
m_lastGoodXKBModifiers.find(eGroup * 256 + keycode);
|
||||
if (k != m_lastGoodXKBModifiers.end()) {
|
||||
// Use last known good modifier
|
||||
isModifier = true;
|
||||
level = k->second.m_level;
|
||||
modifierMask = k->second.m_mask;
|
||||
item.m_lock = k->second.m_lock;
|
||||
}
|
||||
}
|
||||
else if (isModifier) {
|
||||
// Save known good modifier
|
||||
XKBModifierInfo& info =
|
||||
m_lastGoodXKBModifiers[eGroup * 256 + keycode];
|
||||
info.m_level = level;
|
||||
info.m_mask = modifierMask;
|
||||
info.m_lock = item.m_lock;
|
||||
}
|
||||
|
||||
// record the modifier mask for this key. don't bother
|
||||
// for keys that change the group.
|
||||
item.m_generates = 0;
|
||||
UInt32 modifierBit =
|
||||
CXWindowsUtil::getModifierBitForKeySym(keysym);
|
||||
if (isModifier && modifierBit != kKeyModifierBitNone) {
|
||||
item.m_generates = (1u << modifierBit);
|
||||
for (SInt32 j = 0; j < 8; ++j) {
|
||||
// skip modifiers this key doesn't generate
|
||||
if ((modifierMask & (1u << j)) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// skip keys that map to a modifier that we've
|
||||
// already seen using fewer modifiers. that is
|
||||
// if this key must combine with other modifiers
|
||||
// and we know of a key that combines with fewer
|
||||
// modifiers (or no modifiers) then prefer the
|
||||
// other key.
|
||||
if (level >= modifierLevel[8 * group + j]) {
|
||||
continue;
|
||||
}
|
||||
modifierLevel[8 * group + j] = level;
|
||||
|
||||
// save modifier
|
||||
m_modifierFromX[8 * group + j] |= (1u << modifierBit);
|
||||
m_modifierToX.insert(std::make_pair(
|
||||
1u << modifierBit, 1u << j));
|
||||
}
|
||||
}
|
||||
|
||||
// handle special cases of just one keysym for the keycode
|
||||
if (type->num_levels == 1) {
|
||||
// if there are upper- and lowercase versions of the
|
||||
// keysym then add both.
|
||||
KeySym lKeysym, uKeysym;
|
||||
XConvertCase(keysym, &lKeysym, &uKeysym);
|
||||
if (lKeysym != uKeysym) {
|
||||
if (j != -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
item.m_sensitive |= ShiftMask | LockMask;
|
||||
|
||||
KeyID lKeyID = CXWindowsUtil::mapKeySymToKeyID(lKeysym);
|
||||
KeyID uKeyID = CXWindowsUtil::mapKeySymToKeyID(uKeysym);
|
||||
if (lKeyID == kKeyNone || uKeyID == kKeyNone) {
|
||||
continue;
|
||||
}
|
||||
|
||||
item.m_id = lKeyID;
|
||||
item.m_required = 0;
|
||||
keyMap.addKeyEntry(item);
|
||||
|
||||
item.m_id = uKeyID;
|
||||
item.m_required = ShiftMask;
|
||||
keyMap.addKeyEntry(item);
|
||||
item.m_required = LockMask;
|
||||
keyMap.addKeyEntry(item);
|
||||
|
||||
if (group == 0) {
|
||||
m_keyCodeFromKey.insert(
|
||||
std::make_pair(lKeyID, keycode));
|
||||
m_keyCodeFromKey.insert(
|
||||
std::make_pair(uKeyID, keycode));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// add entry
|
||||
item.m_id = CXWindowsUtil::mapKeySymToKeyID(keysym);
|
||||
keyMap.addKeyEntry(item);
|
||||
if (group == 0) {
|
||||
m_keyCodeFromKey.insert(std::make_pair(item.m_id, keycode));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// change all modifier masks to synergy masks from X masks
|
||||
keyMap.foreachKey(&CXWindowsKeyState::remapKeyModifiers, this);
|
||||
|
||||
// allow composition across groups
|
||||
keyMap.allowGroupSwitchDuringCompose();
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
CXWindowsKeyState::remapKeyModifiers(KeyID id, SInt32 group,
|
||||
CKeyMap::KeyItem& item, void* vself)
|
||||
{
|
||||
CXWindowsKeyState* self = reinterpret_cast<CXWindowsKeyState*>(vself);
|
||||
item.m_required =
|
||||
self->mapModifiersFromX(XkbBuildCoreState(item.m_required, group));
|
||||
item.m_sensitive =
|
||||
self->mapModifiersFromX(XkbBuildCoreState(item.m_sensitive, group));
|
||||
}
|
||||
|
||||
bool
|
||||
CXWindowsKeyState::hasModifiersXKB() const
|
||||
{
|
||||
#if HAVE_XKB_EXTENSION
|
||||
// iterate over all keycodes
|
||||
for (int i = m_xkb->min_key_code; i <= m_xkb->max_key_code; ++i) {
|
||||
KeyCode keycode = static_cast<KeyCode>(i);
|
||||
if (XkbKeyHasActions(m_xkb, keycode)) {
|
||||
// iterate over all groups
|
||||
int numGroups = XkbKeyNumGroups(m_xkb, keycode);
|
||||
for (int group = 0; group < numGroups; ++group) {
|
||||
// iterate over all shift levels for the button (including none)
|
||||
XkbKeyTypePtr type = XkbKeyKeyType(m_xkb, keycode, group);
|
||||
for (int j = -1; j < type->map_count; ++j) {
|
||||
if (j != -1 && !type->map[j].active) {
|
||||
continue;
|
||||
}
|
||||
int level = ((j == -1) ? 0 : type->map[j].level);
|
||||
XkbAction* action =
|
||||
XkbKeyActionEntry(m_xkb, keycode, level, group);
|
||||
if (action->type == XkbSA_SetMods ||
|
||||
action->type == XkbSA_LockMods) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
int
|
||||
CXWindowsKeyState::getEffectiveGroup(KeyCode keycode, int group) const
|
||||
{
|
||||
(void)keycode;
|
||||
#if HAVE_XKB_EXTENSION
|
||||
// get effective group for key
|
||||
int numGroups = XkbKeyNumGroups(m_xkb, keycode);
|
||||
if (group >= numGroups) {
|
||||
unsigned char groupInfo = XkbKeyGroupInfo(m_xkb, keycode);
|
||||
switch (XkbOutOfRangeGroupAction(groupInfo)) {
|
||||
case XkbClampIntoRange:
|
||||
group = numGroups - 1;
|
||||
break;
|
||||
|
||||
case XkbRedirectIntoRange:
|
||||
group = XkbOutOfRangeGroupNumber(groupInfo);
|
||||
if (group >= numGroups) {
|
||||
group = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// wrap
|
||||
group %= numGroups;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return group;
|
||||
}
|
||||
|
||||
UInt32
|
||||
CXWindowsKeyState::getGroupFromState(unsigned int state) const
|
||||
{
|
||||
#if HAVE_XKB_EXTENSION
|
||||
if (m_xkb != NULL) {
|
||||
return XkbGroupForCoreState(state);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
155
lib/platform/CXWindowsKeyState.h
Normal file
155
lib/platform/CXWindowsKeyState.h
Normal file
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2003 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.
|
||||
*/
|
||||
|
||||
#ifndef CXWINDOWSKEYSTATE_H
|
||||
#define CXWINDOWSKEYSTATE_H
|
||||
|
||||
#include "CKeyState.h"
|
||||
#include "stdmap.h"
|
||||
#include "stdvector.h"
|
||||
#if X_DISPLAY_MISSING
|
||||
# error X11 is required to build synergy
|
||||
#else
|
||||
# include <X11/Xlib.h>
|
||||
# if HAVE_X11_EXTENSIONS_XTEST_H
|
||||
# include <X11/extensions/XTest.h>
|
||||
# else
|
||||
# error The XTest extension is required to build synergy
|
||||
# endif
|
||||
# if HAVE_XKB_EXTENSION
|
||||
# include <X11/extensions/XKBstr.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
//! X Windows key state
|
||||
/*!
|
||||
A key state for X Windows.
|
||||
*/
|
||||
class CXWindowsKeyState : public CKeyState {
|
||||
public:
|
||||
typedef std::vector<int> CKeycodeList;
|
||||
enum {
|
||||
kGroupPoll = -1,
|
||||
kGroupPollAndSet = -2
|
||||
};
|
||||
|
||||
CXWindowsKeyState(Display*, bool useXKB);
|
||||
~CXWindowsKeyState();
|
||||
|
||||
//! @name modifiers
|
||||
//@{
|
||||
|
||||
//! Set active group
|
||||
/*!
|
||||
Sets the active group to \p group. This is the group returned by
|
||||
\c pollActiveGroup(). If \p group is \c kGroupPoll then
|
||||
\c pollActiveGroup() will really poll, but that's a slow operation
|
||||
on X11. If \p group is \c kGroupPollAndSet then this will poll the
|
||||
active group now and use it for future calls to \c pollActiveGroup().
|
||||
*/
|
||||
void setActiveGroup(SInt32 group);
|
||||
|
||||
//! Set the auto-repeat state
|
||||
/*!
|
||||
Sets the auto-repeat state.
|
||||
*/
|
||||
void setAutoRepeat(const XKeyboardState&);
|
||||
|
||||
//@}
|
||||
//! @name accessors
|
||||
//@{
|
||||
|
||||
//! Convert X modifier mask to synergy mask
|
||||
/*!
|
||||
Returns the synergy modifier mask corresponding to the X modifier
|
||||
mask in \p state.
|
||||
*/
|
||||
KeyModifierMask mapModifiersFromX(unsigned int state) const;
|
||||
|
||||
//! Convert synergy modifier mask to X mask
|
||||
/*!
|
||||
Converts the synergy modifier mask to the corresponding X modifier
|
||||
mask. Returns \c true if successful and \c false if any modifier
|
||||
could not be converted.
|
||||
*/
|
||||
bool mapModifiersToX(KeyModifierMask, unsigned int&) const;
|
||||
|
||||
//! Convert synergy key to all corresponding X keycodes
|
||||
/*!
|
||||
Converts the synergy key \p key to all of the keycodes that map to
|
||||
that key.
|
||||
*/
|
||||
void mapKeyToKeycodes(KeyID key,
|
||||
CKeycodeList& keycodes) const;
|
||||
|
||||
//@}
|
||||
|
||||
// IKeyState overrides
|
||||
virtual bool fakeCtrlAltDel();
|
||||
virtual KeyModifierMask
|
||||
pollActiveModifiers() const;
|
||||
virtual SInt32 pollActiveGroup() const;
|
||||
virtual void pollPressedKeys(KeyButtonSet& pressedKeys) const;
|
||||
|
||||
protected:
|
||||
// CKeyState overrides
|
||||
virtual void getKeyMap(CKeyMap& keyMap);
|
||||
virtual void fakeKey(const Keystroke& keystroke);
|
||||
|
||||
private:
|
||||
void updateKeysymMap(CKeyMap&);
|
||||
void updateKeysymMapXKB(CKeyMap&);
|
||||
bool hasModifiersXKB() const;
|
||||
int getEffectiveGroup(KeyCode, int group) const;
|
||||
UInt32 getGroupFromState(unsigned int state) const;
|
||||
|
||||
static void remapKeyModifiers(KeyID, SInt32,
|
||||
CKeyMap::KeyItem&, void*);
|
||||
|
||||
private:
|
||||
struct XKBModifierInfo {
|
||||
public:
|
||||
unsigned char m_level;
|
||||
UInt32 m_mask;
|
||||
bool m_lock;
|
||||
};
|
||||
|
||||
typedef std::vector<KeyModifierMask> KeyModifierMaskList;
|
||||
typedef std::map<KeyModifierMask, unsigned int> KeyModifierToXMask;
|
||||
typedef std::multimap<KeyID, KeyCode> KeyToKeyCodeMap;
|
||||
typedef std::map<KeyCode, unsigned int> NonXKBModifierMap;
|
||||
typedef std::map<UInt32, XKBModifierInfo> XKBModifierMap;
|
||||
|
||||
Display* m_display;
|
||||
#if HAVE_XKB_EXTENSION
|
||||
XkbDescPtr m_xkb;
|
||||
#endif
|
||||
SInt32 m_group;
|
||||
XKBModifierMap m_lastGoodXKBModifiers;
|
||||
NonXKBModifierMap m_lastGoodNonXKBModifiers;
|
||||
|
||||
// X modifier (bit number) to synergy modifier (mask) mapping
|
||||
KeyModifierMaskList m_modifierFromX;
|
||||
|
||||
// synergy modifier (mask) to X modifier (mask)
|
||||
KeyModifierToXMask m_modifierToX;
|
||||
|
||||
// map KeyID to all keycodes that can synthesize that KeyID
|
||||
KeyToKeyCodeMap m_keyCodeFromKey;
|
||||
|
||||
// autorepeat state
|
||||
XKeyboardState m_keyboardState;
|
||||
};
|
||||
|
||||
#endif
|
||||
1901
lib/platform/CXWindowsScreen.cpp
Normal file
1901
lib/platform/CXWindowsScreen.cpp
Normal file
File diff suppressed because it is too large
Load Diff
229
lib/platform/CXWindowsScreen.h
Normal file
229
lib/platform/CXWindowsScreen.h
Normal file
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 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.
|
||||
*/
|
||||
|
||||
#ifndef CXWINDOWSSCREEN_H
|
||||
#define CXWINDOWSSCREEN_H
|
||||
|
||||
#include "CPlatformScreen.h"
|
||||
#include "stdset.h"
|
||||
#include "stdvector.h"
|
||||
#if X_DISPLAY_MISSING
|
||||
# error X11 is required to build synergy
|
||||
#else
|
||||
# include <X11/Xlib.h>
|
||||
#endif
|
||||
|
||||
class CXWindowsClipboard;
|
||||
class CXWindowsKeyState;
|
||||
class CXWindowsScreenSaver;
|
||||
|
||||
//! Implementation of IPlatformScreen for X11
|
||||
class CXWindowsScreen : public CPlatformScreen {
|
||||
public:
|
||||
CXWindowsScreen(const char* displayName, bool isPrimary);
|
||||
virtual ~CXWindowsScreen();
|
||||
|
||||
//! @name manipulators
|
||||
//@{
|
||||
|
||||
//@}
|
||||
|
||||
// IScreen overrides
|
||||
virtual void* getEventTarget() const;
|
||||
virtual bool getClipboard(ClipboardID id, IClipboard*) const;
|
||||
virtual void getShape(SInt32& x, SInt32& y,
|
||||
SInt32& width, SInt32& height) const;
|
||||
virtual void getCursorPos(SInt32& x, SInt32& y) const;
|
||||
|
||||
// IPrimaryScreen overrides
|
||||
virtual void reconfigure(UInt32 activeSides);
|
||||
virtual void warpCursor(SInt32 x, SInt32 y);
|
||||
virtual UInt32 registerHotKey(KeyID key, KeyModifierMask mask);
|
||||
virtual void unregisterHotKey(UInt32 id);
|
||||
virtual void fakeInputBegin();
|
||||
virtual void fakeInputEnd();
|
||||
virtual SInt32 getJumpZoneSize() const;
|
||||
virtual bool isAnyMouseButtonDown() const;
|
||||
virtual void getCursorCenter(SInt32& x, SInt32& y) const;
|
||||
|
||||
// ISecondaryScreen overrides
|
||||
virtual void fakeMouseButton(ButtonID id, bool press) const;
|
||||
virtual void fakeMouseMove(SInt32 x, SInt32 y) const;
|
||||
virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const;
|
||||
virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const;
|
||||
|
||||
// IPlatformScreen overrides
|
||||
virtual void enable();
|
||||
virtual void disable();
|
||||
virtual void enter();
|
||||
virtual bool leave();
|
||||
virtual bool setClipboard(ClipboardID, const IClipboard*);
|
||||
virtual void checkClipboards();
|
||||
virtual void openScreensaver(bool notify);
|
||||
virtual void closeScreensaver();
|
||||
virtual void screensaver(bool activate);
|
||||
virtual void resetOptions();
|
||||
virtual void setOptions(const COptionsList& options);
|
||||
virtual void setSequenceNumber(UInt32);
|
||||
virtual bool isPrimary() const;
|
||||
|
||||
protected:
|
||||
// IPlatformScreen overrides
|
||||
virtual void handleSystemEvent(const CEvent&, void*);
|
||||
virtual void updateButtons();
|
||||
virtual IKeyState* getKeyState() const;
|
||||
|
||||
private:
|
||||
// event sending
|
||||
void sendEvent(CEvent::Type, void* = NULL);
|
||||
void sendClipboardEvent(CEvent::Type, ClipboardID);
|
||||
|
||||
// create the transparent cursor
|
||||
Cursor createBlankCursor() const;
|
||||
|
||||
// determine the clipboard from the X selection. returns
|
||||
// kClipboardEnd if no such clipboard.
|
||||
ClipboardID getClipboardID(Atom selection) const;
|
||||
|
||||
// continue processing a selection request
|
||||
void processClipboardRequest(Window window,
|
||||
Time time, Atom property);
|
||||
|
||||
// terminate a selection request
|
||||
void destroyClipboardRequest(Window window);
|
||||
|
||||
// X I/O error handler
|
||||
void onError();
|
||||
static int ioErrorHandler(Display*);
|
||||
|
||||
private:
|
||||
class CKeyEventFilter {
|
||||
public:
|
||||
int m_event;
|
||||
Window m_window;
|
||||
Time m_time;
|
||||
KeyCode m_keycode;
|
||||
};
|
||||
|
||||
Display* openDisplay(const char* displayName);
|
||||
void saveShape();
|
||||
Window openWindow() const;
|
||||
void openIM();
|
||||
|
||||
bool grabMouseAndKeyboard();
|
||||
void onKeyPress(XKeyEvent&);
|
||||
void onKeyRelease(XKeyEvent&, bool isRepeat);
|
||||
bool onHotKey(XKeyEvent&, bool isRepeat);
|
||||
void onMousePress(const XButtonEvent&);
|
||||
void onMouseRelease(const XButtonEvent&);
|
||||
void onMouseMove(const XMotionEvent&);
|
||||
|
||||
void selectEvents(Window) const;
|
||||
void doSelectEvents(Window) const;
|
||||
|
||||
KeyID mapKeyFromX(XKeyEvent*) const;
|
||||
ButtonID mapButtonFromX(const XButtonEvent*) const;
|
||||
unsigned int mapButtonToX(ButtonID id) const;
|
||||
|
||||
void warpCursorNoFlush(SInt32 x, SInt32 y);
|
||||
|
||||
void refreshKeyboard(XEvent*);
|
||||
|
||||
static Bool findKeyEvent(Display*, XEvent* xevent, XPointer arg);
|
||||
|
||||
private:
|
||||
struct CHotKeyItem {
|
||||
public:
|
||||
CHotKeyItem(int, unsigned int);
|
||||
|
||||
bool operator<(const CHotKeyItem&) const;
|
||||
|
||||
private:
|
||||
int m_keycode;
|
||||
unsigned int m_mask;
|
||||
};
|
||||
typedef std::set<bool> CFilteredKeycodes;
|
||||
typedef std::vector<std::pair<int, unsigned int> > HotKeyList;
|
||||
typedef std::map<UInt32, HotKeyList> HotKeyMap;
|
||||
typedef std::vector<UInt32> HotKeyIDList;
|
||||
typedef std::map<CHotKeyItem, UInt32> HotKeyToIDMap;
|
||||
|
||||
// true if screen is being used as a primary screen, false otherwise
|
||||
bool m_isPrimary;
|
||||
|
||||
Display* m_display;
|
||||
Window m_root;
|
||||
Window m_window;
|
||||
|
||||
// true if mouse has entered the screen
|
||||
bool m_isOnScreen;
|
||||
|
||||
// screen shape stuff
|
||||
SInt32 m_x, m_y;
|
||||
SInt32 m_w, m_h;
|
||||
SInt32 m_xCenter, m_yCenter;
|
||||
|
||||
// last mouse position
|
||||
SInt32 m_xCursor, m_yCursor;
|
||||
|
||||
// keyboard stuff
|
||||
CXWindowsKeyState* m_keyState;
|
||||
|
||||
// hot key stuff
|
||||
HotKeyMap m_hotKeys;
|
||||
HotKeyIDList m_oldHotKeyIDs;
|
||||
HotKeyToIDMap m_hotKeyToIDMap;
|
||||
|
||||
// input focus stuff
|
||||
Window m_lastFocus;
|
||||
int m_lastFocusRevert;
|
||||
|
||||
// input method stuff
|
||||
XIM m_im;
|
||||
XIC m_ic;
|
||||
KeyCode m_lastKeycode;
|
||||
CFilteredKeycodes m_filtered;
|
||||
|
||||
// clipboards
|
||||
CXWindowsClipboard* m_clipboard[kClipboardEnd];
|
||||
UInt32 m_sequenceNumber;
|
||||
|
||||
// screen saver stuff
|
||||
CXWindowsScreenSaver* m_screensaver;
|
||||
bool m_screensaverNotify;
|
||||
|
||||
// logical to physical button mapping. m_buttons[i] gives the
|
||||
// physical button for logical button i+1.
|
||||
std::vector<unsigned char> m_buttons;
|
||||
|
||||
// true if global auto-repeat was enabled before we turned it off
|
||||
bool m_autoRepeat;
|
||||
|
||||
// stuff to workaround xtest being xinerama unaware. attempting
|
||||
// to fake a mouse motion under xinerama may behave strangely,
|
||||
// especially if screen 0 is not at 0,0 or if faking a motion on
|
||||
// a screen other than screen 0.
|
||||
bool m_xtestIsXineramaUnaware;
|
||||
bool m_xinerama;
|
||||
|
||||
// XKB extension stuff
|
||||
bool m_xkb;
|
||||
int m_xkbEventBase;
|
||||
|
||||
// pointer to (singleton) screen. this is only needed by
|
||||
// ioErrorHandler().
|
||||
static CXWindowsScreen* s_screen;
|
||||
};
|
||||
|
||||
#endif
|
||||
598
lib/platform/CXWindowsScreenSaver.cpp
Normal file
598
lib/platform/CXWindowsScreenSaver.cpp
Normal file
@@ -0,0 +1,598 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 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 "CXWindowsScreenSaver.h"
|
||||
#include "CXWindowsUtil.h"
|
||||
#include "IPlatformScreen.h"
|
||||
#include "CLog.h"
|
||||
#include "CEvent.h"
|
||||
#include "IEventQueue.h"
|
||||
#include "TMethodEventJob.h"
|
||||
#include <X11/Xatom.h>
|
||||
#if HAVE_X11_EXTENSIONS_XTEST_H
|
||||
# include <X11/extensions/XTest.h>
|
||||
#else
|
||||
# error The XTest extension is required to build synergy
|
||||
#endif
|
||||
#if HAVE_X11_EXTENSIONS_DPMS_H
|
||||
extern "C" {
|
||||
# include <X11/Xmd.h>
|
||||
# include <X11/extensions/dpms.h>
|
||||
# if !HAVE_DPMS_PROTOTYPES
|
||||
# undef DPMSModeOn
|
||||
# undef DPMSModeStandby
|
||||
# undef DPMSModeSuspend
|
||||
# undef DPMSModeOff
|
||||
# define DPMSModeOn 0
|
||||
# define DPMSModeStandby 1
|
||||
# define DPMSModeSuspend 2
|
||||
# define DPMSModeOff 3
|
||||
extern Bool DPMSQueryExtension(Display *, int *, int *);
|
||||
extern Bool DPMSCapable(Display *);
|
||||
extern Status DPMSEnable(Display *);
|
||||
extern Status DPMSDisable(Display *);
|
||||
extern Status DPMSForceLevel(Display *, CARD16);
|
||||
extern Status DPMSInfo(Display *, CARD16 *, BOOL *);
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
// CXWindowsScreenSaver
|
||||
//
|
||||
|
||||
CXWindowsScreenSaver::CXWindowsScreenSaver(
|
||||
Display* display, Window window, void* eventTarget) :
|
||||
m_display(display),
|
||||
m_xscreensaverSink(window),
|
||||
m_eventTarget(eventTarget),
|
||||
m_xscreensaver(None),
|
||||
m_xscreensaverActive(false),
|
||||
m_dpms(false),
|
||||
m_disabled(false),
|
||||
m_suppressDisable(false),
|
||||
m_disableTimer(NULL),
|
||||
m_disablePos(0)
|
||||
{
|
||||
// get atoms
|
||||
m_atomScreenSaver = XInternAtom(m_display,
|
||||
"SCREENSAVER", False);
|
||||
m_atomScreenSaverVersion = XInternAtom(m_display,
|
||||
"_SCREENSAVER_VERSION", False);
|
||||
m_atomScreenSaverActivate = XInternAtom(m_display,
|
||||
"ACTIVATE", False);
|
||||
m_atomScreenSaverDeactivate = XInternAtom(m_display,
|
||||
"DEACTIVATE", False);
|
||||
|
||||
// check for DPMS extension. this is an alternative screen saver
|
||||
// that powers down the display.
|
||||
#if HAVE_X11_EXTENSIONS_DPMS_H
|
||||
int eventBase, errorBase;
|
||||
if (DPMSQueryExtension(m_display, &eventBase, &errorBase)) {
|
||||
if (DPMSCapable(m_display)) {
|
||||
// we have DPMS
|
||||
m_dpms = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// watch top-level windows for changes
|
||||
bool error = false;
|
||||
{
|
||||
CXWindowsUtil::CErrorLock lock(m_display, &error);
|
||||
Window root = DefaultRootWindow(m_display);
|
||||
XWindowAttributes attr;
|
||||
XGetWindowAttributes(m_display, root, &attr);
|
||||
m_rootEventMask = attr.your_event_mask;
|
||||
XSelectInput(m_display, root, m_rootEventMask | SubstructureNotifyMask);
|
||||
}
|
||||
if (error) {
|
||||
LOG((CLOG_DEBUG "didn't set root event mask"));
|
||||
m_rootEventMask = 0;
|
||||
}
|
||||
|
||||
// get the built-in settings
|
||||
XGetScreenSaver(m_display, &m_timeout, &m_interval,
|
||||
&m_preferBlanking, &m_allowExposures);
|
||||
|
||||
// get the DPMS settings
|
||||
m_dpmsEnabled = isDPMSEnabled();
|
||||
|
||||
// get the xscreensaver window, if any
|
||||
if (!findXScreenSaver()) {
|
||||
setXScreenSaver(None);
|
||||
}
|
||||
|
||||
// install disable timer event handler
|
||||
EVENTQUEUE->adoptHandler(CEvent::kTimer, this,
|
||||
new TMethodEventJob<CXWindowsScreenSaver>(this,
|
||||
&CXWindowsScreenSaver::handleDisableTimer));
|
||||
}
|
||||
|
||||
CXWindowsScreenSaver::~CXWindowsScreenSaver()
|
||||
{
|
||||
// done with disable job
|
||||
if (m_disableTimer != NULL) {
|
||||
EVENTQUEUE->deleteTimer(m_disableTimer);
|
||||
}
|
||||
EVENTQUEUE->removeHandler(CEvent::kTimer, this);
|
||||
|
||||
if (m_display != NULL) {
|
||||
enableDPMS(m_dpmsEnabled);
|
||||
XSetScreenSaver(m_display, m_timeout, m_interval,
|
||||
m_preferBlanking, m_allowExposures);
|
||||
clearWatchForXScreenSaver();
|
||||
CXWindowsUtil::CErrorLock lock(m_display);
|
||||
XSelectInput(m_display, DefaultRootWindow(m_display), m_rootEventMask);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsScreenSaver::destroy()
|
||||
{
|
||||
m_display = NULL;
|
||||
delete this;
|
||||
}
|
||||
|
||||
bool
|
||||
CXWindowsScreenSaver::handleXEvent(const XEvent* xevent)
|
||||
{
|
||||
switch (xevent->type) {
|
||||
case CreateNotify:
|
||||
if (m_xscreensaver == None) {
|
||||
if (isXScreenSaver(xevent->xcreatewindow.window)) {
|
||||
// found the xscreensaver
|
||||
setXScreenSaver(xevent->xcreatewindow.window);
|
||||
}
|
||||
else {
|
||||
// another window to watch. to detect the xscreensaver
|
||||
// window we look for a property but that property may
|
||||
// not yet exist by the time we get this event so we
|
||||
// have to watch the window for property changes.
|
||||
// this would be so much easier if xscreensaver did the
|
||||
// smart thing and stored its window in a property on
|
||||
// the root window.
|
||||
addWatchXScreenSaver(xevent->xcreatewindow.window);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DestroyNotify:
|
||||
if (xevent->xdestroywindow.window == m_xscreensaver) {
|
||||
// xscreensaver is gone
|
||||
LOG((CLOG_DEBUG "xscreensaver died"));
|
||||
setXScreenSaver(None);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case PropertyNotify:
|
||||
if (xevent->xproperty.state == PropertyNewValue) {
|
||||
if (isXScreenSaver(xevent->xproperty.window)) {
|
||||
// found the xscreensaver
|
||||
setXScreenSaver(xevent->xcreatewindow.window);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MapNotify:
|
||||
if (xevent->xmap.window == m_xscreensaver) {
|
||||
// xscreensaver has activated
|
||||
setXScreenSaverActive(true);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case UnmapNotify:
|
||||
if (xevent->xunmap.window == m_xscreensaver) {
|
||||
// xscreensaver has deactivated
|
||||
setXScreenSaverActive(false);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsScreenSaver::enable()
|
||||
{
|
||||
// for xscreensaver
|
||||
m_disabled = false;
|
||||
updateDisableTimer();
|
||||
|
||||
// for built-in X screen saver
|
||||
XSetScreenSaver(m_display, m_timeout, m_interval,
|
||||
m_preferBlanking, m_allowExposures);
|
||||
|
||||
// for DPMS
|
||||
enableDPMS(m_dpmsEnabled);
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsScreenSaver::disable()
|
||||
{
|
||||
// for xscreensaver
|
||||
m_disabled = true;
|
||||
updateDisableTimer();
|
||||
|
||||
// use built-in X screen saver
|
||||
XGetScreenSaver(m_display, &m_timeout, &m_interval,
|
||||
&m_preferBlanking, &m_allowExposures);
|
||||
XSetScreenSaver(m_display, 0, m_interval,
|
||||
m_preferBlanking, m_allowExposures);
|
||||
|
||||
// for DPMS
|
||||
m_dpmsEnabled = isDPMSEnabled();
|
||||
enableDPMS(false);
|
||||
|
||||
// FIXME -- now deactivate?
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsScreenSaver::activate()
|
||||
{
|
||||
// remove disable job timer
|
||||
m_suppressDisable = true;
|
||||
updateDisableTimer();
|
||||
|
||||
// enable DPMS if it was enabled
|
||||
enableDPMS(m_dpmsEnabled);
|
||||
|
||||
// try xscreensaver
|
||||
findXScreenSaver();
|
||||
if (m_xscreensaver != None) {
|
||||
sendXScreenSaverCommand(m_atomScreenSaverActivate);
|
||||
return;
|
||||
}
|
||||
|
||||
// try built-in X screen saver
|
||||
if (m_timeout != 0) {
|
||||
XForceScreenSaver(m_display, ScreenSaverActive);
|
||||
}
|
||||
|
||||
// try DPMS
|
||||
activateDPMS(true);
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsScreenSaver::deactivate()
|
||||
{
|
||||
// reinstall disable job timer
|
||||
m_suppressDisable = false;
|
||||
updateDisableTimer();
|
||||
|
||||
// try DPMS
|
||||
activateDPMS(false);
|
||||
|
||||
// disable DPMS if screen saver is disabled
|
||||
if (m_disabled) {
|
||||
enableDPMS(false);
|
||||
}
|
||||
|
||||
// try xscreensaver
|
||||
findXScreenSaver();
|
||||
if (m_xscreensaver != None) {
|
||||
sendXScreenSaverCommand(m_atomScreenSaverDeactivate);
|
||||
return;
|
||||
}
|
||||
|
||||
// use built-in X screen saver
|
||||
XForceScreenSaver(m_display, ScreenSaverReset);
|
||||
}
|
||||
|
||||
bool
|
||||
CXWindowsScreenSaver::isActive() const
|
||||
{
|
||||
// check xscreensaver
|
||||
if (m_xscreensaver != None) {
|
||||
return m_xscreensaverActive;
|
||||
}
|
||||
|
||||
// check DPMS
|
||||
if (isDPMSActivated()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// can't check built-in X screen saver activity
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
CXWindowsScreenSaver::findXScreenSaver()
|
||||
{
|
||||
// do nothing if we've already got the xscreensaver window
|
||||
if (m_xscreensaver == None) {
|
||||
// find top-level window xscreensaver window
|
||||
Window root = DefaultRootWindow(m_display);
|
||||
Window rw, pw, *cw;
|
||||
unsigned int nc;
|
||||
if (XQueryTree(m_display, root, &rw, &pw, &cw, &nc)) {
|
||||
for (unsigned int i = 0; i < nc; ++i) {
|
||||
if (isXScreenSaver(cw[i])) {
|
||||
setXScreenSaver(cw[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
XFree(cw);
|
||||
}
|
||||
}
|
||||
|
||||
return (m_xscreensaver != None);
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsScreenSaver::setXScreenSaver(Window window)
|
||||
{
|
||||
LOG((CLOG_DEBUG "xscreensaver window: 0x%08x", window));
|
||||
|
||||
// save window
|
||||
m_xscreensaver = window;
|
||||
|
||||
if (m_xscreensaver != None) {
|
||||
// clear old watch list
|
||||
clearWatchForXScreenSaver();
|
||||
|
||||
// see if xscreensaver is active
|
||||
bool error = false;
|
||||
XWindowAttributes attr;
|
||||
{
|
||||
CXWindowsUtil::CErrorLock lock(m_display, &error);
|
||||
XGetWindowAttributes(m_display, m_xscreensaver, &attr);
|
||||
}
|
||||
setXScreenSaverActive(!error && attr.map_state != IsUnmapped);
|
||||
|
||||
// save current DPMS state; xscreensaver may have changed it.
|
||||
m_dpmsEnabled = isDPMSEnabled();
|
||||
}
|
||||
else {
|
||||
// screen saver can't be active if it doesn't exist
|
||||
setXScreenSaverActive(false);
|
||||
|
||||
// start watching for xscreensaver
|
||||
watchForXScreenSaver();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CXWindowsScreenSaver::isXScreenSaver(Window w) const
|
||||
{
|
||||
// check for m_atomScreenSaverVersion string property
|
||||
Atom type;
|
||||
return (CXWindowsUtil::getWindowProperty(m_display, w,
|
||||
m_atomScreenSaverVersion,
|
||||
NULL, &type, NULL, False) &&
|
||||
type == XA_STRING);
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsScreenSaver::setXScreenSaverActive(bool activated)
|
||||
{
|
||||
if (m_xscreensaverActive != activated) {
|
||||
LOG((CLOG_DEBUG "xscreensaver %s on window 0x%08x", activated ? "activated" : "deactivated", m_xscreensaver));
|
||||
m_xscreensaverActive = activated;
|
||||
|
||||
// if screen saver was activated forcefully (i.e. against
|
||||
// our will) then just accept it. don't try to keep it
|
||||
// from activating since that'll just pop up the password
|
||||
// dialog if locking is enabled.
|
||||
m_suppressDisable = activated;
|
||||
updateDisableTimer();
|
||||
|
||||
if (activated) {
|
||||
EVENTQUEUE->addEvent(CEvent(
|
||||
IPlatformScreen::getScreensaverActivatedEvent(),
|
||||
m_eventTarget));
|
||||
}
|
||||
else {
|
||||
EVENTQUEUE->addEvent(CEvent(
|
||||
IPlatformScreen::getScreensaverDeactivatedEvent(),
|
||||
m_eventTarget));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsScreenSaver::sendXScreenSaverCommand(Atom cmd, long arg1, long arg2)
|
||||
{
|
||||
XEvent event;
|
||||
event.xclient.type = ClientMessage;
|
||||
event.xclient.display = m_display;
|
||||
event.xclient.window = m_xscreensaverSink;
|
||||
event.xclient.message_type = m_atomScreenSaver;
|
||||
event.xclient.format = 32;
|
||||
event.xclient.data.l[0] = static_cast<long>(cmd);
|
||||
event.xclient.data.l[1] = arg1;
|
||||
event.xclient.data.l[2] = arg2;
|
||||
event.xclient.data.l[3] = 0;
|
||||
event.xclient.data.l[4] = 0;
|
||||
|
||||
LOG((CLOG_DEBUG "send xscreensaver command: %d %d %d", (long)cmd, arg1, arg2));
|
||||
bool error = false;
|
||||
{
|
||||
CXWindowsUtil::CErrorLock lock(m_display, &error);
|
||||
XSendEvent(m_display, m_xscreensaver, False, 0, &event);
|
||||
}
|
||||
if (error) {
|
||||
findXScreenSaver();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsScreenSaver::watchForXScreenSaver()
|
||||
{
|
||||
// clear old watch list
|
||||
clearWatchForXScreenSaver();
|
||||
|
||||
// add every child of the root to the list of windows to watch
|
||||
Window root = DefaultRootWindow(m_display);
|
||||
Window rw, pw, *cw;
|
||||
unsigned int nc;
|
||||
if (XQueryTree(m_display, root, &rw, &pw, &cw, &nc)) {
|
||||
for (unsigned int i = 0; i < nc; ++i) {
|
||||
addWatchXScreenSaver(cw[i]);
|
||||
}
|
||||
XFree(cw);
|
||||
}
|
||||
|
||||
// now check for xscreensaver window in case it set the property
|
||||
// before we could request property change events.
|
||||
if (findXScreenSaver()) {
|
||||
// found it so clear out our watch list
|
||||
clearWatchForXScreenSaver();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsScreenSaver::clearWatchForXScreenSaver()
|
||||
{
|
||||
// stop watching all windows
|
||||
CXWindowsUtil::CErrorLock lock(m_display);
|
||||
for (CWatchList::iterator index = m_watchWindows.begin();
|
||||
index != m_watchWindows.end(); ++index) {
|
||||
XSelectInput(m_display, index->first, index->second);
|
||||
}
|
||||
m_watchWindows.clear();
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsScreenSaver::addWatchXScreenSaver(Window window)
|
||||
{
|
||||
// get window attributes
|
||||
bool error = false;
|
||||
XWindowAttributes attr;
|
||||
{
|
||||
CXWindowsUtil::CErrorLock lock(m_display, &error);
|
||||
XGetWindowAttributes(m_display, window, &attr);
|
||||
}
|
||||
|
||||
// if successful and window uses override_redirect (like xscreensaver
|
||||
// does) then watch it for property changes.
|
||||
if (!error && attr.override_redirect == True) {
|
||||
error = false;
|
||||
{
|
||||
CXWindowsUtil::CErrorLock lock(m_display, &error);
|
||||
XSelectInput(m_display, window,
|
||||
attr.your_event_mask | PropertyChangeMask);
|
||||
}
|
||||
if (!error) {
|
||||
// if successful then add the window to our list
|
||||
m_watchWindows.insert(std::make_pair(window, attr.your_event_mask));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsScreenSaver::updateDisableTimer()
|
||||
{
|
||||
if (m_disabled && !m_suppressDisable && m_disableTimer == NULL) {
|
||||
// 5 seconds should be plenty often to suppress the screen saver
|
||||
m_disableTimer = EVENTQUEUE->newTimer(5.0, this);
|
||||
}
|
||||
else if ((!m_disabled || m_suppressDisable) && m_disableTimer != NULL) {
|
||||
EVENTQUEUE->deleteTimer(m_disableTimer);
|
||||
m_disableTimer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsScreenSaver::handleDisableTimer(const CEvent&, void*)
|
||||
{
|
||||
// send fake mouse motion directly to xscreensaver
|
||||
if (m_xscreensaver != None) {
|
||||
XEvent event;
|
||||
event.xmotion.type = MotionNotify;
|
||||
event.xmotion.display = m_display;
|
||||
event.xmotion.window = m_xscreensaver;
|
||||
event.xmotion.root = DefaultRootWindow(m_display);
|
||||
event.xmotion.subwindow = None;
|
||||
event.xmotion.time = CurrentTime;
|
||||
event.xmotion.x = m_disablePos;
|
||||
event.xmotion.y = 0;
|
||||
event.xmotion.x_root = m_disablePos;
|
||||
event.xmotion.y_root = 0;
|
||||
event.xmotion.state = 0;
|
||||
event.xmotion.is_hint = NotifyNormal;
|
||||
event.xmotion.same_screen = True;
|
||||
|
||||
CXWindowsUtil::CErrorLock lock(m_display);
|
||||
XSendEvent(m_display, m_xscreensaver, False, 0, &event);
|
||||
|
||||
m_disablePos = 20 - m_disablePos;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsScreenSaver::activateDPMS(bool activate)
|
||||
{
|
||||
#if HAVE_X11_EXTENSIONS_DPMS_H
|
||||
if (m_dpms) {
|
||||
// DPMSForceLevel will generate a BadMatch if DPMS is disabled
|
||||
CXWindowsUtil::CErrorLock lock(m_display);
|
||||
DPMSForceLevel(m_display, activate ? DPMSModeStandby : DPMSModeOn);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsScreenSaver::enableDPMS(bool enable)
|
||||
{
|
||||
#if HAVE_X11_EXTENSIONS_DPMS_H
|
||||
if (m_dpms) {
|
||||
if (enable) {
|
||||
DPMSEnable(m_display);
|
||||
}
|
||||
else {
|
||||
DPMSDisable(m_display);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
CXWindowsScreenSaver::isDPMSEnabled() const
|
||||
{
|
||||
#if HAVE_X11_EXTENSIONS_DPMS_H
|
||||
if (m_dpms) {
|
||||
CARD16 level;
|
||||
BOOL state;
|
||||
DPMSInfo(m_display, &level, &state);
|
||||
return (state != False);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
CXWindowsScreenSaver::isDPMSActivated() const
|
||||
{
|
||||
#if HAVE_X11_EXTENSIONS_DPMS_H
|
||||
if (m_dpms) {
|
||||
CARD16 level;
|
||||
BOOL state;
|
||||
DPMSInfo(m_display, &level, &state);
|
||||
return (level != DPMSModeOn);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
164
lib/platform/CXWindowsScreenSaver.h
Normal file
164
lib/platform/CXWindowsScreenSaver.h
Normal file
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 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.
|
||||
*/
|
||||
|
||||
#ifndef CXWINDOWSSCREENSAVER_H
|
||||
#define CXWINDOWSSCREENSAVER_H
|
||||
|
||||
#include "IScreenSaver.h"
|
||||
#include "stdmap.h"
|
||||
#if X_DISPLAY_MISSING
|
||||
# error X11 is required to build synergy
|
||||
#else
|
||||
# include <X11/Xlib.h>
|
||||
#endif
|
||||
|
||||
class CEvent;
|
||||
class CEventQueueTimer;
|
||||
|
||||
//! X11 screen saver implementation
|
||||
class CXWindowsScreenSaver : public IScreenSaver {
|
||||
public:
|
||||
CXWindowsScreenSaver(Display*, Window, void* eventTarget);
|
||||
virtual ~CXWindowsScreenSaver();
|
||||
|
||||
//! @name manipulators
|
||||
//@{
|
||||
|
||||
//! Event filtering
|
||||
/*!
|
||||
Should be called for each system event before event translation and
|
||||
dispatch. Returns true to skip translation and dispatch.
|
||||
*/
|
||||
bool handleXEvent(const XEvent*);
|
||||
|
||||
//! Destroy without the display
|
||||
/*!
|
||||
Tells this object to delete itself without using the X11 display.
|
||||
It may leak some resources as a result.
|
||||
*/
|
||||
void destroy();
|
||||
|
||||
//@}
|
||||
|
||||
// IScreenSaver overrides
|
||||
virtual void enable();
|
||||
virtual void disable();
|
||||
virtual void activate();
|
||||
virtual void deactivate();
|
||||
virtual bool isActive() const;
|
||||
|
||||
private:
|
||||
// find and set the running xscreensaver's window. returns true iff
|
||||
// found.
|
||||
bool findXScreenSaver();
|
||||
|
||||
// set the xscreensaver's window, updating the activation state flag
|
||||
void setXScreenSaver(Window);
|
||||
|
||||
// returns true if the window appears to be the xscreensaver window
|
||||
bool isXScreenSaver(Window) const;
|
||||
|
||||
// set xscreensaver's activation state flag. sends notification
|
||||
// if the state has changed.
|
||||
void setXScreenSaverActive(bool activated);
|
||||
|
||||
// send a command to xscreensaver
|
||||
void sendXScreenSaverCommand(Atom, long = 0, long = 0);
|
||||
|
||||
// watch all windows that could potentially be the xscreensaver for
|
||||
// the events that will confirm it.
|
||||
void watchForXScreenSaver();
|
||||
|
||||
// stop watching all watched windows
|
||||
void clearWatchForXScreenSaver();
|
||||
|
||||
// add window to the watch list
|
||||
void addWatchXScreenSaver(Window window);
|
||||
|
||||
// install/uninstall the job used to suppress the screensaver
|
||||
void updateDisableTimer();
|
||||
|
||||
// called periodically to prevent the screen saver from starting
|
||||
void handleDisableTimer(const CEvent&, void*);
|
||||
|
||||
// force DPMS to activate or deactivate
|
||||
void activateDPMS(bool activate);
|
||||
|
||||
// enable/disable DPMS screen saver
|
||||
void enableDPMS(bool);
|
||||
|
||||
// check if DPMS is enabled
|
||||
bool isDPMSEnabled() const;
|
||||
|
||||
// check if DPMS is activate
|
||||
bool isDPMSActivated() const;
|
||||
|
||||
private:
|
||||
typedef std::map<Window, long> CWatchList;
|
||||
|
||||
// the X display
|
||||
Display* m_display;
|
||||
|
||||
// window to receive xscreensaver repsonses
|
||||
Window m_xscreensaverSink;
|
||||
|
||||
// the target for the events we generate
|
||||
void* m_eventTarget;
|
||||
|
||||
// xscreensaver's window
|
||||
Window m_xscreensaver;
|
||||
|
||||
// xscreensaver activation state
|
||||
bool m_xscreensaverActive;
|
||||
|
||||
// old event mask on root window
|
||||
long m_rootEventMask;
|
||||
|
||||
// potential xscreensaver windows being watched
|
||||
CWatchList m_watchWindows;
|
||||
|
||||
// atoms used to communicate with xscreensaver's window
|
||||
Atom m_atomScreenSaver;
|
||||
Atom m_atomScreenSaverVersion;
|
||||
Atom m_atomScreenSaverActivate;
|
||||
Atom m_atomScreenSaverDeactivate;
|
||||
|
||||
// built-in screen saver settings
|
||||
int m_timeout;
|
||||
int m_interval;
|
||||
int m_preferBlanking;
|
||||
int m_allowExposures;
|
||||
|
||||
// DPMS screen saver settings
|
||||
bool m_dpms;
|
||||
bool m_dpmsEnabled;
|
||||
|
||||
// true iff the client wants the screen saver suppressed
|
||||
bool m_disabled;
|
||||
|
||||
// true iff we're ignoring m_disabled. this is true, for example,
|
||||
// when the client has called activate() and so presumably wants
|
||||
// to activate the screen saver even if disabled.
|
||||
bool m_suppressDisable;
|
||||
|
||||
// the disable timer (NULL if not installed)
|
||||
CEventQueueTimer* m_disableTimer;
|
||||
|
||||
// fake mouse motion position for suppressing the screen saver.
|
||||
// xscreensaver since 2.21 requires the mouse to move more than 10
|
||||
// pixels to be considered significant.
|
||||
SInt32 m_disablePos;
|
||||
};
|
||||
|
||||
#endif
|
||||
1766
lib/platform/CXWindowsUtil.cpp
Normal file
1766
lib/platform/CXWindowsUtil.cpp
Normal file
File diff suppressed because it is too large
Load Diff
185
lib/platform/CXWindowsUtil.h
Normal file
185
lib/platform/CXWindowsUtil.h
Normal file
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2002 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.
|
||||
*/
|
||||
|
||||
#ifndef CXWINDOWSUTIL_H
|
||||
#define CXWINDOWSUTIL_H
|
||||
|
||||
#include "CString.h"
|
||||
#include "BasicTypes.h"
|
||||
#include "stdmap.h"
|
||||
#include "stdvector.h"
|
||||
#if X_DISPLAY_MISSING
|
||||
# error X11 is required to build synergy
|
||||
#else
|
||||
# include <X11/Xlib.h>
|
||||
#endif
|
||||
|
||||
//! X11 utility functions
|
||||
class CXWindowsUtil {
|
||||
public:
|
||||
typedef std::vector<KeySym> KeySyms;
|
||||
|
||||
//! Get property
|
||||
/*!
|
||||
Gets property \c property on \c window. \b Appends the data to
|
||||
\c *data if \c data is not NULL, saves the property type in \c *type
|
||||
if \c type is not NULL, and saves the property format in \c *format
|
||||
if \c format is not NULL. If \c deleteProperty is true then the
|
||||
property is deleted after being read.
|
||||
*/
|
||||
static bool getWindowProperty(Display*,
|
||||
Window window, Atom property,
|
||||
CString* data, Atom* type,
|
||||
SInt32* format, bool deleteProperty);
|
||||
|
||||
//! Set property
|
||||
/*!
|
||||
Sets property \c property on \c window to \c size bytes of data from
|
||||
\c data.
|
||||
*/
|
||||
static bool setWindowProperty(Display*,
|
||||
Window window, Atom property,
|
||||
const void* data, UInt32 size,
|
||||
Atom type, SInt32 format);
|
||||
|
||||
//! Get X server time
|
||||
/*!
|
||||
Returns the current X server time.
|
||||
*/
|
||||
static Time getCurrentTime(Display*, Window);
|
||||
|
||||
//! Convert KeySym to KeyID
|
||||
/*!
|
||||
Converts a KeySym to the equivalent KeyID. Returns kKeyNone if the
|
||||
KeySym cannot be mapped.
|
||||
*/
|
||||
static UInt32 mapKeySymToKeyID(KeySym);
|
||||
|
||||
//! Convert KeySym to corresponding KeyModifierMask
|
||||
/*!
|
||||
Converts a KeySym to the corresponding KeyModifierMask, or 0 if the
|
||||
KeySym is not a modifier.
|
||||
*/
|
||||
static UInt32 getModifierBitForKeySym(KeySym keysym);
|
||||
|
||||
//! Convert Atom to its string
|
||||
/*!
|
||||
Converts \p atom to its string representation.
|
||||
*/
|
||||
static CString atomToString(Display*, Atom atom);
|
||||
|
||||
//! Convert several Atoms to a string
|
||||
/*!
|
||||
Converts each atom in \p atoms to its string representation and
|
||||
concatenates the results.
|
||||
*/
|
||||
static CString atomsToString(Display* display,
|
||||
const Atom* atom, UInt32 num);
|
||||
|
||||
//! Prepare a property of atoms for use
|
||||
/*!
|
||||
64-bit systems may need to modify a property's data if it's a
|
||||
list of Atoms before using it.
|
||||
*/
|
||||
static void convertAtomProperty(CString& data);
|
||||
|
||||
//! Append an Atom to property data
|
||||
/*!
|
||||
Converts \p atom to a 32-bit on-the-wire format and appends it to
|
||||
\p data.
|
||||
*/
|
||||
static void appendAtomData(CString& data, Atom atom);
|
||||
|
||||
//! Replace an Atom in property data
|
||||
/*!
|
||||
Converts \p atom to a 32-bit on-the-wire format and replaces the atom
|
||||
at index \p index in \p data.
|
||||
*/
|
||||
static void replaceAtomData(CString& data,
|
||||
UInt32 index, Atom atom);
|
||||
|
||||
//! Append an Time to property data
|
||||
/*!
|
||||
Converts \p time to a 32-bit on-the-wire format and appends it to
|
||||
\p data.
|
||||
*/
|
||||
static void appendTimeData(CString& data, Time time);
|
||||
|
||||
//! X11 error handler
|
||||
/*!
|
||||
This class sets an X error handler in the c'tor and restores the
|
||||
previous error handler in the d'tor. A lock should only be
|
||||
installed while the display is locked by the thread.
|
||||
|
||||
CErrorLock() ignores errors
|
||||
CErrorLock(bool* flag) sets *flag to true if any error occurs
|
||||
*/
|
||||
class CErrorLock {
|
||||
public:
|
||||
//! Error handler type
|
||||
typedef void (*ErrorHandler)(Display*, XErrorEvent*, void* userData);
|
||||
|
||||
/*!
|
||||
Ignore X11 errors.
|
||||
*/
|
||||
CErrorLock(Display*);
|
||||
|
||||
/*!
|
||||
Set \c *errorFlag if any error occurs.
|
||||
*/
|
||||
CErrorLock(Display*, bool* errorFlag);
|
||||
|
||||
/*!
|
||||
Call \c handler on each error.
|
||||
*/
|
||||
CErrorLock(Display*, ErrorHandler handler, void* userData);
|
||||
|
||||
~CErrorLock();
|
||||
|
||||
private:
|
||||
void install(ErrorHandler, void*);
|
||||
static int internalHandler(Display*, XErrorEvent*);
|
||||
static void ignoreHandler(Display*, XErrorEvent*, void*);
|
||||
static void saveHandler(Display*, XErrorEvent*, void*);
|
||||
|
||||
private:
|
||||
typedef int (*XErrorHandler)(Display*, XErrorEvent*);
|
||||
|
||||
Display* m_display;
|
||||
ErrorHandler m_handler;
|
||||
void* m_userData;
|
||||
XErrorHandler m_oldXHandler;
|
||||
CErrorLock* m_next;
|
||||
static CErrorLock* s_top;
|
||||
};
|
||||
|
||||
private:
|
||||
class CPropertyNotifyPredicateInfo {
|
||||
public:
|
||||
Window m_window;
|
||||
Atom m_property;
|
||||
};
|
||||
|
||||
static Bool propertyNotifyPredicate(Display*,
|
||||
XEvent* xevent, XPointer arg);
|
||||
|
||||
static void initKeyMaps();
|
||||
|
||||
private:
|
||||
typedef std::map<KeySym, UInt32> CKeySymMap;
|
||||
|
||||
static CKeySymMap s_keySymToUCS4;
|
||||
};
|
||||
|
||||
#endif
|
||||
123
lib/platform/Makefile.am
Normal file
123
lib/platform/Makefile.am
Normal file
@@ -0,0 +1,123 @@
|
||||
# synergy -- mouse and keyboard sharing utility
|
||||
# Copyright (C) 2002 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.
|
||||
|
||||
## Process this file with automake to produce Makefile.in
|
||||
NULL =
|
||||
|
||||
XWINDOWS_SOURCE_FILES = \
|
||||
CXWindowsClipboard.cpp \
|
||||
CXWindowsClipboardAnyBitmapConverter.cpp\
|
||||
CXWindowsClipboardBMPConverter.cpp \
|
||||
CXWindowsClipboardHTMLConverter.cpp \
|
||||
CXWindowsClipboardTextConverter.cpp \
|
||||
CXWindowsClipboardUCS2Converter.cpp \
|
||||
CXWindowsClipboardUTF8Converter.cpp \
|
||||
CXWindowsEventQueueBuffer.cpp \
|
||||
CXWindowsKeyState.cpp \
|
||||
CXWindowsScreen.cpp \
|
||||
CXWindowsScreenSaver.cpp \
|
||||
CXWindowsUtil.cpp \
|
||||
CXWindowsClipboard.h \
|
||||
CXWindowsClipboardAnyBitmapConverter.h \
|
||||
CXWindowsClipboardBMPConverter.h \
|
||||
CXWindowsClipboardHTMLConverter.h \
|
||||
CXWindowsClipboardTextConverter.h \
|
||||
CXWindowsClipboardUCS2Converter.h \
|
||||
CXWindowsClipboardUTF8Converter.h \
|
||||
CXWindowsEventQueueBuffer.h \
|
||||
CXWindowsKeyState.h \
|
||||
CXWindowsScreen.h \
|
||||
CXWindowsScreenSaver.h \
|
||||
CXWindowsUtil.h \
|
||||
$(NULL)
|
||||
MSWINDOWS_SOURCE_FILES = \
|
||||
CMSWindowsClipboard.cpp \
|
||||
CMSWindowsClipboardAnyTextConverter.cpp \
|
||||
CMSWindowsClipboardBitmapConverter.cpp \
|
||||
CMSWindowsClipboardHTMLConverter.cpp \
|
||||
CMSWindowsClipboardTextConverter.cpp \
|
||||
CMSWindowsClipboardUTF16Converter.cpp \
|
||||
CMSWindowsDesks.cpp \
|
||||
CMSWindowsEventQueueBuffer.cpp \
|
||||
CMSWindowsKeyState.cpp \
|
||||
CMSWindowsScreen.cpp \
|
||||
CMSWindowsScreenSaver.cpp \
|
||||
CMSWindowsUtil.cpp \
|
||||
CMSWindowsClipboard.h \
|
||||
CMSWindowsClipboardAnyTextConverter.h \
|
||||
CMSWindowsClipboardBitmapConverter.h \
|
||||
CMSWindowsClipboardHTMLConverter.h \
|
||||
CMSWindowsClipboardTextConverter.h \
|
||||
CMSWindowsClipboardUTF16Converter.h \
|
||||
CMSWindowsDesks.h \
|
||||
CMSWindowsEventQueueBuffer.h \
|
||||
CMSWindowsKeyState.h \
|
||||
CMSWindowsScreen.h \
|
||||
CMSWindowsScreenSaver.h \
|
||||
CMSWindowsUtil.h \
|
||||
$(NULL)
|
||||
MSWINDOWS_HOOK_SOURCE_FILES = \
|
||||
CSynergyHook.cpp \
|
||||
CSynergyHook.h \
|
||||
$(NULL)
|
||||
CARBON_SOURCE_FILES = \
|
||||
COSXClipboard.cpp \
|
||||
COSXClipboardAnyTextConverter.cpp \
|
||||
COSXClipboardTextConverter.cpp \
|
||||
COSXClipboardUTF16Converter.cpp \
|
||||
COSXEventQueueBuffer.cpp \
|
||||
COSXKeyState.cpp \
|
||||
COSXScreen.cpp \
|
||||
COSXScreenSaver.cpp \
|
||||
COSXScreenSaverUtil.m \
|
||||
COSXClipboard.h \
|
||||
COSXClipboardAnyTextConverter.h \
|
||||
COSXClipboardTextConverter.h \
|
||||
COSXClipboardUTF16Converter.h \
|
||||
COSXEventQueueBuffer.h \
|
||||
COSXKeyState.h \
|
||||
COSXScreen.h \
|
||||
COSXScreenSaver.h \
|
||||
COSXScreenSaverUtil.h \
|
||||
OSXScreenSaverControl.h \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DIST = \
|
||||
Makefile.win \
|
||||
$(XWINDOWS_SOURCE_FILES) \
|
||||
$(MSWINDOWS_SOURCE_FILES) \
|
||||
$(MSWINDOWS_HOOK_SOURCE_FILES) \
|
||||
$(CARBON_SOURCE_FILES) \
|
||||
$(NULL)
|
||||
|
||||
MAINTAINERCLEANFILES = \
|
||||
Makefile.in \
|
||||
$(NULL)
|
||||
|
||||
noinst_LIBRARIES = libplatform.a
|
||||
if XWINDOWS
|
||||
libplatform_a_SOURCES = $(XWINDOWS_SOURCE_FILES)
|
||||
endif
|
||||
if MSWINDOWS
|
||||
libplatform_a_SOURCES = $(MSWINDOWS_SOURCE_FILES)
|
||||
endif
|
||||
if CARBON
|
||||
libplatform_a_SOURCES = $(CARBON_SOURCE_FILES)
|
||||
endif
|
||||
INCLUDES = \
|
||||
-I$(top_srcdir)/lib/common \
|
||||
-I$(top_srcdir)/lib/arch \
|
||||
-I$(top_srcdir)/lib/base \
|
||||
-I$(top_srcdir)/lib/mt \
|
||||
-I$(top_srcdir)/lib/io \
|
||||
-I$(top_srcdir)/lib/synergy \
|
||||
$(NULL)
|
||||
119
lib/platform/Makefile.win
Normal file
119
lib/platform/Makefile.win
Normal file
@@ -0,0 +1,119 @@
|
||||
# synergy -- mouse and keyboard sharing utility
|
||||
# Copyright (C) 2007 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.
|
||||
|
||||
LIB_PLATFORM_SRC = lib\platform
|
||||
LIB_PLATFORM_DST = $(BUILD_DST)\$(LIB_PLATFORM_SRC)
|
||||
LIB_PLATFORM_LIB = "$(LIB_PLATFORM_DST)\platform.lib"
|
||||
LIB_PLATFORM_CPP = \
|
||||
"CMSWindowsClipboard.cpp" \
|
||||
"CMSWindowsClipboardAnyTextConverter.cpp" \
|
||||
"CMSWindowsClipboardBitmapConverter.cpp" \
|
||||
"CMSWindowsClipboardHTMLConverter.cpp" \
|
||||
"CMSWindowsClipboardTextConverter.cpp" \
|
||||
"CMSWindowsClipboardUTF16Converter.cpp" \
|
||||
"CMSWindowsDesks.cpp" \
|
||||
"CMSWindowsEventQueueBuffer.cpp" \
|
||||
"CMSWindowsKeyState.cpp" \
|
||||
"CMSWindowsScreen.cpp" \
|
||||
"CMSWindowsScreenSaver.cpp" \
|
||||
"CMSWindowsUtil.cpp" \
|
||||
$(NULL)
|
||||
LIB_PLATFORM_OBJ = \
|
||||
"$(LIB_PLATFORM_DST)\CMSWindowsClipboard.obj" \
|
||||
"$(LIB_PLATFORM_DST)\CMSWindowsClipboardAnyTextConverter.obj" \
|
||||
"$(LIB_PLATFORM_DST)\CMSWindowsClipboardBitmapConverter.obj" \
|
||||
"$(LIB_PLATFORM_DST)\CMSWindowsClipboardHTMLConverter.obj" \
|
||||
"$(LIB_PLATFORM_DST)\CMSWindowsClipboardTextConverter.obj" \
|
||||
"$(LIB_PLATFORM_DST)\CMSWindowsClipboardUTF16Converter.obj" \
|
||||
"$(LIB_PLATFORM_DST)\CMSWindowsDesks.obj" \
|
||||
"$(LIB_PLATFORM_DST)\CMSWindowsEventQueueBuffer.obj" \
|
||||
"$(LIB_PLATFORM_DST)\CMSWindowsKeyState.obj" \
|
||||
"$(LIB_PLATFORM_DST)\CMSWindowsScreen.obj" \
|
||||
"$(LIB_PLATFORM_DST)\CMSWindowsScreenSaver.obj" \
|
||||
"$(LIB_PLATFORM_DST)\CMSWindowsUtil.obj" \
|
||||
$(NULL)
|
||||
LIB_PLATFORM_HOOK_CPP = \
|
||||
"$(LIB_PLATFORM_SRC)\CSynergyHook.cpp" \
|
||||
$(NULL)
|
||||
LIB_PLATFORM_HOOK_OBJ = \
|
||||
"$(LIB_PLATFORM_DST)\CSynergyHook.obj" \
|
||||
$(NULL)
|
||||
LIB_PLATFORM_HOOK_DLL = "$(BUILD_DST)\synrgyhk.dll"
|
||||
LIB_PLATFORM_INC = \
|
||||
/I"lib\common" \
|
||||
/I"lib\arch" \
|
||||
/I"lib\base" \
|
||||
/I"lib\mt" \
|
||||
/I"lib\io" \
|
||||
/I"lib\net" \
|
||||
/I"lib\synergy" \
|
||||
$(NULL)
|
||||
|
||||
CPP_FILES = $(CPP_FILES) $(LIB_PLATFORM_CPP)
|
||||
OBJ_FILES = $(OBJ_FILES) $(LIB_PLATFORM_OBJ)
|
||||
LIB_FILES = $(LIB_FILES) $(LIB_PLATFORM_LIB) $(LIB_PLATFORM_HOOK_DLL)
|
||||
|
||||
# Hook should be as small as possible.
|
||||
cpphookdebug = $(cppdebug:-Ox=-O1)
|
||||
|
||||
# Don't do security checks or run time error checking on hook.
|
||||
cpphookflags = $(cppflags:-GS=)
|
||||
cpphookdebug = $(cpphookdebug:/GZ=)
|
||||
cpphookdebug = $(cpphookdebug:/RTC1=)
|
||||
|
||||
# Dependency rules
|
||||
$(LIB_PLATFORM_OBJ): $(AUTODEP)
|
||||
!if EXIST($(LIB_PLATFORM_DST)\deps.mak)
|
||||
!include $(LIB_PLATFORM_DST)\deps.mak
|
||||
!endif
|
||||
|
||||
# Build rules. Use batch-mode rules if possible.
|
||||
!if DEFINED(_NMAKE_VER)
|
||||
{$(LIB_PLATFORM_SRC)\}.cpp{$(LIB_PLATFORM_DST)\}.obj::
|
||||
!else
|
||||
{$(LIB_PLATFORM_SRC)\}.cpp{$(LIB_PLATFORM_DST)\}.obj:
|
||||
!endif
|
||||
@$(ECHO) Compile in $(LIB_PLATFORM_SRC)
|
||||
-@$(MKDIR) $(LIB_PLATFORM_DST) 2>NUL:
|
||||
$(cpp) $(cppdebug) $(cppflags) $(cppvarsmt) /showIncludes \
|
||||
$(LIB_PLATFORM_INC) \
|
||||
/Fo$(LIB_PLATFORM_DST)\ \
|
||||
/Fd$(LIB_PLATFORM_LIB:.lib=.pdb) \
|
||||
$< | $(AUTODEP) $(LIB_PLATFORM_SRC) $(LIB_PLATFORM_DST)
|
||||
$(LIB_PLATFORM_LIB): $(LIB_PLATFORM_OBJ)
|
||||
@$(ECHO) Link $(@F)
|
||||
$(implib) $(ildebug) $(ilflags) \
|
||||
/out:$@ \
|
||||
$**
|
||||
$(AUTODEP) $(LIB_PLATFORM_SRC) $(LIB_PLATFORM_DST) \
|
||||
$(LIB_PLATFORM_OBJ:.obj=.d) $(LIB_PLATFORM_HOOK_OBJ:.obj=.d)
|
||||
|
||||
# Hook build rules
|
||||
$(LIB_PLATFORM_HOOK_OBJ): \
|
||||
$(LIB_PLATFORM_HOOK_CPP) $(LIB_PLATFORM_HOOK_CPP:.cpp=.h)
|
||||
@$(ECHO) Compile $(LIB_PLATFORM_HOOK_CPP)
|
||||
-@$(MKDIR) $(LIB_PLATFORM_DST) 2>NUL:
|
||||
$(cpp) $(cpphookdebug) $(cpphookflags) $(cppvarsmt) /showIncludes \
|
||||
-D_DLL -D_USRDLL -DSYNRGYHK_EXPORTS \
|
||||
$(LIB_PLATFORM_INC) \
|
||||
/Fo$(LIB_PLATFORM_DST)\ \
|
||||
/Fd$(@:.obj=.pdb) \
|
||||
$(LIB_PLATFORM_HOOK_CPP) | \
|
||||
$(AUTODEP) $(LIB_PLATFORM_SRC) $(LIB_PLATFORM_DST)
|
||||
$(LIB_PLATFORM_HOOK_DLL): $(LIB_PLATFORM_HOOK_OBJ)
|
||||
@$(ECHO) Link $(@F)
|
||||
$(link) $(ldebug) $(lflags) $(guilibsmt) \
|
||||
/entry:"DllMain$(DLLENTRY)" /dll \
|
||||
/out:$@ \
|
||||
$**
|
||||
$(AUTODEP) $(LIB_PLATFORM_SRC) $(LIB_PLATFORM_DST) \
|
||||
$(LIB_PLATFORM_OBJ:.obj=.d) $(LIB_PLATFORM_HOOK_OBJ:.obj=.d)
|
||||
36
lib/platform/OSXScreenSaverControl.h
Normal file
36
lib/platform/OSXScreenSaverControl.h
Normal file
@@ -0,0 +1,36 @@
|
||||
// ScreenSaver.framework private API
|
||||
// Class dumping by Alex Harper http://www.ragingmenace.com/
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
@protocol ScreenSaverControl
|
||||
- (double)screenSaverTimeRemaining;
|
||||
- (void)restartForUser:fp12;
|
||||
- (void)screenSaverStopNow;
|
||||
- (void)screenSaverStartNow;
|
||||
- (void)setScreenSaverCanRun:(char)fp12;
|
||||
- (BOOL)screenSaverCanRun;
|
||||
- (BOOL)screenSaverIsRunning;
|
||||
@end
|
||||
|
||||
|
||||
@interface ScreenSaverController:NSObject <ScreenSaverControl>
|
||||
|
||||
+ controller;
|
||||
+ monitor;
|
||||
+ daemonConnectionName;
|
||||
+ daemonPath;
|
||||
+ enginePath;
|
||||
- init;
|
||||
- (void)dealloc;
|
||||
- (void)_connectionClosed:fp12;
|
||||
- (BOOL)screenSaverIsRunning;
|
||||
- (BOOL)screenSaverCanRun;
|
||||
- (void)setScreenSaverCanRun:(char)fp12;
|
||||
- (void)screenSaverStartNow;
|
||||
- (void)screenSaverStopNow;
|
||||
- (void)restartForUser:fp12;
|
||||
- (double)screenSaverTimeRemaining;
|
||||
|
||||
@end
|
||||
|
||||
Reference in New Issue
Block a user