summaryrefslogtreecommitdiffstats
path: root/src/lib/platform/MSWindowsDesks.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/platform/MSWindowsDesks.h')
-rw-r--r--src/lib/platform/MSWindowsDesks.h297
1 files changed, 297 insertions, 0 deletions
diff --git a/src/lib/platform/MSWindowsDesks.h b/src/lib/platform/MSWindowsDesks.h
new file mode 100644
index 0000000..da93c34
--- /dev/null
+++ b/src/lib/platform/MSWindowsDesks.h
@@ -0,0 +1,297 @@
+/*
+ * barrier -- mouse and keyboard sharing utility
+ * Copyright (C) 2018 Debauchee Open Source Group
+ * Copyright (C) 2012-2016 Symless Ltd.
+ * 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 LICENSE that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "platform/synwinhk.h"
+#include "barrier/key_types.h"
+#include "barrier/mouse_types.h"
+#include "barrier/option_types.h"
+#include "mt/CondVar.h"
+#include "mt/Mutex.h"
+#include "base/String.h"
+#include "common/stdmap.h"
+
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+
+class Event;
+class EventQueueTimer;
+class Thread;
+class IJob;
+class IScreenSaver;
+class IEventQueue;
+
+//! 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. Barrier must deal with them mainly because of the login
+window and screensaver but users can create their own desks and
+barrier 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 MSWindowsDesks {
+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.
+ */
+ MSWindowsDesks(
+ bool isPrimary, bool noHooks,
+ const IScreenSaver* screensaver, IEventQueue* events,
+ IJob* updateKeys, bool stopOnDeskSwitch);
+ ~MSWindowsDesks();
+
+ //! @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 OptionsList& 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);
+
+ //! 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 Desk {
+ public:
+ String m_name;
+ Thread* m_thread;
+ DWORD m_threadID;
+ DWORD m_targetID;
+ HDESK m_desk;
+ HWND m_window;
+ HWND m_foregroundWindow;
+ bool m_lowLevel;
+ };
+ typedef std::map<String, Desk*> Desks;
+
+ // initialization and shutdown operations
+ 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(Desk* desk);
+ void deskLeave(Desk* desk, HKL keyLayout);
+ void deskThread(void* vdesk);
+
+ // desk switch checking and handling
+ Desk* addDesk(const String& name, HDESK hdesk);
+ void removeDesks();
+ void checkDesk();
+ bool isDeskAccessible(const Desk* desk) const;
+ void handleCheckDesk(const Event& 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);
+ String 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 hooks are not to be installed (useful for debugging)
+ bool m_noHooks;
+
+ // 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
+ EventQueueTimer* m_timer;
+
+ // screen saver stuff
+ DWORD m_threadID;
+ const IScreenSaver* m_screensaver;
+ bool m_screensaverNotify;
+
+ // the current desk and it's name
+ Desk* m_activeDesk;
+ String m_activeDeskName;
+
+ // one desk per desktop and a cond var to communicate with it
+ Mutex m_mutex;
+ CondVar<bool> m_deskReady;
+ Desks m_desks;
+
+ // keyboard stuff
+ IJob* m_updateKeys;
+ HKL m_keyLayout;
+
+ // options
+ bool m_leaveForegroundOption;
+
+ IEventQueue* m_events;
+
+ // true if program should stop on desk switch.
+ bool m_stopOnDeskSwitch;
+};