/*
 * synergy -- mouse and keyboard sharing utility
 * Copyright (C) 2003 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
 * 
 * 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef IKEYSTATE_H
#define IKEYSTATE_H

#include "IInterface.h"
#include "KeyTypes.h"
#include "CEvent.h"
#include "CString.h"
#include "stdset.h"
#include "IEventQueue.h"

//! Key state interface
/*!
This interface provides access to set and query the keyboard state and
to synthesize key events.
*/
class IKeyState : public IInterface {
public:
	IKeyState();
	IKeyState(IEventQueue& eventQueue);

	enum {
		kNumButtons = 0x200
	};

	//! Key event data
	class CKeyInfo {
	public:
		static CKeyInfo* alloc(KeyID, KeyModifierMask, KeyButton, SInt32 count);
		static CKeyInfo* alloc(KeyID, KeyModifierMask, KeyButton, SInt32 count,
							const std::set<CString>& destinations);
		static CKeyInfo* alloc(const CKeyInfo&);

		static bool isDefault(const char* screens);
		static bool contains(const char* screens, const CString& name);
		static bool equal(const CKeyInfo*, const CKeyInfo*);
		static CString join(const std::set<CString>& destinations);
		static void split(const char* screens, std::set<CString>&);

	public:
		KeyID			m_key;
		KeyModifierMask	m_mask;
		KeyButton		m_button;
		SInt32			m_count;
		char*			m_screens;
		char			m_screensBuffer[1];
	};

	typedef std::set<KeyButton> KeyButtonSet;

	//! @name manipulators
	//@{

	//! Update the keyboard map
	/*!
	Causes the key state to get updated to reflect the current keyboard
	mapping.
	*/
	virtual void		updateKeyMap() = 0;

	//! Update the key state
	/*!
	Causes the key state to get updated to reflect the physical keyboard
	state.
	*/
	virtual void		updateKeyState() = 0;

	//! Set half-duplex mask
	/*!
	Sets which modifier toggle keys are half-duplex.  A half-duplex
	toggle key doesn't report a key release when toggled on and
	doesn't report a key press when toggled off.
	*/
	virtual void		setHalfDuplexMask(KeyModifierMask) = 0;

	//! Fake a key press
	/*!
	Synthesizes a key press event and updates the key state.
	*/
	virtual void		fakeKeyDown(KeyID id, KeyModifierMask mask,
							KeyButton button) = 0;

	//! Fake a key repeat
	/*!
	Synthesizes a key repeat event and updates the key state.
	*/
	virtual bool		fakeKeyRepeat(KeyID id, KeyModifierMask mask,
							SInt32 count, KeyButton button) = 0;

	//! Fake a key release
	/*!
	Synthesizes a key release event and updates the key state.
	*/
	virtual bool		fakeKeyUp(KeyButton button) = 0;

	//! Fake key releases for all fake pressed keys
	/*!
	Synthesizes a key release event for every key that is synthetically
	pressed and updates the key state.
	*/
	virtual void		fakeAllKeysUp() = 0;

	//! Fake ctrl+alt+del
	/*!
	Synthesize a press of ctrl+alt+del.  Return true if processing is
	complete and false if normal key processing should continue.
	*/
	virtual bool		fakeCtrlAltDel() = 0;

	//@}
	//! @name accessors
	//@{

	//! Test if key is pressed
	/*!
	Returns true iff the given key is down.  Half-duplex toggles
	always return false.
	*/
	virtual bool		isKeyDown(KeyButton) const = 0;

	//! Get the active modifiers
	/*!
	Returns the modifiers that are currently active according to our
	shadowed state.
	*/
	virtual KeyModifierMask
						getActiveModifiers() const = 0;

	//! Get the active modifiers from OS
	/*!
	Returns the modifiers that are currently active according to the
	operating system.
	*/
	virtual KeyModifierMask
						pollActiveModifiers() const = 0;

	//! Get the active keyboard layout from OS
	/*!
	Returns the active keyboard layout according to the operating system.
	*/
	virtual SInt32		pollActiveGroup() const = 0;

	//! Get the keys currently pressed from OS
	/*!
	Adds any keys that are currently pressed according to the operating
	system to \p pressedKeys.
	*/
	virtual void		pollPressedKeys(KeyButtonSet& pressedKeys) const = 0;

	//! Get key down event type.  Event data is CKeyInfo*, count == 1.
	CEvent::Type		getKeyDownEvent() { return getKeyDownEvent(m_eventQueue); }

	//! Get key up event type.  Event data is CKeyInfo*, count == 1.
	CEvent::Type		getKeyUpEvent() { return getKeyUpEvent(m_eventQueue); }

	//! Get key repeat event type.  Event data is CKeyInfo*.
	CEvent::Type		getKeyRepeatEvent() { return getKeyRepeatEvent(m_eventQueue); }

	//! Get key down event type.  Event data is CKeyInfo*, count == 1.
	static CEvent::Type	getKeyDownEvent(IEventQueue& eventQueue);

	//! Get key up event type.  Event data is CKeyInfo*, count == 1.
	static CEvent::Type	getKeyUpEvent(IEventQueue& eventQueue);

	//! Get key repeat event type.  Event data is CKeyInfo*.
	static CEvent::Type	getKeyRepeatEvent(IEventQueue& eventQueue);

	//@}

protected:
	IEventQueue& getEventQueue() const { return m_eventQueue; }

private:
	static CEvent::Type	s_keyDownEvent;
	static CEvent::Type	s_keyUpEvent;
	static CEvent::Type	s_keyRepeatEvent;
	IEventQueue& m_eventQueue;
};

#endif
