/***************************************************************************
                     keycapturedialog.cpp - KeyCaptureDialog
                             -------------------
    begin                : Wed Dec 25 01:20:22 CET 2002
    copyright            : (C) 2002-2003 by Tim Jansen
                           (C) unknown (whoever wrote kshortcutdialog.cpp)
                           (C) 2004 Nadeem Hasan <nhasan@kde.org>
    email                : tim@tjansen.de
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program 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 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

//
// based on key capture code from kdelibs/kdeui/kshortcutdialog.cpp
//

#include "keycapturedialog.h"
#include "keycapturewidget.h"

#include <qlabel.h>
#include <qlayout.h>

#include <klocale.h>

#define XK_XKB_KEYS
#define XK_MISCELLANY
#include <X11/Xlib.h>	// For x11Event()
#include <X11/keysymdef.h> // For XK_...

#ifdef KeyPress
const int XFocusOut = FocusOut;
const int XFocusIn = FocusIn;
const int XKeyPress = KeyPress;
const int XKeyRelease = KeyRelease;
#undef KeyRelease
#undef KeyPress
#undef FocusOut
#undef FocusIn
#endif


KeyCaptureDialog::KeyCaptureDialog(QWidget *parent, const char *name)
    : KDialogBase(parent, name, true, i18n( "Enter Key Combination" ),
      Cancel, Cancel, true), m_grabbed(false) {
  QFrame *main = makeMainWidget();
  QVBoxLayout *layout = new QVBoxLayout( main, 0, KDialog::spacingHint() );
  m_captureWidget = new KeyCaptureWidget( main, "m_captureWidget" );
  layout->addWidget( m_captureWidget );
  layout->addStretch();
}

KeyCaptureDialog::~KeyCaptureDialog() {
	if (m_grabbed)
		releaseKeyboard();
}

void KeyCaptureDialog::execute() {
	m_captureWidget->keyLabel->setText("");
	exec();
	if (m_grabbed)
		releaseKeyboard();
}

bool KeyCaptureDialog::x11Event(XEvent *pEvent)
{
	switch( pEvent->type ) {
		case XKeyPress:
		case XKeyRelease:
			x11EventKeyPress( pEvent );
			return true;
		case XFocusIn:
			if (!m_grabbed)
				grabKeyboard();
			return true;
		case XFocusOut:
			if (m_grabbed)
				releaseKeyboard();
			return true;
		default:
			break;
	}
	return QWidget::x11Event( pEvent );
}

void KeyCaptureDialog::x11EventKeyPress( XEvent *pEvent )
{
	// taken from kshortcutdialog.h
	KKeyNative keyNative( pEvent );
	uint keyModX = keyNative.mod(), keySymX = keyNative.sym();
	if ((keySymX == XK_Escape) && !keyModX) {
		accept();
		return;
	}

	switch( keySymX ) {
		// Don't allow setting a modifier key as an accelerator.
		// Also, don't release the focus yet.  We'll wait until
		//  we get a 'normal' key.
		case XK_Shift_L:   case XK_Shift_R:   keyModX = KKeyNative::modX(KKey::SHIFT); break;
		case XK_Control_L: case XK_Control_R: keyModX = KKeyNative::modX(KKey::CTRL); break;
		case XK_Alt_L:     case XK_Alt_R:     keyModX = KKeyNative::modX(KKey::ALT); break;
		// FIXME: check whether the Meta or Super key are for the Win modifier
		case XK_Meta_L:    case XK_Meta_R:
		case XK_Super_L:   case XK_Super_R:   keyModX = KKeyNative::modX(KKey::WIN); break;
		case XK_Hyper_L:   case XK_Hyper_R:
		case XK_Mode_switch:
		case XK_Num_Lock:
		case XK_Caps_Lock:
			break;
		default:
			if( pEvent->type == XKeyPress && keyNative.sym() ) {
				emit keyPressed(pEvent);
				reject();
			}
			return;
	}

	// If we are editing the first key in the sequence,
	//  display modifier keys which are held down
	if( pEvent->type == XKeyPress )
		keyModX |= pEvent->xkey.state;
	else
		keyModX = pEvent->xkey.state & ~keyModX;

	QString keyModStr;
	if( keyModX & KKeyNative::modX(KKey::WIN) )	keyModStr += KKey::modFlagLabel(KKey::WIN) + "+";
	if( keyModX & KKeyNative::modX(KKey::ALT) )	keyModStr += KKey::modFlagLabel(KKey::ALT) + "+";
	if( keyModX & KKeyNative::modX(KKey::CTRL) )	keyModStr += KKey::modFlagLabel(KKey::CTRL) + "+";
	if( keyModX & KKeyNative::modX(KKey::SHIFT) )	keyModStr += KKey::modFlagLabel(KKey::SHIFT) + "+";

	// Display currently selected modifiers, or redisplay old key.
	m_captureWidget->keyLabel->setText( keyModStr );
}

#include "keycapturedialog.moc"