/*
	Actionaz
	Copyright (C) 2008-2012 Jonathan Mercier-Ganady

	Actionaz is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	Actionaz 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/>.

	Contact : jmgr@jmgr.info
*/

#include "keyinput.h"
#include "keymapper.h"

#include <QKeyEvent>
#include <QKeySequence>
#include <QDebug>

#ifdef Q_WS_X11
#define XK_MISCELLANY
#define XK_LATIN1
#define XK_KOREAN
#define XK_XKB_KEYS
#include <X11/keysymdef.h>
#include <X11/XF86keysym.h>
#include <QX11Info>
#endif
#ifdef Q_WS_WIN
#include <Windows.h>
#endif

namespace ActionTools
{
	const StringListPair KeyInput::mKeyNames = qMakePair(
		QStringList() << "invalid" << "shiftLeft" << "shiftRight" << "controlLeft" << "controlRight" << "altLeft" << "altRight" << "metaLeft" << "metaRight" << "altGr"
		<< "numpad0" << "numpad1" << "numpad2" << "numpad3" << "numpad4" << "numpad5" << "numpad6" << "numpad7" << "numpad8" << "numpad9"
		<< "numpadMultiply" << "numpadAdd" << "numpadSeparator" << "numpadSubstract" << "numpadDecimal" << "numpadDivide",
		QStringList() << QString() << QObject::tr("Left Shift") << QObject::tr("Right Shift") << QObject::tr("Left Control") << QObject::tr("Right Control")
		<< QObject::tr("Left Alt") << QObject::tr("Right Alt")
#ifdef Q_WS_WIN
		<< QObject::tr("Left Windows") << QObject::tr("Right Windows")
#else
		<< QObject::tr("Left Meta") << QObject::tr("Right Meta")
#endif
		<< QObject::tr("Alt Gr") << QObject::tr("Numpad 0") << QObject::tr("Numpad 1") << QObject::tr("Numpad 2") << QObject::tr("Numpad 3") << QObject::tr("Numpad 4")
		<< QObject::tr("Numpad 5") << QObject::tr("Numpad 6") << QObject::tr("Numpad 7") << QObject::tr("Numpad 8") << QObject::tr("Numpad 9")
		<< QObject::tr("Numpad *") << QObject::tr("Numpad +") << QObject::tr("Numpad Separator") << QObject::tr("Numpad -") << QObject::tr("Numpad .") << QObject::tr("Numpad /")
	);

	bool KeyInput::mInitDone = false;
	unsigned long KeyInput::mNativeKey[] = {0};

	KeyInput::KeyInput()
		: mIsQtKey(false),
		mKey(InvalidKey)
	{
		init();
	}

	QString KeyInput::toTranslatedText() const
	{
		if(mIsQtKey)
		{
			QKeySequence keySequence(mKey);

			return keySequence.toString(QKeySequence::NativeText);
		}

		return mKeyNames.second[mKey];
	}

	QString KeyInput::toPortableText() const
	{
		if(mIsQtKey)
		{
			QKeySequence keySequence(mKey);

			return keySequence.toString(QKeySequence::PortableText);
		}

		return mKeyNames.first[mKey];
	}

	bool KeyInput::fromPortableText(const QString &key)
	{
		mIsQtKey = true;

		for(int i = 0; i < KeyCount; ++i)
		{
			if(mKeyNames.first[i] == key)
			{
				mKey = i;
				mIsQtKey = false;

				return true;
			}
		}

		QKeySequence keySequence(key);

		mKey = keySequence[0];
		mKey &= ~(Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier);

		return true;
	}

	bool KeyInput::fromPortableText(const QString &key, bool isQtKey)
	{
		mIsQtKey = isQtKey;

		if(mIsQtKey)
		{
			QKeySequence keySequence(key);

			mKey = keySequence[0];
			mKey &= ~(Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier);

			return true;
		}

		for(int i = 0; i < KeyCount; ++i)
		{
			if(mKeyNames.first[i] == key)
			{
				mKey = i;

				return true;
			}
		}

		return false;
	}

	bool KeyInput::fromEvent(QKeyEvent *event)
	{
		mIsQtKey = true;

		for(int i = 0; i < KeyCount; ++i)
		{
			if(event->nativeVirtualKey() == mNativeKey[i])
			{
				mKey = static_cast<Key>(i);
				mIsQtKey = false;
				break;
			}
		}

		switch(event->key())
		{
#ifdef Q_WS_WIN
		case Qt::Key_Shift:
		case Qt::Key_Control:
		case Qt::Key_Alt:
		case Qt::Key_Meta:
		case Qt::Key_AltGr:
			for(int i = 1; i < KeyCount; ++i)
			{
				if(HIBYTE(GetAsyncKeyState(mNativeKey[i])))
				{
					mKey = static_cast<Key>(i);

					mIsQtKey = false;
					break;
				}
			}
			break;
#endif
		default:
			break;
		}

		if(mIsQtKey)
		{
			if(event->modifiers() != Qt::NoModifier)
				return false;

			mKey = event->key();

			if(!KeyMapper::toNativeKey(static_cast<Qt::Key>(mKey)))
				return false;
		}
		else
		{
			if(!nativeKey(mKey))
				return false;
		}

		return true;
	}

	void KeyInput::init()
	{
		if(mInitDone)
			return;

		mInitDone = true;

		mNativeKey[InvalidKey] = 0;

#ifdef Q_WS_X11
		mNativeKey[ShiftLeft] = XK_Shift_L;
		mNativeKey[ShiftRight] = XK_Shift_R;
		mNativeKey[ControlLeft] = XK_Control_L;
		mNativeKey[ControlRight] = XK_Control_R;
		mNativeKey[AltLeft] = XK_Alt_L;
		mNativeKey[AltRight] = XK_Alt_R;
		mNativeKey[MetaLeft] = XK_Super_L;
		mNativeKey[MetaRight] = XK_Super_R;
		mNativeKey[AltGr] = XK_ISO_Level3_Shift;
		mNativeKey[Numpad0] = XK_KP_0;
		mNativeKey[Numpad1] = XK_KP_1;
		mNativeKey[Numpad2] = XK_KP_2;
		mNativeKey[Numpad3] = XK_KP_3;
		mNativeKey[Numpad4] = XK_KP_4;
		mNativeKey[Numpad5] = XK_KP_5;
		mNativeKey[Numpad6] = XK_KP_6;
		mNativeKey[Numpad7] = XK_KP_7;
		mNativeKey[Numpad8] = XK_KP_8;
		mNativeKey[Numpad9] = XK_KP_9;
		mNativeKey[NumpadMultiply] = XK_KP_Multiply;
		mNativeKey[NumpadAdd] = XK_KP_Add;
		mNativeKey[NumpadSeparator] = XK_KP_Separator;
		mNativeKey[NumpadSubstract] = XK_KP_Subtract;
		mNativeKey[NumpadDecimal] = XK_KP_Decimal;
		mNativeKey[NumpadDivide] = XK_KP_Divide;
#endif
#ifdef Q_WS_WIN
		mNativeKey[ShiftLeft] = VK_LSHIFT;
		mNativeKey[ShiftRight] = VK_RSHIFT;
		mNativeKey[ControlLeft] = VK_LCONTROL;
		mNativeKey[ControlRight] = VK_RCONTROL;
		mNativeKey[AltLeft] = VK_LMENU;
		mNativeKey[AltRight] = VK_RMENU;
		mNativeKey[MetaLeft] = VK_LWIN;
		mNativeKey[MetaRight] = VK_RWIN;
		mNativeKey[AltGr] = 0;
		mNativeKey[Numpad0] = VK_NUMPAD0;
		mNativeKey[Numpad1] = VK_NUMPAD1;
		mNativeKey[Numpad2] = VK_NUMPAD2;
		mNativeKey[Numpad3] = VK_NUMPAD3;
		mNativeKey[Numpad4] = VK_NUMPAD4;
		mNativeKey[Numpad5] = VK_NUMPAD5;
		mNativeKey[Numpad6] = VK_NUMPAD6;
		mNativeKey[Numpad7] = VK_NUMPAD7;
		mNativeKey[Numpad8] = VK_NUMPAD8;
		mNativeKey[Numpad9] = VK_NUMPAD9;
		mNativeKey[NumpadMultiply] = VK_MULTIPLY;
		mNativeKey[NumpadAdd] = VK_ADD;
		mNativeKey[NumpadSeparator] = VK_SEPARATOR;
		mNativeKey[NumpadSubstract] = VK_SUBTRACT;
		mNativeKey[NumpadDecimal] = VK_DECIMAL;
		mNativeKey[NumpadDivide] = VK_DIVIDE;
#endif
	}
}
