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) 2007-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 polled keyboard
// The code here implements a simple polled keyboard driver.
// This is an alternative to the interrupt-driven driver in keyboard_interrupt.cpp.
// This example assumes that we have a non-intelligent keyboard
// consisting of a number of i/o lines arranged in a grid.
// You can use this code as a starting point and modify it to suit
// your hardware.
//
//
#include <template_assp.h>
#include "platform.h"
#include <kernel/kpower.h>
#include <e32keys.h>
// The TKeyboardState class is used to encapsulate the state of
// the keyboard. i.e which keys are currently being pressed.
// To determine which keys are being pressed, typically a voltage
// is applied to each row in turn (or column, depending on the hardware)
// and the output is read resulting in a bitmask for each row.
//
// For example, the keys could be arranged as follows (where a '1' indicates
// that a key is currently being pressed :
// EXAMPLE ONLY
//
// Translated
// Column# 0 1 2 3 4 5 6 7 8 9 A B C D E F KeyCode
// Row#
// 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 60 to 6F
// 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 50 to 5F
// 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 40 to 4F
// 3 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 30 to 3F
// Input-> 2 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 20 to 2F
// 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 to 1F
// 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 to 0F
//
// output-> 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0
//
// TO DO: (mandadory)
// Modify TKeyboardState (or provide an alternative) to model the
// real keyboard state
//
// EXAMPLE ONLY
class TKeyboardState
{
public:
enum TDimensions
{
KRows = 7,
KColumns = 16
};
public:
TKeyboardState();
void Clear();
TBool IsKeyReady();
TUint32 GetKeyCode();
TKeyboardState operator&(const TKeyboardState& aState);
TKeyboardState operator|(const TKeyboardState& aState);
TKeyboardState operator~();
public:
TUint32 iKeyBitMask[KRows];
};
/**
Constructor
*/
TKeyboardState::TKeyboardState()
{
Clear();
}
/**
Clears the array of bitmasks
*/
void TKeyboardState::Clear()
{
for (TInt row=0; row<KRows; row++)
iKeyBitMask[row] = 0;
}
/**
Determines whether any keys are being pressed by examining the
array of bitmasks to determine whether any bits are set
@return ETrue if one or more keys are being pressed
*/
TBool TKeyboardState::IsKeyReady()
{
for (TInt row=0; row<KRows; row++)
{
if (iKeyBitMask[row] != 0)
return ETrue;
}
return EFalse;
}
/**
Scans the array of bitmasks and returns a keycode representing
the first bit that it finds that is on.
E.g. :
if the first bit on the first row is set, then 1 is returned,
if the third bit on the first row is set, then 3 is returned. etc.
Once a bit is found it is cleared to avoid reading it again.
NB Before calling this function, IsKeyReady() should be called
to determine whether a key code is available.
@return a 32-bit keycode representing a key that is currently pressed
*/
TUint32 TKeyboardState::GetKeyCode()
{
TInt keyNum = 0;
for (TInt row=0; row<KRows; row++)
{
TUint32 bitMask = 1;
for (TInt col=0; col<KColumns; col++)
{
if (iKeyBitMask[row] & bitMask)
{
iKeyBitMask[row] &= ~bitMask;
return keyNum;
}
bitMask<<= 1;
keyNum++;
}
}
return 0;
}
/**
Perform a bitwise AND between two TKeyboardState objects
by AND-ing together all the 32-bit integers
@return a new instance of a TKeyboardState object containing the result
*/
TKeyboardState TKeyboardState::operator&(const TKeyboardState& aState)
{
TKeyboardState state = *this;
for (TInt row=0; row<KRows; row++)
state.iKeyBitMask[row]&= aState.iKeyBitMask[row];;
return state;
}
/**
Perform a bitwise OR between two TKeyboardState objects
by OR-ing together all the 32-bit integers
@return a new instance of a TKeyboardState object containing the result
*/
TKeyboardState TKeyboardState::operator|(const TKeyboardState& aState)
{
TKeyboardState state = *this;
for (TInt row=0; row<KRows; row++)
state.iKeyBitMask[row]|= aState.iKeyBitMask[row];;
return state;
}
/**
Perform a bitwise NOT (one's complement) of a KeyboardState object
by NOT-ing all the 32-bit integers
@return a new instance of a TKeyboardState object containing the result
*/
TKeyboardState TKeyboardState::operator~()
{
TKeyboardState state = *this;
for (TInt row=0; row<KRows; row++)
state.iKeyBitMask[row] = ~state.iKeyBitMask[row];
return state;
}
//
//
// TO DO: (optional)
//
// Modify this conversion table to suit your keyboard layout
// EXAMPLE ONLY
//
const TUint8 convertCode[] =
{
//Row 0 (bottom row)
EStdKeyLeftAlt , EStdKeyHash , EStdKeyNull , EStdKeyLeftCtrl ,
EStdKeyLeftFunc , EStdKeyEscape , '1' , '2' ,
'9' , '0' , EStdKeyMinus , EStdKeyEquals ,
EStdKeyNull , EStdKeyBackspace , EStdKeyNull , EStdKeyNull ,
//Row 1
EStdKeyNull , EStdKeyBackSlash , EStdKeyLeftShift , EStdKeyNull ,
EStdKeyNull , EStdKeyDelete , EStdKeyNull , 'T' ,
'Y' , 'U' , 'I' , EStdKeyEnter ,
EStdKeyRightShift , EStdKeyDownArrow , EStdKeyNull , EStdKeyNull ,
//Row 2
EStdKeyNull , EStdKeyTab , EStdKeyNull , EStdKeyNull ,
EStdKeyNull , 'Q' , 'W' , 'E' ,
'R' , 'O' , 'P' , EStdKeySquareBracketLeft ,
EStdKeyNull , EStdKeySquareBracketRight,EStdKeyNull , EStdKeyNull ,
//Row 3
EStdKeyNull , 'Z' , EStdKeyNull , EStdKeyNull ,
EStdKeyNull , EStdKeyCapsLock , EStdKeyNull , EStdKeyNull ,
'K' , 'L' , EStdKeySemiColon , EStdKeySingleQuote ,
EStdKeyNull , EStdKeyUpArrow , EStdKeyNull , EStdKeyNull ,
//Row 4
EStdKeyNull , EStdKeyTab , EStdKeyNull , EStdKeyNull,
EStdKeyNull , 'Q' , 'W' , 'E' ,
'R' , 'O' , 'P' , EStdKeySquareBracketLeft ,
EStdKeyNull , EStdKeySquareBracketRight, EStdKeyNull , EStdKeyNull ,
//Row 5
EStdKeyNull , 'X' , EStdKeyNull , EStdKeyNull ,
EStdKeyNull , 'C' , 'V' , 'B' ,
'N' , 'M' , EStdKeyComma , EStdKeyFullStop ,
EStdKeyNull , EStdKeySpace , EStdKeyNull , EStdKeyNull ,
//Row 6
EStdKeyNull , EStdKeyNull , EStdKeyNull , EStdKeyNull ,
EStdKeyNull , '3' , '4' , '5' ,
'6' , '7' , '8' , EStdKeyMenu ,
EStdKeyNull , EStdKeyRightArrow , EStdKeyNull , EStdKeyNull
};
// EXAMPLE ONLY
const TKeyboard KConfigKeyboardType = EKeyboard_Full;
const TInt KConfigKeyboardDeviceKeys = 0;
const TInt KConfigKeyboardAppsKeys = 0;
//
// TO DO: (optional)
//
// Set the keyboard scan rate in milliseconds
//
// EXAMPLE ONLY
const TInt KScanRate = 50; // poll every 1/20 of a second (i.e. every 50 milliseconds)
_LIT(KLitKeyboard,"Keyboard");
//
// TO DO: (optional)
//
// Add any private functions and data you require
//
NONSHARABLE_CLASS(DKeyboardTemplate) : public DPowerHandler
{
public:
DKeyboardTemplate();
TInt Create();
// from DPowerHandler
void PowerUp();
void PowerDown(TPowerState);
private:
static void HandleMessage(TAny* aPtr);
void HandleMsg(TMessageBase* aMsg);
static TInt HalFunction(TAny* aPtr, TInt aFunction, TAny* a1, TAny* a2);
TInt HalFunction(TInt aFunction, TAny* a1, TAny* a2);
static void PowerUpDfcFn(TAny* aPtr);
void PowerUpDfc();
static void PowerDownDfcFn(TAny* aPtr);
void PowerDownDfc();
static void TimerCallback(TAny* aDriver);
static void TimerDfcFn(TAny* aDriver);
void Poll();
void KeyboardInfo(TKeyboardInfoV01& aInfo);
void KeyboardOn();
void KeyboardOff();
void KeyboardPowerUp();
private:
TDfcQue* iDfcQ;
TMessageQue iMsgQ;
TDfc iPowerUpDfc;
TDfc iPowerDownDfc;
TBool iKeyboardOn;
NTimer iTimer;
TInt iTimerTicks;
TDfc iTimerDfc;
// a bitmask indicating which keys were pressed down on the last timer tick
TKeyboardState iKeyStateLast;
// a bitmask indicating the set of keys for which we have sent an EKeyDown event
TKeyboardState iKeysDown;
};
/**
constructor
*/
DKeyboardTemplate::DKeyboardTemplate()
: DPowerHandler(KLitKeyboard),
iMsgQ(HandleMessage, this, NULL, 1),
iPowerUpDfc(PowerUpDfcFn, this, 6),
iPowerDownDfc(PowerDownDfcFn, this, 7),
iTimer(&DKeyboardTemplate::TimerCallback, (TAny*) this),
iTimerDfc(TimerDfcFn, this, 1)
{
// Convert the scan rate from milliseconds to nanokernel ticks (normally 1/64 of a second)
iTimerTicks = NKern::TimerTicks(KScanRate);
}
/**
Second-phase constructor
Assigns queues for all the DFCs and starts the keyboard-polling timer
Called by factory function at ordinal 0
*/
TInt DKeyboardTemplate::Create()
{
iDfcQ=Kern::DfcQue0();
iKeyboardOn = EFalse;
// install the HAL function
TInt r = Kern::AddHalEntry(EHalGroupKeyboard, DKeyboardTemplate::HalFunction, this);
if (r != KErrNone)
return r;
iTimerDfc.SetDfcQ(iDfcQ);
iPowerUpDfc.SetDfcQ(iDfcQ);
iPowerDownDfc.SetDfcQ(iDfcQ);
iMsgQ.SetDfcQ(iDfcQ);
iMsgQ.Receive();
// install the power handler
Add();
// Power up the device and start the timer
KeyboardPowerUp();
return r;
}
/**
Calback for the keyboard-polling timer
Called in the context of an ISR
@param aPtr A pointer to an instance of DKeyboardTemplate
*/
void DKeyboardTemplate::TimerCallback(TAny *aPtr)
{
// schedule a DFC
DKeyboardTemplate& k=*(DKeyboardTemplate*)aPtr;
k.iTimerDfc.Add();
}
/**
DFC scheduled by the keyboard-polling timer when it expires
@param aPtr A pointer to an instance of DKeyboardTemplate
*/
void DKeyboardTemplate::TimerDfcFn(TAny* aPtr)
{
((DKeyboardTemplate*)aPtr)->Poll();
}
/**
Reads scan codes from the keyboard until there are none left
Called from the keyboard-polling timer's DFC
*/
void DKeyboardTemplate::Poll()
{
__KTRACE_OPT(KHARDWARE,Kern::Printf("DKeyboardTemplate::EventDfc"));
TKeyboardState keyState;
//
// TO DO: (mandatory)
// Read new key state into the array of bitmasks in keyState
// This typically involves applying a voltage to each row from 0 to KRows-1,
// reading the output state of the i/o lines at every step
// - this represents the keys that are pressed on each row -
// and storing the output of each row as a bitmask into keyState.iKeyBitMask[n],
// where n = the row being accessed
//
// To enable a simple de-bouncing algorithm,
// work out which keys have been pressed down for at least two timer
// ticks by AND-ing together the last bitmask with the current bitmask
TKeyboardState keysStillDown = keyState & iKeyStateLast;
// Similarly, work out which keys have been "un-pressed" for at least two timer
// ticks by AND-ing together the one's complement of the last bitmask with the
// one's complement of the current bitmask and
// then AND-ing this with the set of keys for which we have sent an EKeyDown
// event to give the set of keys for which we need to send an EKeyUp event
TKeyboardState keysStillUp = (~keyState & ~iKeyStateLast) & iKeysDown;
// save the current state for next time
iKeyStateLast = keyState;
// update the set of keys for which we have sent an EKeyDown event
iKeysDown = iKeysDown | keysStillDown;
iKeysDown = iKeysDown & ~keysStillUp;
// process all the key-down events
while (keysStillDown.IsKeyReady()) // while there are keys we haven't processed
{
TRawEvent e;
TUint keyCode = keysStillDown.GetKeyCode(); // Read keycodes from bitmask
__KTRACE_OPT(KHARDWARE,Kern::Printf("EKeyDown: #%02x\n",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:
//
__ASSERT_DEBUG(keyCode < (sizeof(convertCode) / sizeof(TUint8)), Kern::Fault("Keyboard", __LINE__));
TUint8 stdKey = convertCode[keyCode];
e.Set(TRawEvent::EKeyDown, stdKey, 0);
Kern::AddEvent(e);
}
// process all the key-up events
while (keysStillUp.IsKeyReady()) // while there are keys we haven't processed
{
TRawEvent e;
TUint keyCode = keysStillUp.GetKeyCode(); // Read keycodes from bitmask
__KTRACE_OPT(KHARDWARE,Kern::Printf("EKeyUp: #%02x\n",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:
//
__ASSERT_DEBUG(keyCode < (sizeof(convertCode) / sizeof(TUint8)), Kern::Fault("Keyboard", __LINE__));
TUint8 stdKey = convertCode[keyCode];
e.Set(TRawEvent::EKeyUp, stdKey, 0);
Kern::AddEvent(e);
}
// start the timer again
iTimer.OneShot(iTimerTicks);
}
/**
Notifies the peripheral of system power up.
Called by the power manager during a transition from standby.
Schedules a DFC to handle the power up.
*/
void DKeyboardTemplate::PowerUp()
{
iPowerUpDfc.Enque();
}
/**
static DFC to handle powering up the keyboard
@param aPtr A pointer to an instance of DKeyboardTemplate
*/
void DKeyboardTemplate::PowerUpDfcFn(TAny* aPtr)
{
((DKeyboardTemplate*)aPtr)->PowerUpDfc();
}
/**
DFC to handle powering up the keyboard
*/
void DKeyboardTemplate::PowerUpDfc()
{
__KTRACE_OPT(KPOWER, Kern::Printf("DKeyboardTemplate::PowerUpDfc()"));
KeyboardOn();
// Indicate to power handle that powered up is complete
PowerUpDone();
}
/**
Powers up the keyboard
May be called as a result of a power transition or from the HAL
*/
void DKeyboardTemplate::KeyboardOn()
{
__KTRACE_OPT(KPOWER,Kern::Printf("DKeyboardTemplate::KeyboardOn() iKeyboardOn=%d", iKeyboardOn));
if (!iKeyboardOn) // make sure we don't initialize more than once
KeyboardPowerUp();
}
/**
Powers up the keyboard
Assumes that the keyboard is currently powered off
*/
void DKeyboardTemplate::KeyboardPowerUp()
{
__KTRACE_OPT(KPOWER,Kern::Printf("DKeyboardTemplate::KeyboardPowerUp()"));
iKeyboardOn = ETrue;
iKeyStateLast.Clear();
iKeysDown.Clear();
// 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);
// Start the periodic tick for the selected rate.
// This will call TimerCallback() in the context of an ISR
iTimer.OneShot(iTimerTicks);
}
/**
Requests keyboard to power down.
Called by the power manager during a transition to standby or power off
Schedules a DFC to handle the power up.
@param aPowerState the current power state
*/
void DKeyboardTemplate::PowerDown(TPowerState)
{
iPowerDownDfc.Enque();
}
/**
static DFC to handle powering down the keyboard
@param aPtr A pointer to an instance of DKeyboardTemplate
*/
void DKeyboardTemplate::PowerDownDfcFn(TAny* aPtr)
{
((DKeyboardTemplate*)aPtr)->PowerDownDfc();
}
/**
DFC to handle powering down the keyboard
*/
void DKeyboardTemplate::PowerDownDfc()
{
__KTRACE_OPT(KPOWER, Kern::Printf("DKeyboardTemplate::PowerDownDfc()"));
KeyboardOff();
PowerDownDone();
}
/**
Powers down the keyboard
May be called as a result of a power transition or from the HAL
*/
void DKeyboardTemplate::KeyboardOff()
{
__KTRACE_OPT(KPOWER,Kern::Printf("DKeyboardTemplate::KeyboardOff() iKeyboardOn=%d", iKeyboardOn));
// cancel the keyboard-polling timer
iTimerDfc.Cancel();
iTimer.Cancel();
iKeyboardOn = EFalse;
}
/**
static message handler for processing power up/down messages
posted internally from HalFunction()
@param aPtr A pointer to an instance of DKeyboardTemplate
*/
void DKeyboardTemplate::HandleMessage(TAny* aPtr)
{
DKeyboardTemplate& h=*(DKeyboardTemplate*)aPtr;
TMessageBase* pM=h.iMsgQ.iMessage;
if (pM)
h.HandleMsg(pM);
}
/**
Message handler for processing power up/down messages
posted internally from HalFunction()
param aMsg A message indicating whether to power the keyboard on or off
*/
void DKeyboardTemplate::HandleMsg(TMessageBase* aMsg)
{
if (aMsg->iValue)
KeyboardOn();
else
KeyboardOff();
aMsg->Complete(KErrNone,ETrue);
}
/**
Retrieves information about the keyboard
Called from HalFunction()
@param aInfo a caller-supplied class which on return contains information about the keyboard
*/
void DKeyboardTemplate::KeyboardInfo(TKeyboardInfoV01& aInfo)
{
__KTRACE_OPT(KEXTENSION,Kern::Printf("DKeyboardTemplate::KeyboardInfo"));
aInfo.iKeyboardType=KConfigKeyboardType;
aInfo.iDeviceKeys=KConfigKeyboardDeviceKeys;
aInfo.iAppsKeys=KConfigKeyboardAppsKeys;
}
/**
HAL handler function
@param aPtr a pointer to an instance of DLcdPowerHandler
@param aFunction the function number
@param a1 an arbitrary parameter
@param a2 an arbitrary parameter
*/
TInt DKeyboardTemplate::HalFunction(TAny* aPtr, TInt aFunction, TAny* a1, TAny* a2)
{
DKeyboardTemplate* pH=(DKeyboardTemplate*)aPtr;
return pH->HalFunction(aFunction,a1,a2);
}
/**
a HAL entry handling function for HAL group attribute EHalGroupKeyboard
@param a1 an arbitrary argument
@param a2 an arbitrary argument
@return KErrNone if successful
*/
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;
}