/*
* Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:  Declares main application class.
 *
*/


#ifndef __KEYBOARD_H
#define __KEYBOARD_H

#include <e32std.h>
#include <w32std.h>
#include <e32event.h>
#include <aknkeylock.h>

#include "hidinterfaces.h"
#include "hidkeys.h"
#include "layoutmgr.h"
#include "timeoutnotifier.h"
#include "bthidsettings.h"

class CField;
class CHidKeyboardDriver;
class CTimeOutTimer;
/*!
 HID keyboard driver class
 */
class CHidKeyboardDriver : public CHidDriver, public MTimeOutNotifier
    {

private:
    /*! Initialisation states */
    enum TKeyboardDriverState
        {
        EUninitialised, /*!< Driver has not been initialised */
        EInitialised, /*!< Driver is initialised */
        EDisabled
        /*!< The driver will not respond to interrupt data */
        };

    // Flags indicating which locking keys are active
    enum TLockVals
        {
        ENumLock = 1, ECapsLock = 2, EScrollLock = 4
        };

    // The types of keyboard input report fields that we handle:
    enum TKeyFieldType
        {
        EStandardKeys = 0,
        EModifierKeys = 1,
        EMediaKeys = 2,
        EPowerKeys = 3,
        KNumInputFieldTypes
        };

public:
    // Constructors and destructor
    /*!
     Creates an instantiated CHidKeyboardDriver object.
     @param aHid The generic HID layer that requested the driver
     @param aFactory aFactory The factory that created the driver
     @result A pointer to the instantiated keyboard driver
     */
    static CHidKeyboardDriver* NewL(MDriverAccess* aHid);
    /*!
     Creates an instantiated CHidKeyboardDriver object and leaves it on the
     cleanup stack.
     @param aHid The generic HID layer that requested the driver
     @param aFactory aFactory The factory that created the driver
     @result A pointer to the instantiated keyboard driver
     */
    static CHidKeyboardDriver* NewLC(MDriverAccess* aHid);

    /*!
     Stops driver activity, deletes the key repeat and decode objects and closes
     the window server session before the driver is deleted
     */
    virtual ~CHidKeyboardDriver();

public:
    // new functions
    /*!
     Called by the Generic HID layer to see if the driver can is able to use
     reports from a newly-connected device
     @result ETrue The driver can handle the reports
     @result EFalse The driver cannot handle the reports
     */
    virtual TInt CanHandleReportL(CReportRoot* aReportRoot);

    /*!
     Called by the Generic HID layer when a device has been removed, prior to the
     driver being removed.  This allows the driver to notify any applications of
     disconnection, if required
     @param aReason The reason for device disconnection
     */
    virtual void Disconnected(TInt aReason);

    /*!
     Called by the Generic HID layer when data has been received from the device
     handled by this driver.
     @param aChannel The channel on which the data was received (as defined by the
     transport layer
     @param aPayload A pointer to the data buffer
     */
    virtual TInt DataIn(CHidTransport::THidChannelType aChannel,
            const TDesC8& aPayload);

    /*!
     Called by the transport layers to inform the generic HID of the success of
     the last Set... command.
     @param aConnectionId ID of the device
     @param aCmdAck Status of the last Set... command
     */
    virtual void CommandResult(TInt aCmdAck);

    /*!
     Called after a driver is sucessfully created by the Generic HID, when a
     device is connected
     */
    virtual void InitialiseL(TInt aConnectionId);

    /*!
     Resets the internal state of the driver (any pressed keys are released) and
     enables the driver
     */
    virtual void StartL(TInt aConnectionId);
    /*!
     Cancels all pressed keys and disables the driver (so it will not
     process interrupt data)
     */
    virtual void Stop();

    /**
     * Return count of supported fields
     *
     * @since S60 v5.0     
     * @return Number of supported fields.
     */
    virtual TInt SupportedFieldCount();

    /**
     * Set input handling registy 
     *
     * @since S60 v5.0     
     * @param aHandlingReg  a Input handling registry
     */
    virtual void SetInputHandlingReg(CHidInputDataHandlingReg* aHandlingReg);

    // ----------------------------------------
    // Repeat key timer interface:

    /*!
     Callback function for the key repeat timer to trigger a repeat key event.
     */
    TInt OnKeyRepeat();

    static TInt TimerFiredOnKeyRepeat(TAny* aThis);

private:
    // Constructors

    // Constructor taking a pointer to the HID layer requesting the driver
    // instance
    CHidKeyboardDriver(MDriverAccess* aHid);

    void ConstructL();

private:
    // Functions from base classes

    /**
     * From MTimeoutNotifier
     */
    void TimerExpired();
private:
    // New Functions

    // Called from within DataIn to handle interrupt and control channel data
    void InterruptData(const TDesC8& aPayload);

    // Send key down / key up events to the window server:
    void KeyEvent(TBool aIsKeyDown, TInt aHidKey, TInt aUsagePage);
    TKeyEvent TKeyEventFromScanCode(TInt aScanCode) const;
    inline void KeyUp(TInt aHidKey, TInt aUsagePage);
    inline void KeyDown(TInt aHidKey, TInt aUsagePage);

    // Handles the states of the modifier keys
    void UpdateModifiers(TInt aFieldIndex, const TDesC8& aReport);

    // Handle key presses
    void ProcessKeys(TInt aFieldIndex, const TDesC8& aReport);

    // Determines whether too many keys have been pressed on the device
    TBool IsRollover(TInt aFieldIndex, const TDesC8& aReport) const;

    // Get current modifier state in the format used by TKeyEvent
    TUint32 KeyEventModifiers() const;

    // Resets the internal keypress states and sends keyup events if required
    void CancelKeysForField(TInt aFieldIndex);
    void CancelAllKeys();

    // Determines whether any lock (Caps,Num,scroll) keys are pressed
    void UpdateLockState(TInt aKey);

    // Sets the LEDs on the keyboard according to the keyboard state
    // (Not implemented)
    void SetKeyboardLeds() const;

    // Send a key event to the system
    void SendKeyPress(TUint16 aUnicode, TInt aUsagePage, TInt aScanCode,
            TBool aIsRepeatingKey);

    void SendToWindowGroup(const TKeyEvent& aKeyEvent, TEventCode aType);
    void SendToWindowServer(TKeyEvent aKeyEvent);

    // Determine which window group a key event should be sent to.
    // Except for special cases this is the window group with the focus.
    TInt WindowGroupForKeyEvent(const TKeyEvent& aKeyEvent, TEventCode aType);

    // Handles the sending of raw events to the phone application instead of key events.
    void HandleTelephoneAppKeys(TInt aScanCode, TInt aUniCode,
            TBool aIsKeyDown);

    // Checks if application launching key combination and launch a corresponding application
    void HandleApplicationLaunchKeysL(TUint16 aScancodeKey, TBool aIsKeyDown,
            TUint8 aModifiers);

    /**
     * CHidKeyboardDriver::LaunchApplicationL
     * @param aAppUid Application UID
     */
    void LaunchApplicationL(TInt aAppUid);

    // Checks if multimedia-key (play,stop,..) and sends to RemCon
    TBool HandleKeyMapping(TDecodedKeyInfo& aKey, TBool aIsKeyDown,
            TUint8 aModifiers);
    TBool HandleKeyMappingUp(TDecodedKeyInfo& aKey, TBool aIsKeyDown,
            TUint8 aModifiers);
    TBool HandleKeyMappingDown(TDecodedKeyInfo& aKey, TBool aIsKeyDown,
            TUint8 aModifiers);
    TBool HandleKeyMappingLeft(TDecodedKeyInfo& aKey, TBool aIsKeyDown,
            TUint8 aModifiers);
    TBool HandleKeyMappingRight(TDecodedKeyInfo& aKey, TBool aIsKeyDown,
            TUint8 aModifiers);
    TBool HandleKeyMappingOther(TDecodedKeyInfo& aKey, TBool aIsKeyDown,
            TUint8 aModifiers);

    TInt AppMenuId();
    TInt PhoneAppId();
    TInt IdleAppId();
    TBool IsApplicationMenuTopMost();
    TBool IsPhoneAppTopMost();

    // bitmap for Multimedia key states
    enum TMmKeyDown
        {
        ENone       = 0x00,
        EVolUp      = 0x01,
        EVolDown    = 0x02,
        EPlay       = 0x04,
        EStop       = 0x08,
        ENext       = 0x10,
        EPrev       = 0x20,
        };
    
    // bitmap for navigation keys
    enum TNavKeyDown
        {
        ELsk        = 0x01,
        ERsk        = 0x02,
        ESend       = 0x04,
        EEnd        = 0x08,
        EEsc        = 0x10
        };

    void ResetBitmap(TBool aIsKeyDown, TMmKeyDown aBitmapToReset);

    /**
     * Send raw key event to window server
     * @param aScancode key scancode
     * @param aModifiers modifier
     * @return Error code
     */
    TInt SendRawEvent(TInt aScancode, TBool aIsKeyDown, TUint aModifier);

    // ----------------------------------------

    static TInt ResetArrayToSize(RArray<TInt>& aArray, TInt aSize);

    TBool IsDigitKey(TInt aScanCode);
    TBool IsSpecialHandleKey(TInt aUniCode);

private:

    TKeyboardDriverState iDriverState;

    // Application UIDs
    TInt iConnectionId;
    TInt iAppMenuId;
    TInt iPhoneAppId;
    TInt iIdleAppId;

    // The Generic HID layer
    MDriverAccess *iGenericHid;

    // Arrays of keys currently pressed for each field:
    RArray<TInt> iKeys[KNumInputFieldTypes];

    // Pointers to the fields in the report descriptor containing the
    // various types of key:
    const CField* iField[KNumInputFieldTypes];

    // Pointer to the field in the report descriptor containing the LEDs:
    const CField* iLedField;

    // The current modifier state
    TUint8 iModifiers;
    // The current locking key states
    TUint8 iLockState;
    //Supported field types count
    TInt iSupportedFieldCount;

    // A window server session, so keypresses can be sent to applications:
    RWsSession iWsSession;

    // Timer object so the driver can generate repeat keypresses:
    CPeriodic *iRepeatTimer;

    // The last keypress event sent to the window server (allows key repeat)
    TKeyEvent iLastKey;

    // Layout manager session:
    RLayoutManager iLayoutMgr;

    // Settings handler class
    CBtHidSettings* iSettings;

    /*! The last keyboard layout selected by the user */
    THidKeyboardLayoutId iLastSelectedLayout;

    // Flag for Multimedia key state
    TUint8 iMmKeyDown;

    CHidInputDataHandlingReg* iInputHandlingReg;

    // This timer stops key repeating after defined time to prevent endless key repeats in error cases. Fix for EMKD-7FBB9H
    CTimeOutTimer* iRepeatEndTimer;
    
    TUint8 iNavKeyDown;
    RAknKeyLock iKeyLock;
    };

// ----------------------------------------------------------------------
// Helpers for sending key events:

inline void CHidKeyboardDriver::KeyUp(TInt aHidKey, TInt aUsagePage)
    {
    KeyEvent(EFalse, aHidKey, aUsagePage);
    }

inline void CHidKeyboardDriver::KeyDown(TInt aHidKey, TInt aUsagePage)
    {
    KeyEvent(ETrue, aHidKey, aUsagePage);
    }

// ----------------------------------------------------------------------

#endif
