bsptemplate/asspandvariant/template_variant/specific/keyboard_interrupt.cpp
author Slion
Tue, 08 Dec 2009 08:11:42 +0100
branchanywhere
changeset 19 f6d3d9676ee4
parent 0 a41df078684a
child 62 4a8fed1c0ef6
permissions -rw-r--r--
Trying to figure out how to implement my WINC like compatibility layer. Going the emulation way is probably not so smart. We should not use the kernel but rather hook native functions in the Exec calls.

// Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "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:
// template\template_variant\specific\keyboard.cpp
// Access to Template interruptible keyboard
// The code here implements a simple interrupt-driven keyboard driver.
// This is an alternative to the polled driver in keyboard.cpp.
// This example assumes that we have an intelligent keyboard controller
// which:
// scans the keyboard automatically
// generates an interrupt when a key is pressed or released
// You can use this code as a starting point and modify it to suit
// your hardware.
// 
//

#include <template_assp.h>
#include "iolines.h"
#include "platform.h"
#include <kernel/kpower.h>
#include <e32keys.h>
//
//
// TO DO: (optional)
//
// Modify this conversion table to suit your keyboard layout
//
// This example assumes that the following keyboard layout:
//
// <----Row0-----><-----Row1-------><---Row2-----><-----Row3-------><-------Row4-----------><------Row5------><-----Row6-------><---Row7--->
//		LAlt																																Column0
//		'				\				TAB				Z					A						X										Column1
//						LShift																												Column2
//		LCtrl																																Column3
//		Fn																																	Column4
//		Esc				Del				Q				CapLk				S						C				3						Column5
//		1								W									D						V				4						Column6
//		2				T				E									F						B				5						Column7
//		9				Y				R				K					G						N				6						Column8
//		0				U				O				L					H						M				7						Column9
//		-				I				P				;					J						,				8						Column10
//		=				Enter			[				'					/						.				Prog					Column11
//						RShift																												Column12
//		BkSp			DnArrow			]				UpArrow				LeftArrow				Space			RightArrow				Column13
//																																			Column14
//																																			Column15
// EXAMPLE ONLY
const TUint8 convertCode[] =
	{
	EStdKeyNull ,   EStdKeyLeftAlt  ,  EStdKeyNull   ,   EStdKeyNull    ,      EStdKeyNull      ,   EStdKeyNull     ,    EStdKeyNull    ,EStdKeyNull,       // Column0
	EStdKeyNull ,   EStdKeyHash     ,EStdKeyBackSlash,   EStdKeyTab     ,          'Z'          ,       'A'         ,       'X'         ,EStdKeyNull,       // Column1
	EStdKeyNull ,    EStdKeyNull    ,EStdKeyLeftShift,   EStdKeyNull    ,      EStdKeyNull      ,   EStdKeyNull     ,    EStdKeyNull    ,EStdKeyNull,       // Column2
	EStdKeyNull ,  EStdKeyLeftCtrl  ,  EStdKeyNull   ,   EStdKeyNull    ,      EStdKeyNull      ,   EStdKeyNull     ,    EStdKeyNull    ,EStdKeyNull,       // Column3
	EStdKeyNull ,  EStdKeyLeftFunc  ,  EStdKeyNull   ,   EStdKeyNull    ,      EStdKeyNull      ,   EStdKeyNull     ,    EStdKeyNull    ,EStdKeyNull,       // Column4
	EStdKeyNull ,   EStdKeyEscape   , EStdKeyDelete  ,      'Q'         ,      EStdKeyCapsLock  ,       'S'         ,        'C'        ,   '3'     ,       // Column5
	EStdKeyNull ,       '1'         ,  EStdKeyNull   ,      'W'         ,      EStdKeyNull      ,       'D'         ,        'V'        ,   '4'     ,       // Column6
	EStdKeyNull ,       '2'         ,     'T'        ,      'E'         ,      EStdKeyNull      ,       'F'         ,        'B'        ,   '5'     ,       // Column7
	EStdKeyNull ,       '9'         ,     'Y'        ,      'R'         ,          'K'          ,       'G'         ,        'N'        ,   '6'     ,       // Column8
	EStdKeyNull ,       '0'         ,     'U'        ,      'O'         ,          'L'          ,       'H'         ,        'M'        ,   '7'     ,       // Column9
	EStdKeyNull ,    EStdKeyMinus   ,     'I'        ,      'P'         ,    EStdKeySemiColon   ,       'J'         ,    EStdKeyComma   ,   '8'     ,       // Column10
	EStdKeyNull ,    EStdKeyEquals  ,  EStdKeyEnter  ,EStdKeySquareBracketLeft,EStdKeySingleQuote,EStdKeyForwardSlash, EStdKeyFullStop  ,EStdKeyMenu,       // Column11
	EStdKeyNull ,    EStdKeyNull    ,EStdKeyRightShift,   EStdKeyNull   ,      EStdKeyNull      ,   EStdKeyNull     ,    EStdKeyNull    ,EStdKeyNull,       // Column12
	EStdKeyNull ,  EStdKeyBackspace ,EStdKeyDownArrow,EStdKeySquareBracketRight,EStdKeyUpArrow  , EStdKeyLeftArrow  ,    EStdKeySpace   ,EStdKeyRightArrow, // Column13
	EStdKeyNull ,    EStdKeyNull    ,  EStdKeyNull   ,   EStdKeyNull    ,      EStdKeyNull      ,   EStdKeyNull     ,    EStdKeyNull    ,EStdKeyNull,       // Column14
	EStdKeyNull ,    EStdKeyNull    ,  EStdKeyNull   ,   EStdKeyNull    ,      EStdKeyNull      ,   EStdKeyNull     ,    EStdKeyNull    ,EStdKeyNull        // Column15
	};

// EXAMPLE ONLY
const TInt KFlagKeyPressed = 0x80;		// As an example, we'll assume the top bit indicates pressed/released

// EXAMPLE ONLY
const TKeyboard	KConfigKeyboardType = EKeyboard_Full;
const TInt KConfigKeyboardDeviceKeys = 0;
const TInt KConfigKeyboardAppsKeys = 0;
//
//
_LIT(KLitKeyboard,"Keyboard");

class DKeyboardTemplate : public DPowerHandler
	{
public:
	DKeyboardTemplate();
	TInt Create();
public: // from DPowerHandler
	void PowerUp();
	void PowerDown(TPowerState);
	TInt HalFunction(TInt aFunction, TAny* a1, TAny* a2);
	void KeyboardInfo(TKeyboardInfoV01& aInfo);
	void KeyboardOn();
	void KeyboardOff();
	void HandleMsg(TMessageBase* aMsg);
private:
	static void Isr(TAny* aPtr);
	static void EventDfcFn(TAny* aPtr);
	void EventDfc();

	void PowerUpDfc();
	static void PowerUpDfcFn(TAny* aPtr);
	void PowerDownDfc();
	static void PowerDownDfcFn(TAny* aPtr);
private:
	void KeyboardPowerUp();
	TUint GetKeyCode();
	TBool IsKeyReady();
public:
	TDfcQue* iDfcQ;
	TMessageQue iMsgQ;	
	TDfc iPowerUpDfc;
	TDfc iPowerDownDfc;	
private:
	TDfc iEventDfc;
	TBool iKeyboardOn;
	};

LOCAL_C TInt halFunction(TAny* aPtr, TInt aFunction, TAny* a1, TAny* a2)
	{
	DKeyboardTemplate* pH=(DKeyboardTemplate*)aPtr;
	return pH->HalFunction(aFunction,a1,a2);
	}

void rxMsg(TAny* aPtr)
	{
	DKeyboardTemplate& h=*(DKeyboardTemplate*)aPtr;
	TMessageBase* pM=h.iMsgQ.iMessage;
	if (pM)
		h.HandleMsg(pM);
	}

//
//	Keyboard class
//
DKeyboardTemplate::DKeyboardTemplate()
	:	DPowerHandler(KLitKeyboard), 
		iMsgQ(rxMsg,this,NULL,1),
		iPowerUpDfc(PowerUpDfcFn,this,6),
		iPowerDownDfc(PowerDownDfcFn,this,7),
		iEventDfc(EventDfcFn,this,1)
	{
	}

TInt DKeyboardTemplate::Create()
//
// Initialisation. Bind and enable the interrupt.
//
	{
	iDfcQ=Kern::DfcQue0();

	iKeyboardOn = EFalse;	
		// install the HAL function
	TInt r=Kern::AddHalEntry(EHalGroupKeyboard,halFunction,this);
	if (r!=KErrNone)
		return r;

	iEventDfc.SetDfcQ(iDfcQ);
	iPowerUpDfc.SetDfcQ(iDfcQ);
	iPowerDownDfc.SetDfcQ(iDfcQ);
	iMsgQ.SetDfcQ(iDfcQ);
	iMsgQ.Receive();

	// Bind the key event interrupt
	r=Interrupt::Bind(KIntIdKeyboard,Isr,this);
	if (r==KErrNone)
		{
		// install the power handler
		Add();
		KeyboardPowerUp();
		}
	return r;
	}

void DKeyboardTemplate::Isr(TAny* aPtr)
	{
	DKeyboardTemplate& k=*(DKeyboardTemplate*)aPtr;
	Interrupt::Disable(KIntIdKeyboard);
	k.iEventDfc.Add();
	}

void DKeyboardTemplate::EventDfcFn(TAny* aPtr)
	{
	((DKeyboardTemplate*)aPtr)->EventDfc();
	}

void DKeyboardTemplate::EventDfc()
	{
	__KTRACE_OPT(KHARDWARE,Kern::Printf("DKeyboardTemplate::EventDfc"));

	TInt irq=NKern::DisableAllInterrupts();
	while (IsKeyReady())						// while there are keys in the controller's output buffer
		{
		NKern::RestoreInterrupts(irq);
		TRawEvent e;
		TUint keyCode=GetKeyCode();				// Read keycodes from controller
		__KTRACE_OPT(KHARDWARE,Kern::Printf("#%02x",keyCode));

		//
		// TO DO: (mandatory)
		//
		// Convert from hardware scancode to EPOC scancode and send the scancode as an event (key pressed or released)
		// as per below EXAMPLE ONLY:
		//
		TUint bareCode=keyCode&~KFlagKeyPressed;
		TUint8 stdKey=convertCode[bareCode];
		if (keyCode&KFlagKeyPressed)
			e.Set(TRawEvent::EKeyUp,stdKey,0);
		else
			e.Set(TRawEvent::EKeyDown,stdKey,0);
		Kern::AddEvent(e);
		NKern::Sleep(1);						// pause before reading more keycodes
		irq=NKern::DisableAllInterrupts();
		}
	Interrupt::Enable(KIntIdKeyboard);
	NKern::RestoreInterrupts(irq);
	}

TBool DKeyboardTemplate::IsKeyReady()
	{
	//
	// TO DO: (mandatory)
	//
	// Return ETrue if the keyboard controller has a key event waiting to be read
	//

	return EFalse;	// EXAMPLE ONLY
	}

TUint DKeyboardTemplate::GetKeyCode()
	{
	//
	// TO DO: (mandatory)
	//
	// Read and return the next available keycode from the keyboard controller
	//

	return 0;	// EXAMPLE ONLY
	}

void DKeyboardTemplate::PowerUpDfcFn(TAny* aPtr)
	{
	((DKeyboardTemplate*)aPtr)->PowerUpDfc();
	}

void DKeyboardTemplate::PowerDownDfcFn(TAny* aPtr)
	{
	((DKeyboardTemplate*)aPtr)->PowerDownDfc();
	}


void DKeyboardTemplate::KeyboardPowerUp()
	{
	__KTRACE_OPT(KPOWER,Kern::Printf("DKeyboardTemplate::KeyboardPowerUp()"));

	iKeyboardOn = ETrue;

	// Send key up events for EStdKeyOff (Fn+Esc) event 
	TRawEvent e;
	e.Set(TRawEvent::EKeyUp,EStdKeyEscape,0);
	Kern::AddEvent(e);
	e.Set(TRawEvent::EKeyUp,EStdKeyLeftFunc,0);
	Kern::AddEvent(e);
	}

void DKeyboardTemplate::PowerUp()
	{
	iPowerUpDfc.Enque();	// schedules DFC to execute on this driver's thread
	}

void DKeyboardTemplate::PowerUpDfc()
	{
	__KTRACE_OPT(KPOWER, Kern::Printf("DKeyboardTemplate::PowerUpDfc()"));
	KeyboardOn();
	PowerUpDone();		// must be called from a different thread than PowerUp()
	}

void DKeyboardTemplate::KeyboardOn()
	{
	__KTRACE_OPT(KPOWER,Kern::Printf("DKeyboardTemplate::KeyboardOn() iKeyboardOn=%d", iKeyboardOn));

	if (!iKeyboardOn)	// may be powered up from Power Manager or HAL
		{
		KeyboardPowerUp();
		}
	}

void DKeyboardTemplate::PowerDown(TPowerState)
	{
	iPowerDownDfc.Enque();	// schedules DFC to execute on this driver's thread
	}

void DKeyboardTemplate::PowerDownDfc()
	{
	__KTRACE_OPT(KPOWER, Kern::Printf("DKeyboardTemplate::PowerDownDfc()"));
	KeyboardOff();
	PowerDownDone();		// must be called from a different thread than PowerDown()
	}

void DKeyboardTemplate::KeyboardOff()
	{
	__KTRACE_OPT(KPOWER,Kern::Printf("DKeyboardTemplate::KeyboardOff() iKeyboardOn=%d", iKeyboardOn));

	if (iKeyboardOn)	// may have already been powered down by the HAL
		{
		iKeyboardOn = EFalse;
		Interrupt::Disable(KIntIdKeyboard);
		}
	iEventDfc.Cancel();
	}

void DKeyboardTemplate::HandleMsg(TMessageBase* aMsg)
	{
	if (aMsg->iValue)
		KeyboardOn();
	else
		KeyboardOff();
	aMsg->Complete(KErrNone,ETrue);
	}

void DKeyboardTemplate::KeyboardInfo(TKeyboardInfoV01& aInfo)
	{
	__KTRACE_OPT(KEXTENSION,Kern::Printf("DKeyboardTemplate::KeyboardInfo"));

	aInfo.iKeyboardType=KConfigKeyboardType;
	aInfo.iDeviceKeys=KConfigKeyboardDeviceKeys;
	aInfo.iAppsKeys=KConfigKeyboardAppsKeys;
	}

TInt DKeyboardTemplate::HalFunction(TInt aFunction, TAny* a1, TAny* a2)
	{
	TInt r=KErrNone;
	__KTRACE_OPT(KEXTENSION,Kern::Printf("DKeyboardTemplate::HalFunction %d", aFunction));
	switch(aFunction)
		{
		case EKeyboardHalKeyboardInfo:
			{
			TPckgBuf<TKeyboardInfoV01> kPckg;
			KeyboardInfo(kPckg());
			Kern::InfoCopy(*(TDes8*)a1,kPckg);
			break;
			}
		case EKeyboardHalSetKeyboardState:
			{
			if(!Kern::CurrentThreadHasCapability(ECapabilityPowerMgmt,__PLATSEC_DIAGNOSTIC_STRING("Checked by Hal function EKeyboardHalSetKeyboardState")))
				return KErrPermissionDenied;
			if ((TBool)a1)
				{
				TThreadMessage& m=Kern::Message();
				m.iValue = ETrue;
				m.SendReceive(&iMsgQ);		// send a message and block Client thread until keyboard has been powered up
				}
			else
				{
				TThreadMessage& m=Kern::Message();
				m.iValue = EFalse;
				m.SendReceive(&iMsgQ);		// send a message and block Client thread until keyboard has been powered down
				}
			}
			break;
		case EKeyboardHalKeyboardState:
			kumemput32(a1, &iKeyboardOn, sizeof(TBool));
			break;
		default:
			r=KErrNotSupported;
			break;
		}
	return r;
	}

DECLARE_STANDARD_EXTENSION()
	{
	__KTRACE_OPT(KEXTENSION,Kern::Printf("Starting keyboard driver"));

	// create keyboard driver
	TInt r=KErrNoMemory;
	DKeyboardTemplate* pK=new DKeyboardTemplate;
	if (pK)
		r=pK->Create();

	__KTRACE_OPT(KEXTENSION,Kern::Printf("Returns %d",r));
	return r;
	}