omap3530/beagle_drivers/keytran/keymap.cpp
changeset 0 6663340f3fc9
child 25 524118fd998f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/beagle_drivers/keytran/keymap.cpp	Thu Oct 15 12:59:54 2009 +0100
@@ -0,0 +1,2227 @@
+// Copyright (c) 1996-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:
+// omap3530/beagle_drivers/keytran/keymap.cpp
+// This file is part of the Beagle Base port
+// The keyboard lookup tables giving the function to be carried out
+// and the new state of the keyboard
+//
+
+
+#include <k32keys.h>
+
+#define ARRAY_LENGTH(array) (sizeof(array)/sizeof(array[0]))
+
+
+//
+// Scancode conversion tables
+// --------------------------
+// The scancode conversion is arranged as a tree of tables which are used to
+// convert a scancode to a keycode, taking into account the modifier state
+// (shift, control, fn)
+//
+// How the tables work:
+// --------------------
+// Firstly, there is a distinction between the "scancodes" used in scanning
+// the keyboard, and the "scancodes" used in this files.
+//
+// Typically the keyboard driver already contains a table to convert hardware
+// key location codes produced during keyboard scanning into EPOC "scancodes".
+// EPOC scancodes are defined for "standard" keys like shift, backspace,
+// escape, in the TStdScanCode enum (see E32KEYS.H), and should be ASCII codes
+// for normal characters. The keyboard driver should add these EPOC scancodes
+// to the event queue, not hardware-dependant key locations.
+//
+// For now on "scancode" refers to EPOC scancodes:
+//
+// The keyboard is divided into a number of "blocks" of contiguous scancodes
+//
+// Blocks map to keycodes in a keycode table, and several blocks can be
+// grouped and map to a single keycode table. Blocks map into the keycode
+// table in the order they are declared. For example, if two scancode blocks
+// with a range of 5 scancodes map to a single 10-entry keycode table, scancodes
+// which fall in the first block will map to the first 5 entries in the keycode
+// table, scancodes falling in the second block map the the next 5 entries in
+// the keycode table.
+//
+// In theory it is possible to have multiple [keycode,scancode blocks] groups
+// but there is little point doing this - grouping all the scancode blocks
+// with a single keycode table holding all possible keycode values is usually
+// sufficient (and simpler). However, there are some special cases where this
+// is useful - the most obvious example is handling of shift and caps lock.
+// The shift key implies everything that the caps-lock key does (upper case
+// letters) plus some shifted characters for other keys. This is done by 
+// defining two tables - the first handles only caps-lock (upper case), the 
+// second handles all other keys that are affected only by shift. If caps-
+// lock is active, only the caps-lock table is used. If shift is pressed both
+// the caps-lock and shift tables are scanned for the conversion. This allows
+// a base table to be extended with "extras", much like deriving a class from
+// base class and extending it.
+//
+//
+// There is one or more [keycode table, scancode blocks] group for each
+// modifier state - e.g. a lower-case table, upper-case, ctrl, ctrl-shift.
+// This is the root of the table.
+//
+// When converting a scancode the key translator first obtains the correct
+// conversion tables for the modifier state. It then traverses all the scancode
+// blocks looking for one which contains the scancode being converted. Once
+// a matching scancode range is located, the key translator maps this into
+// its position in the associated keycode table to obtain the converted keycode.
+//
+// The key tables below appear more complicated than they really are because of
+// the intermediate structures that hold pointers to other structures. The
+// important structures are:
+//		SScanCodeBlock - contains a "start" and "end" for a scancode range
+//		SConvSubTable - groups a number of scanode blocks with a keycode table
+//		SConvTableNode - points to SConvSubTables for each modifier state
+//		SConvTable - the root of the translation table - points to 1..n SConvTableNode
+//
+// The keycode tables are just an array of TUint16.
+//
+
+
+//
+// TO DO: (optional)
+//
+// Keys which are not affected by modifier state
+//
+
+//
+// This is a simple example of scancode to keycode mapping. The first block
+// in scanCodeBlock_unmodifiable is a range of several scancodes, so maps to
+// several entries in the keycode table convKeyCodes_unmodifiable.
+//		EStdKeyLeftShift -> maps to -> EKeyLeftShift
+//		EStdKeyRightShift -> maps to -> EKeyRightShift
+//		...
+//		EStdKeyScrollLock -> maps to -> EKeyScrollLock
+//
+LOCAL_D const SScanCodeBlock scanCodeBlock_unmodifiable[]=
+	{
+	{EStdKeyLeftShift, EStdKeyScrollLock},	// range 1: left shift to scroll lock
+	};
+
+LOCAL_D const TUint16 convKeyCodes_unmodifiable[]=
+	{
+	EKeyLeftShift,
+	EKeyRightShift,
+	EKeyLeftAlt,
+	EKeyRightAlt,
+	EKeyLeftCtrl,
+	EKeyRightCtrl,
+	EKeyLeftFunc,
+	EKeyRightFunc,
+	EKeyCapsLock,
+	EKeyNumLock,
+	EKeyScrollLock
+	};
+
+
+
+//
+// TO DO: (optional)
+//
+// Base conversion table
+// this table traps all of the keyboard's scanCodes except those in
+// convKeyCodes_unmodifiable. It appears last in the top-level table and
+// is used to convert any scancode that is not converted by any of the
+// other tables
+//
+LOCAL_D const SScanCodeBlock scanCodeBlock_base[]=
+	{
+	{EStdKeyNull, EStdKeyDownArrow},		// scancode range 1
+	{'0', '9'},								// scancode range 2
+	{'A', 'Z'},								// scancode range 3
+	{EStdKeyF1, EStdKeyDictaphoneRecord},	// scancode range 4
+	};
+
+LOCAL_D const TUint16 convKeyCodes_base[]=
+	{
+	EKeyNull,				// scancode range 1 mapping starts here
+	EKeyBackspace,
+	EKeyTab,
+	EKeyEnter,
+	EKeyEscape,
+	' ',
+	EKeyPrintScreen,
+	EKeyPause,
+	EKeyHome,
+	EKeyEnd,
+	EKeyPageUp,
+	EKeyPageDown,
+	EKeyInsert,
+	EKeyDelete,
+	EKeyLeftArrow,
+	EKeyRightArrow,
+	EKeyUpArrow,
+	EKeyDownArrow,
+	'0',					// scancode range 2 mapping starts here
+	'1',
+	'2',
+	'3',
+	'4',
+	'5',
+	'6',
+	'7',
+	'8',
+	'9',
+	'a',					// scancode range 3 mapping starts here
+	'b',
+	'c',
+	'd',
+	'e',
+	'f',
+	'g',
+	'h',
+	'i',
+	'j',
+	'k',
+	'l',
+	'm',
+	'n',
+	'o',
+	'p',
+	'q',
+	'r',
+	's',
+	't',
+	'u',
+	'v',
+	'w',
+	'x',
+	'y',
+	'z',
+	EKeyF1,						// scancode range 4 mapping starts here
+	EKeyF2,
+	EKeyF3,
+	EKeyF4,
+	EKeyF5,
+	EKeyF6,
+	EKeyF7,
+	EKeyF8,
+	EKeyF9,
+	EKeyF10,
+	EKeyF11,
+	EKeyF12,
+	EKeyF13,
+	EKeyF14,
+	EKeyF15,
+	EKeyF16,
+	EKeyF17,
+	EKeyF18,
+	EKeyF19,
+	EKeyF20,
+	EKeyF21,
+	EKeyF22,
+	EKeyF23,
+	EKeyF24,
+	'`',
+	',',
+	'.',
+	'/',
+	'\\',
+	';',
+	'\'',
+	'#',
+	'[',
+	']',
+	'-',
+	'=',
+	'/',
+	'*',
+	'-',
+	'+',
+	EKeyEnter,
+	EKeyEnd,
+	EKeyDownArrow,
+	EKeyPageDown,
+	EKeyLeftArrow,
+	EKeyNull, // numeric keypad '5'
+	EKeyRightArrow,
+	EKeyHome,
+	EKeyUpArrow,
+	EKeyPageUp,
+	EKeyInsert,
+	EKeyDelete,
+	EKeyMenu,
+	EKeyBacklightOn,
+	EKeyBacklightOff,
+	EKeyBacklightToggle,
+	EKeyIncContrast,
+	EKeyDecContrast,
+	EKeySliderDown,
+	EKeySliderUp,
+	EKeyDictaphonePlay,
+	EKeyDictaphoneStop,
+	EKeyDictaphoneRecord
+	};
+
+
+//
+// TO DO: (optional)
+//	
+// caps-lock: this table traps those scanCodes which are affected by caps-lock
+//
+LOCAL_D const SScanCodeBlock scanCodeBlock_capsLock[]=
+	{
+	{'A', 'Z'}			// only alpha keys are affected by caps-lock
+	};
+
+LOCAL_D const TUint16 convKeyCodes_capsLock[]=
+	{
+	'A',
+	'B',
+	'C',
+	'D',
+	'E',
+	'F',
+	'G',
+	'H',
+	'I',
+	'J',
+	'K',
+	'L',
+	'M',
+	'N',
+	'O',
+	'P',
+	'Q',
+	'R',
+	'S',
+	'T',
+	'U',
+	'V',
+	'W',
+	'X',
+	'Y',
+	'Z'
+	};
+
+//
+// TO DO: (optional)
+//
+// shift: this table traps those scanCodes which are affected
+// by normal shift key EXCEPT for those scanCodes affected by caps-lock
+//
+
+LOCAL_D const SScanCodeBlock scanCodeBlock_shift[]=
+	{
+	{'0', '9'},
+	{EStdKeyXXX, EStdKeyEquals},
+	};
+
+LOCAL_D const TUint16 convKeyCodes_shift[]=
+	{
+	')',
+	'!',
+	'@',/*'"',*/
+	'#',			/*ELatin1Pound,*/
+	'$',
+	'%',
+	'^',
+	'&',
+	'*',
+	'(',
+	'~',   /*ELatin1LogicNot,*/
+	'<',
+	'>',
+	'?',
+	'|',
+	':',
+	'"',
+	'|', /*'~',*/
+	'{',
+	'}',
+	'_',
+	'+'
+	};
+
+//
+// TO DO: (optional)
+//
+// func: this table traps those scanCodes which are affected
+// by the func key but not shift
+//
+LOCAL_D const SScanCodeBlock scanCodeBlock_func[]=
+	{
+    {EStdKeyEscape, EStdKeyEscape},
+    {'M', 'M'},
+    {EStdKeyComma, EStdKeyComma},
+    {EStdKeyLeftArrow, EStdKeyDownArrow},
+	};
+
+LOCAL_D const TUint16 convKeyCodes_func[]=
+	{
+    EKeyOff,
+    EKeyDecContrast,
+    EKeyIncContrast,
+    EKeyHome,
+    EKeyEnd,
+    EKeyPageUp,
+    EKeyPageDown,
+	};
+
+//
+// TO DO: (optional)
+//
+// func: this table traps those scanCodes which are affected
+// by func and shift - this is for func pressed, shift not pressed
+//
+//LOCAL_D const SScanCodeBlock scanCodeBlock_funcUnshifted[]=
+//	{
+//	{'E', 'E'},
+//	};
+
+//LOCAL_D const TUint16 convKeyCodes_funcUnshifted[]=
+//	{
+//	ELatin1LcEacute,
+//	};
+
+//
+// TO DO: (optional)
+//
+// func: this table traps those scanCodes which are affected
+// by func and shift - this is for func and shift both pressed
+//
+//LOCAL_D const SScanCodeBlock scanCodeBlock_funcShifted[]=
+//	{
+//	{'E', 'E'},
+//	};
+
+//LOCAL_D const TUint16 convKeyCodes_funcShifted[]=
+//	{
+//	ELatin1UcEacute,
+//	};
+
+//
+// TO DO: (optional)
+//
+// ctrl: this table traps those scanCodes which are affected by ctrl
+//
+LOCAL_D const SScanCodeBlock scanCodeBlock_ctrl[]=
+	{
+	//
+	// NOTE: The space key gets handled elsewhere, otherwise it gets
+	// thrown away as a NULL key
+	//	{EStdKeySpace, EStdKeySpace},
+
+	{'A', 'Z'},
+    {EStdKeyComma, EStdKeyComma},
+	};
+
+LOCAL_D const TUint16 convKeyCodes_ctrl[]=
+	{
+//	0,
+	1,
+	2,
+	3,
+	4,
+	5,
+	6,
+	7,
+	8,
+	9,
+	10,
+	11,
+	12,
+	13,
+	14,
+	15,
+	16,
+	17,
+	18,
+	19,
+	20,
+	21,
+	22,
+	23,
+	24,
+	25,
+	26,
+	',',
+	};
+
+
+
+//
+// TO DO: (optional)
+//
+// Each set of scancode+keycode tables must be grouped into a SConvSubTable.
+// The lines below define a number of SConvSubTables for each of the groups
+// above.
+//
+LOCAL_D const SConvSubTable
+	convSubTable_unmodifiable=							// table for unmodifiable keys
+		{
+		&convKeyCodes_unmodifiable[0],					// the keycode table
+			{
+			ARRAY_LENGTH(scanCodeBlock_unmodifiable),	// number of scancode blocks
+			&scanCodeBlock_unmodifiable[0]				// pointer to scancode blocks
+			}
+		},
+	convSubTable_base=									// table for base keys
+		{
+		&convKeyCodes_base[0],							// keycode table
+			{
+			ARRAY_LENGTH(scanCodeBlock_base),			// number of scancode blocks
+			&scanCodeBlock_base[0]						// pointer to scancode blocks
+			}
+		},
+	convSubTable_capsLock=
+		{
+		&convKeyCodes_capsLock[0],
+			{
+			ARRAY_LENGTH(scanCodeBlock_capsLock),
+			&scanCodeBlock_capsLock[0]
+			}
+		},
+	convSubTable_shift=
+		{
+		&convKeyCodes_shift[0],
+			{
+			ARRAY_LENGTH(scanCodeBlock_shift),
+			&scanCodeBlock_shift[0]
+			}
+		},
+	convSubTable_func=
+		{
+		&convKeyCodes_func[0],
+			{
+			ARRAY_LENGTH(scanCodeBlock_func),
+			&scanCodeBlock_func[0]
+			}
+		},
+//	convSubTable_funcUnshifted=
+//		{
+//		&convKeyCodes_funcUnshifted[0],
+//			{
+//			ARRAY_LENGTH(scanCodeBlock_funcUnshifted),
+//			&scanCodeBlock_funcUnshifted[0]
+//			}
+//		},
+//	convSubTable_funcShifted=
+//		{
+//		&convKeyCodes_funcShifted[0],
+//			{
+//			ARRAY_LENGTH(scanCodeBlock_funcShifted),
+//			&scanCodeBlock_funcShifted[0]
+//			}
+//		},
+	convSubTable_ctrl=
+		{
+		&convKeyCodes_ctrl[0],
+			{
+			ARRAY_LENGTH(scanCodeBlock_ctrl),
+			&scanCodeBlock_ctrl[0]
+			}
+		};
+
+//
+// TO DO: (optional)
+//
+// We need to declare arrays of SConvSubTable for each modifier state we
+// are going to handle. As mentioned above, it is possible to have several
+// [keycode table, scancode blocks] groups scanned for each keyboard state.
+//
+// Some modifier states use more than one conversion group. The simple example
+// is handling of caps-lock and shift. 
+//
+// Caps-lock means all letters are upper-case
+// shift means all letters are upper case AND some other keys return control characters
+//
+// Obviously the shift key means everything cpas-lock means PLUS a bit more. So
+// we define two tables, the caps-lock table defines only the uppercase conversion,
+// and the shift table defines all OTHER shifted keys not already handled by
+// caps-lock. The caps-lock modifier state then only scans the caps-lock table, and
+// the shift state scans both tables.
+//
+LOCAL_D const SConvSubTable
+	* const convSubTableArray_unmodifiable[]={&convSubTable_unmodifiable},
+	* const convSubTableArray_base[]={&convSubTable_base},
+
+	//
+	// The caps-lock state scans only the caps-lock table, to handle
+	// conversion to upper case
+	//
+	* const convSubTableArray_capsLock[]={&convSubTable_capsLock},
+	//
+	// The shift table scans the caps-lock table to handle upper case, 
+	// and also the shift table which handles some keys that are not affected
+	// by caps lock (such as 0-9).
+	//
+	* const convSubTableArray_shift[]={&convSubTable_capsLock, &convSubTable_shift},
+	//
+	// Pressing shift with caps-lock active reverts to lower-case letters,
+	// but other keys remain shifted. This time we only scan the shift table
+	// so only the non-alpha keys will be shifted
+	//
+	* const convSubTableArray_capsLockShift[]={&convSubTable_shift},
+
+	//
+	// Like the shift/caps-lock situation, the function key has two states,
+	// shifted and unshifted. Also, some keys may be independant of whether
+	// the shift key is pressed. So there are three tables defined. One declares
+	// all keys that are independant of shift state, the other two tables handle
+	// shifted and unshifted func.
+	//
+	// Unshifted func uses the independant set + funcUnshifted
+	//
+	//	* const convSubTableArray_func[]={&convSubTable_func, &convSubTable_funcUnshifted},
+	* const convSubTableArray_func[]={&convSubTable_func},
+	//
+	// Shifted func uses the independant set + funcShifted
+	//
+	//	* const convSubTableArray_funcShift[]={&convSubTable_func,&convSubTable_funcShifted},
+	//
+	// This keyboard table makes control independant of func and shift
+	//
+	* const convSubTableArray_ctrl[]={&convSubTable_ctrl};
+
+//
+// TO DO: (optional)
+//
+// This is the top of the scancode conversion tree. It is a set of pointers
+// to the SConvSubTable arrays declared above.
+//
+// The order of these nodes is VITAL, as the scanCode/modifiers are
+// searched for a match in this order
+//
+// The modifier state is matched by using a mask and a compare value. This is
+// used as follows:
+//
+//	match is true if ( (modifierState & mask) == compareValue
+//
+// For example, if the mask is (EModifierFunc|EModifierShift) and the
+// compare value is EModifierFunc, this will match ANY combination of
+// modifiers that has func pressed and shift not pressed
+//
+LOCAL_D const SConvTableNode convTableNodes[]=
+	{
+		{
+			{
+			0,		// modifier mask = no modifiers
+			0		// modifier compare = no modifiers
+			},
+		ARRAY_LENGTH(convSubTableArray_unmodifiable),	// number of SConvSubTables
+		&convSubTableArray_unmodifiable[0]				// pointer to SConvSubTable array
+		},
+		{
+			{
+			EModifierCtrl,	// modifier mask = check for ctrl
+			EModifierCtrl	// modifier compare = anything with ctrl pressed
+			},
+		ARRAY_LENGTH(convSubTableArray_ctrl),
+		&convSubTableArray_ctrl[0]
+		},
+		{
+			{
+			//
+			// Check for Func pressed
+			//
+			EModifierFunc,
+			EModifierFunc
+			},
+		ARRAY_LENGTH(convSubTableArray_func),
+		&convSubTableArray_func[0]
+		},
+		{
+			{
+			//
+			// Check for caps-lock pressed, shift not pressed
+			//
+			EModifierCapsLock|EModifierShift,
+			EModifierCapsLock
+			},
+		ARRAY_LENGTH(convSubTableArray_capsLock),
+		&convSubTableArray_capsLock[0]
+		},
+		{
+			{
+			//
+			// Check for caps-lock not pressed, shift pressed
+			//
+			EModifierShift|EModifierCapsLock,
+			EModifierShift
+			},
+		ARRAY_LENGTH(convSubTableArray_shift),
+		&convSubTableArray_shift[0]
+		},
+		{
+			{
+			//
+			// Check for caps-lock pressed, shift pressed
+			//
+			EModifierCapsLock|EModifierShift,
+			EModifierCapsLock|EModifierShift
+			},
+		ARRAY_LENGTH(convSubTableArray_capsLockShift),
+		&convSubTableArray_capsLockShift[0]
+		},
+		{
+		//
+		// This is the base table. It must appear last so that it can
+		// provide a default conversion for any scancodes that are not
+		// handled by any of the tables above
+		//
+			{
+			0,
+			0
+			},
+		ARRAY_LENGTH(convSubTableArray_base),
+		&convSubTableArray_base[0]
+		}
+	};
+
+//
+// The top-level exported data structure of all the conversion tables
+// This just points to the SConvTableNodes above
+//
+LOCAL_D const SConvTable ConvTable=
+	{
+	ARRAY_LENGTH(convTableNodes),
+	&convTableNodes[0]
+	};
+
+// The list of scan-codes on the numeric keypad
+LOCAL_D const SScanCodeBlock keypadScanCodeBlockArray[]=
+	{
+	{EStdKeyNumLock, EStdKeyNumLock},
+	{EStdKeyNkpForwardSlash, EStdKeyNkpFullStop}
+	};
+
+LOCAL_D const SScanCodeBlockList ConvTableKeypadScanCodes=
+	{
+	ARRAY_LENGTH(keypadScanCodeBlockArray),
+	&keypadScanCodeBlockArray[0]
+	};
+
+//
+// TO DO: (optional)
+//
+// List of keycodes that do not autorepeat
+//
+// These are usually control keys like shift, ctrl, escape
+//
+LOCAL_D const TUint16 nonAutorepKeyCodeArray[]=
+	{
+	EKeyEscape,
+	EKeyPrintScreen,
+	EKeyPause,
+	EKeyInsert,
+	EKeyLeftShift,
+	EKeyRightShift,
+	EKeyLeftAlt,
+	EKeyRightAlt,
+	EKeyLeftCtrl,
+	EKeyRightCtrl,
+	EKeyLeftFunc,
+	EKeyRightFunc,
+	EKeyCapsLock,
+	EKeyNumLock,
+	EKeyScrollLock,
+	EKeyMenu,
+	EKeyDictaphonePlay,
+	EKeyDictaphoneStop,
+	EKeyDictaphoneRecord
+	};
+
+//
+// TO DO: (optional)
+//
+// Declare blocks of non-autorepeating keycodes
+//
+LOCAL_D const SKeyCodeList ConvTableNonAutorepKeyCodes=
+	{
+	ARRAY_LENGTH(nonAutorepKeyCodeArray),	// number of keycode arrays
+	&nonAutorepKeyCodeArray[0]				// pointer to arrays
+	};
+
+
+
+
+
+
+/////////////////////////////////////////////////////////////////////
+// Keyboard state tables
+//
+
+// What these tables do
+// --------------------
+//
+// These tables control the way "special" keystrokes modify the behaviour
+// of the keyboard. There are two major uses for this:
+//
+//	- handling modifier keys e.g. caps-lock, shift, alt, fn and defining
+//		what modifier flags are affected by these keypresses
+//
+//	- switching the keyboard into special states (see below)
+//
+// Keyboard states
+// ---------------
+// 
+// Keyboard states are used to switch the keyboard into a special mode where it
+// can be used to enter unusual characters. There are two uses for this:
+//
+// - entering numeric codes, by pressing ctrl and typing the decimal code
+// - entering accented characters by pressing a key combination which
+//		enters "accented mode" then pressing a key. There can be multiple
+//		accented modes.
+//
+// You can see an example of accented modes on a Psion Series 5 by
+// pressing Fn+Z, followed by A - this will produce an a with an umlaut (ä)
+//
+// These tables are also used to select simpler states such as caps-lock
+// and num-lock.
+//
+//
+// The main data structure is a SFuncTableEntry. Each of these contains
+// three fields:
+//
+// 1. modifier match - this works the same way as the scancode conversion
+//     tables above, there is a mask and a compare value
+//
+// 2. a keycode patters - this is used to match with the keycode or keycodes
+//     that the state should respond to. This is a TKeyCodePattern structure
+//     which defines what sort of match should be performed.
+//
+// 3. a function and state change structure, SFuncAndState. This defines the
+//     state to change to, the function to perform, and a parameter for the
+//     function if required.
+//
+// TKeyCodePattern structures have two fields. The first is a keycode value
+// and is only used for some match types. The second field select the type
+// of match to perform:
+//
+//	EAnyKey - match any key
+//	EAnyAlphaNumeric - match any alpha or numeric key
+//	EAnyAlpha - match any alpha key
+//	EAnyAlphaLowerCase - match any lower-case key
+//	EAnyAlphaUpperCase - match any upper-case key
+//	EAnyDecimalDigit - match any decimal digit
+//	EAnyModifierKey - match any modifier key (e.g. alt, fn, ctrl)
+//	EMatchKey - match if equal to keycode value in first field
+//	EMatchLeftOrRight - match if equal to keycode value or (keycode value + 1)
+//	EMatchKeyCaseInsens - like EMatchKey but perform case-insensitive comparison
+//
+//
+
+// the "array" parameter must be a true array and not a pointer
+#define ARRAY_LENGTH(array) (sizeof(array)/sizeof(array[0]))
+
+#define TABLE_ENTRY_ANOTHER_CTRL_DIGIT					\
+	{  													\
+		{												\
+		EModifierKeyUp|EModifierFunc,					\
+		0												\
+		},												\
+		{												\
+		EKeyNull,										\
+		EAnyDigitGivenRadix								\
+		},												\
+		{												\
+		EStateCtrlDigits,								\
+		EAddOnCtrlDigit,								\
+		0												\
+		}												\
+	}
+
+//
+// TO DO: (optional)
+//
+// This table is searched for a match if a match has not been
+// found in the current state's table
+//
+
+LOCAL_D const SFuncTableEntry defaultTable[]=
+	{
+		{ 
+		//
+		// prevent key up events generating keycodes
+		//
+			{
+			EModifierKeyUp,		// mask = key up
+			EModifierKeyUp		// match = key up - i.e. accept any key up event
+			},
+			{
+			EKeyNull,			// dummy value, not used
+			EAnyKey				// accept any key
+			},
+			{
+			EStateUnchanged,	// state will not change
+			EDoNothing,			// no action to perform
+			0
+			}
+		},
+		{ 
+		//
+		// prevent any modifier key (e.g. shift, ctrl) from changing state
+		//
+			{
+			0,					// match any modifier state
+			0
+			},
+			{
+			EKeyNull,			// dummy value
+			EAnyModifierKey		// match any modifier key
+			},
+			{
+			EStateUnchanged,	// don't change state
+			EDoNothing,			// nothing to do
+			0
+			}
+		},
+		{ 
+		//
+		// filter out any unprocessed codes
+		//
+			{
+			0,					// match any modifier state
+			0
+			},
+			{
+			EKeyNull,			// dummy value
+			EAnyKey				// match any key
+			},
+			{
+			EStateNormal,		// switch back to normal keyboard state
+			EDoNothing,			// nothing to do
+			0
+			}
+		}
+	};
+
+//
+// TO DO: (optional)
+//
+// This table controls which keys change which modifiers;
+// NOTE: the state field in this table is ignored
+//
+
+LOCAL_D const SFuncTableEntry modifierTable[]=
+	{
+		{
+			{
+			EModifierKeyUp,		// check key-up modifier flag
+			0					// make sure it's zero (i.e. ignore key-up events)
+			},
+			{
+			//
+			// Here we want to match only the caps-lock key. We specify the
+			// keycode we are looking for in the first field, and EMatchKey
+			// in the second field
+			//
+			EKeyCapsLock,		// we want to respond to caps-lock key
+			EMatchKey			// match caps-lock only
+			},
+			{
+			EStateUnchanged,	// ignored
+			EToggleModifier,	// function = toggle modifier state
+			EModifierCapsLock	// this is the modifier to toggle
+			}
+		},
+		{
+			{
+			EModifierKeyUp,
+			0
+			},
+			{
+			EKeyNumLock,		// this one matched num-lock
+			EMatchKey			// match only num-lock
+			},
+			{
+			EStateUnchanged,	// ignored
+			EToggleModifier,	// function = toggle modifier state
+			EModifierNumLock	// this is the modifier to toggle
+			}
+		},
+		{
+			{
+			EModifierKeyUp,
+			0
+			},
+			{
+			EKeyScrollLock,		// match scroll-lock key
+			EMatchKey
+			},
+			{
+			EStateUnchanged,
+			EToggleModifier,	// function = toggle modifier
+			EModifierScrollLock	// modifier to toggle
+			}
+		},
+		{
+			{
+			EModifierKeyUp,
+			0
+			},
+			{
+			EKeyLeftAlt,		// match left alt key
+			EMatchKey
+			},
+			{
+			EStateUnchanged,	// ignored
+			ETurnOnModifier,	// function = turn on a modifier
+			EModifierAlt|EModifierLeftAlt	// alt turns on this modifier combination
+			}
+		},
+		{
+			{
+			EModifierKeyUp,		// goes with previous table, this handles the alt
+			EModifierKeyUp		// key being released
+			},
+			{
+			EKeyLeftAlt,		// match left alt key again
+			EMatchKey
+			},
+			{
+			EStateUnchanged,
+			ETurnOffModifier,	// function = turn off the modifier
+			EModifierLeftAlt	// modifier to turn off
+			}
+		},
+		{
+			{
+			EModifierKeyUp,		// key down event (key-up flag == 0)
+			0
+			},
+			{
+			EKeyLeftFunc,		// match left fn key
+			EMatchKey
+			},
+			{
+			EStateUnchanged,	// ignored
+			ETurnOnModifier,	// function = turn on modifier
+			EModifierFunc|EModifierLeftFunc	// modifier combination to turn on
+			}
+		},
+		{
+			{
+			EModifierKeyUp,		// goes with above table, this matched the
+			EModifierKeyUp		// left-fn key up event
+			},
+			{
+			EKeyLeftFunc,		// match left fn key
+			EMatchKey
+			},
+			{
+			EStateUnchanged,	// ignored
+			ETurnOffModifier,	// function = turn off modifier
+			EModifierLeftFunc	// modifier to turn off
+			}
+		},
+		{
+			{
+			EModifierKeyUp,		// key down event (key-up flag == 0)
+			0
+			},
+			{
+			EKeyLeftShift,		// match left shift key
+			EMatchKey
+			},
+			{
+			EStateUnchanged,	// ignored
+			ETurnOnModifier,	// function = turn on modifier
+			EModifierShift|EModifierLeftShift	// modifier combination to turn on
+			}
+		},
+		{
+			{
+			EModifierKeyUp,		// goes with above table, matches left shift
+			EModifierKeyUp		// key up event
+			},
+			{
+			EKeyLeftShift,		// match left shift key
+			EMatchKey
+			},
+			{
+			EStateUnchanged,	// ignored
+			ETurnOffModifier,	// turn off modifier
+			EModifierLeftShift	// modifier to turn off
+			}
+		},
+		{
+			{
+			EModifierKeyUp,		// key down event (key-up flag == 0)
+			0
+			},
+			{
+			EKeyLeftCtrl,		// match left ctrl key
+			EMatchKey
+			},
+			{
+			EStateUnchanged,	// ignored
+			ETurnOnModifier,	// function = turn on modifier
+			EModifierCtrl|EModifierLeftCtrl	// modifier combination to turn on
+			}
+		},
+		{
+			{
+			EModifierKeyUp,		// goes with above table, matches left ctrl
+			EModifierKeyUp		// key up event
+			},
+			{
+			EKeyLeftCtrl,		// match left ctrl key
+			EMatchKey
+			},
+			{
+			EStateUnchanged,	// ignored
+			ETurnOffModifier,	// function = turn off modifier
+			EModifierLeftCtrl	// modifier to turn off
+			}
+		},
+		{
+			{
+			EModifierKeyUp,		// key down event (key-up flag == 0)
+			0
+			},
+			{
+			EKeyRightAlt,		// match right alt key
+			EMatchKey
+			},
+			{
+			EStateUnchanged,	// ignored
+			ETurnOnModifier,	// function = turn on modifier
+			EModifierAlt|EModifierRightAlt	// modifier combination to turn on
+			}
+		},
+		{
+			{
+			EModifierKeyUp,		// goes with above table, matches right alt
+			EModifierKeyUp		// key up event
+			},
+			{
+			EKeyRightAlt,		// match right alt key
+			EMatchKey
+			},
+			{
+			EStateUnchanged,	// ignored
+			ETurnOffModifier,	// function = turn off modifier
+			EModifierRightAlt	// modifier to turn off
+			}
+		},
+		{
+			{
+			EModifierKeyUp,		// key down event (key-up flag == 0)
+			0
+			},
+			{
+			EKeyRightFunc,		// match right fn key
+			EMatchKey
+			},
+			{
+			EStateUnchanged,	// ignored
+			ETurnOnModifier,	// function = turn on modifier
+			EModifierFunc|EModifierRightFunc	// modifier combination to turn on
+			}
+		},
+		{
+			{
+			EModifierKeyUp,		// goes with above table, matches right fn
+			EModifierKeyUp		// key up event
+			},
+			{
+			EKeyRightFunc,		// match right fn key
+			EMatchKey
+			},
+			{
+			EStateUnchanged,	// ignored
+			ETurnOffModifier,	// function = turn off modifier
+			EModifierRightFunc	// modifier to turn off
+			}
+		},
+		{
+			{
+			EModifierKeyUp,		// key down event (key-up flag == 0)
+			0
+			},
+			{
+			EKeyRightShift,		// match right shift key
+			EMatchKey
+			},
+			{
+			EStateUnchanged,	// ignored
+			ETurnOnModifier,	// function = turn on modifier
+			EModifierShift|EModifierRightShift	// modifier combinatoin to turn on
+			}
+		},
+		{
+			{
+			EModifierKeyUp,		// goes with above table, handles right shift
+			EModifierKeyUp		// key up event
+			},
+			{
+			EKeyRightShift,		// match right shift key
+			EMatchKey
+			},
+			{
+			EStateUnchanged,	// ignored
+			ETurnOffModifier,	// function = turn off modifier
+			EModifierRightShift	// modifier to turn off
+			}
+		},
+		{
+			{
+			EModifierKeyUp,		// key down event (key-up flag == 0)
+			0
+			},
+			{
+			EKeyRightCtrl,		// match right ctrl key
+			EMatchKey
+			},
+			{
+			EStateUnchanged,	// ignored
+			ETurnOnModifier,	// function = turn on modifier
+			EModifierCtrl|EModifierRightCtrl	// modifier combination to turn on
+			}
+		},
+		{
+			{
+			EModifierKeyUp,		// goes with above table, matched right ctrl
+			EModifierKeyUp		// key up event
+			},
+			{
+			EKeyRightCtrl,		// match right ctrl key
+			EMatchKey
+			},
+			{
+			EStateUnchanged,	// ignored
+			ETurnOffModifier,	// function = turn off modifier
+			EModifierRightCtrl	// modifier to turn off
+			}
+		}
+	};
+
+
+//
+// TO DO: (optional)
+//
+// Tables corresponding to keyboard states.
+//
+// There are 13 keyboard states. States 0 to 9 can be used to create alternative
+// keyboard layouts for entering accented or unusual characters. Switching into
+// these states is done by a keypress. Implementation of the states is optional
+// depending on how many special state you want - you may implement 10 states,
+// you might decide not to implement any.
+//
+// State 10 is the normal state. The table for state 10 defines which keypresses
+// change to other states.
+//
+// States 11 and 12 are used when entering the numeric code of a character. State
+// 11 is for entering a specific number of digits. State 12 is for accepting
+// digits until Ctrl is released.
+//	
+//
+// As before, each SFuncTableEntry entry defines:
+//	- modifier conditions that must be matched
+//	- a keycode match pattern (typically an exact key match)
+//	- the function to perform and new state
+//
+// Switching into states 0..9,11,12 is done by entries in table10
+//
+
+//LOCAL_D const SFuncTableEntry table0[]=
+//	{
+//	TABLE_ENTRY_ANOTHER_CTRL_DIGIT
+//	};
+
+LOCAL_D const SFuncTableEntry table1[]=
+	{
+	//
+	// Table for special keyboard state 1
+	// This state is entered by pressing Fn+q (see table10)
+	//
+	// The table makes certain keys return accented characters
+	//
+		{
+			{
+			//
+			// Function must be release, and this must be a key down event
+			//
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			//
+			// match an 'e' keypress, convert to an ae ligature (æ)
+			//
+			'e',
+			EMatchKeyCaseInsens
+			},
+			{
+			EStateNormal,			// switch back to state normal (table10)
+			EPassSpecialKeyThru,	// turn keypress into a special character
+			ELatin1LcAe				// this is the character to pass on
+			}
+		},
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			'c',
+			EMatchKeyCaseInsens
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1LcCcedilla
+			}
+		},
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			's',
+			EMatchKeyCaseInsens
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1EsTset
+			}
+		},
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			'o',
+			EMatchKeyCaseInsens
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1LcOslash
+			}
+		},
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			'd',
+			EMatchKeyCaseInsens
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1LcThorn
+			}
+		},
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			't',
+			EMatchKeyCaseInsens
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1LcSoftTh
+			}
+		},
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			'l',
+			EMatchKeyCaseInsens
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1LeftChevron
+			}
+		},
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			'r',
+			EMatchKeyCaseInsens
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1RightChevron
+			}
+		},
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			'x',
+			EMatchKeyCaseInsens
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1InvExclam
+			}
+		},
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			'q',
+			EMatchKeyCaseInsens
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1InvQuest
+			}
+		},
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			'a',
+			EMatchKeyCaseInsens
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1LcAo
+			}
+		},
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			'p',
+			EMatchKeyCaseInsens
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1Pound
+			}
+		},
+	TABLE_ENTRY_ANOTHER_CTRL_DIGIT
+	};
+
+LOCAL_D const SFuncTableEntry table2[]=
+	{
+	//
+	// Table for special keyboard state 2
+	// This state is entered by pressing Fn+z (see table10)
+	//
+	// The table makes certain keys return accented characters
+	// See table1 for an explanation of the contents
+	//
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			'a',
+			EMatchKeyCaseInsens
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1LcAumlaut
+			}
+		},
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			'e',
+			EMatchKeyCaseInsens
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1LcEumlaut
+			}
+		},
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			'i',
+			EMatchKeyCaseInsens
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1LcIumlaut
+			}
+		},
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			'o',
+			EMatchKeyCaseInsens
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1LcOumlaut
+			}
+		},
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			'u',
+			EMatchKeyCaseInsens
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1LcUumlaut
+			}
+		},
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			'y',
+			EMatchKeyCaseInsens
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1LcYumlaut
+			}
+		},
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			' ',
+			EMatchKey
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1SpaceUmlaut
+			}
+		},
+	TABLE_ENTRY_ANOTHER_CTRL_DIGIT
+	};
+
+LOCAL_D const SFuncTableEntry table3[]=
+	{
+	//
+	// Table for special keyboard state 3
+	// This state is entered by pressing Fn+x (see table10)
+	//
+	// The table makes certain keys return accented characters
+	//
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			'a',
+			EMatchKeyCaseInsens
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1LcAgrave
+			}
+		},
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			'e',
+			EMatchKeyCaseInsens
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1LcEgrave
+			}
+		},
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			'i',
+			EMatchKeyCaseInsens
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1LcIgrave
+			}
+		},
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			'o',
+			EMatchKeyCaseInsens
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1LcOgrave
+			}
+		},
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			'u',
+			EMatchKeyCaseInsens
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1LcUgrave
+			}
+		},
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			' ',
+			EMatchKey
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1SpaceGrave
+			}
+		},
+	TABLE_ENTRY_ANOTHER_CTRL_DIGIT
+	};
+
+LOCAL_D const SFuncTableEntry table4[]=
+	{
+	//
+	// Table for special keyboard state 4
+	// This state is entered by pressing Fn+c (see table10)
+	//
+	// The table makes certain keys return accented characters
+	//
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			'a',
+			EMatchKeyCaseInsens
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1LcAacute
+			}
+		},
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			'e',
+			EMatchKeyCaseInsens
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1LcEacute
+			}
+		},
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			'i',
+			EMatchKeyCaseInsens
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1LcIacute
+			}
+		},
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			'o',
+			EMatchKeyCaseInsens
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1LcOacute
+			}
+		},
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			'u',
+			EMatchKeyCaseInsens
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1LcUacute
+			}
+		},
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			'y',
+			EMatchKeyCaseInsens
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1LcYacute
+			}
+		},
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			' ',
+			EMatchKey
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1LcSpaceAcute
+			}
+		},
+	TABLE_ENTRY_ANOTHER_CTRL_DIGIT
+	};
+
+LOCAL_D const SFuncTableEntry table5[]=
+	{
+	//
+	// Table for special keyboard state 5
+	// This state is entered by pressing Fn+v (see table10)
+	//
+	// The table makes certain keys return accented characters
+	//
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			'a',
+			EMatchKeyCaseInsens
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1LcAtilde
+			}
+		},
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			'n',
+			EMatchKeyCaseInsens
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1LcNtilde
+			}
+		},
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			'o',
+			EMatchKeyCaseInsens
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1LcOtilde
+			}
+		},
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			' ',
+			EMatchKey
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1LcSpaceTilde
+			}
+		},
+	TABLE_ENTRY_ANOTHER_CTRL_DIGIT
+	};
+
+LOCAL_D const SFuncTableEntry table6[]=
+	{
+	//
+	// Table for special keyboard state 6
+	// This state is entered by pressing Fn+b (see table6)
+	//
+	// The table makes certain keys return accented characters
+	//
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			'a',
+			EMatchKeyCaseInsens
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1LcAcirc
+			}
+		},
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			'e',
+			EMatchKeyCaseInsens
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1LcEcirc
+			}
+		},
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			'i',
+			EMatchKeyCaseInsens
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1LcIcirc
+			}
+		},
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			'o',
+			EMatchKeyCaseInsens
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1LcOcirc
+			}
+		},
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			'u',
+			EMatchKeyCaseInsens
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1LcUcirc
+			}
+		},
+		{
+			{
+			EModifierFunc|EModifierKeyUp,
+			0
+			},
+			{
+			' ',
+			EMatchKey
+			},
+			{
+			EStateNormal,
+			EPassSpecialKeyThru,
+			ELatin1LcSpaceCirc
+			}
+		},
+	TABLE_ENTRY_ANOTHER_CTRL_DIGIT
+	};
+
+//
+// TO DO: (optional)
+//
+// State 7,8,9 aren't used in this example.
+// You can implement them if you want more special states
+//
+
+//LOCAL_D const SFuncTableEntry table7[]=
+//	{
+//	TABLE_ENTRY_ANOTHER_CTRL_DIGIT
+//	};
+
+//LOCAL_D const SFuncTableEntry table8[]=
+//	{
+//	TABLE_ENTRY_ANOTHER_CTRL_DIGIT
+//	};
+
+//LOCAL_D const SFuncTableEntry table9[]=
+//	{
+//	TABLE_ENTRY_ANOTHER_CTRL_DIGIT
+//	};
+
+
+LOCAL_D const SFuncTableEntry table10[]=
+	{
+	//
+	// TO DO: (optional)
+	//
+	// Table keyboard state 10 - the normal state
+	//
+	// This table controls which keys switch into the special states
+	// 0-9, 11 and 12.
+	//
+
+		{ 
+		//
+		// Make sure key-up events are ignored by handling them first and
+		// doing nothing
+		//
+			{
+			EModifierKeyUp,
+			EModifierKeyUp
+			},
+			{
+			EKeyNull,
+			EAnyKey
+			},
+			{
+			EStateUnchanged,
+			EDoNothing,
+			0
+			}
+		},
+		{ 
+		//
+		// Check for ctrl-number presses
+		// This will enter state EStateCtrlDigits (state 12) which allows
+		// entry of a numeric keycode
+		//
+			{
+			EModifierCtrl|EModifierFunc|EModifierKeyUp,
+			EModifierCtrl
+			},
+			{
+			EKeyNull,
+			EAnyDecimalDigit
+			},
+			{
+			EStateDerivedFromDigitEntered,
+			EAddOnCtrlDigit,
+			0
+			}
+		},
+		{
+		//
+		// Any other key events that have not been trapped are just
+		// passed through unchanged
+		//
+			{
+			0,
+			0
+			},
+			{
+			EKeyNull,
+			EAnyKey
+			},
+			{
+			EStateUnchanged,
+			EPassKeyThru,
+			0
+			}
+		}
+	};
+
+//LOCAL_D const SFuncTableEntry table11[]=
+//	{
+//	TABLE_ENTRY_ANOTHER_CTRL_DIGIT
+//	};
+
+LOCAL_D const SFuncTableEntry table12[]=
+	{
+	//
+	// Table 12 handles entring digit codes. The keyboard will remain in this
+	// state until the Ctrl key is released
+	//
+		{
+			{
+			//
+			// Look for a key up event
+			//
+			EModifierKeyUp,
+			EModifierKeyUp
+			},
+			{
+			// 
+			// Match either left or right Ctrl key (i.e. this matches a Ctrl key release)
+			//
+			EKeyLeftCtrl,
+			EMatchLeftOrRight
+			},
+			{
+			EStateNormal,			// return to normal state (table10)
+			EPassCtrlDigitsThru,	// and pass through the numeric code we have accumulated
+			0
+			}
+		},
+	TABLE_ENTRY_ANOTHER_CTRL_DIGIT
+	};
+
+
+//
+// TO DO: (optional)
+//
+// Array of state control tables above. If a state is not used set the array 
+// size to zero and the pointer to NULL
+//
+// The tables must be declared here in order from table 0 to table 12
+//
+LOCAL_D const SFuncTable genFuncTables[]=
+	{
+		{
+		//
+		// state 0
+		//
+		0,			// state 0 not used, size = 0
+		NULL		// state 0 not used, pointer = NULL
+		},
+		{
+		//
+		// state 1
+		//
+		ARRAY_LENGTH(table1),		// size of table 1
+		&table1[0]					// pointer to table 1
+		},
+		{
+		//
+		// state 2
+		//
+		ARRAY_LENGTH(table2),
+		&table2[0]
+		},
+		{
+		//
+		// state 3
+		//
+		ARRAY_LENGTH(table3),
+		&table3[0]
+		},
+		{
+		//
+		// state 4
+		//
+		ARRAY_LENGTH(table4),
+		&table4[0]
+		},
+		{
+		//
+		// state 5
+		//
+		ARRAY_LENGTH(table5),
+		&table5[0]
+		},
+		{
+		//
+		// state 6
+		//
+		ARRAY_LENGTH(table6),
+		&table6[0]
+		},
+		{
+		//
+		// state 7
+		//
+		0,
+		NULL
+		},
+		{
+		//
+		// state 8
+		//
+		0,
+		NULL
+		},
+		{
+		//
+		// state 9
+		//
+		0,
+		NULL
+		},
+		{
+		//
+		// state 10
+		//
+		ARRAY_LENGTH(table10),
+		&table10[0]
+		},
+		{
+		//
+		// state 11
+		//
+		0,
+		NULL
+		},
+		{
+		//
+		// state 12
+		//
+		ARRAY_LENGTH(table12),
+		&table12[0]
+		}
+	};
+
+
+//
+// Root of the state modifier tables
+//
+LOCAL_D const SFuncTables FuncTables=
+	{
+		{
+		//
+		// The default processing table
+		//
+		ARRAY_LENGTH(defaultTable),
+		&defaultTable[0]
+		},
+		{
+		//
+		// The modifier control table
+		//
+		ARRAY_LENGTH(modifierTable),
+		&modifierTable[0]
+		},
+	//
+	// The state control tables
+	//
+	ARRAY_LENGTH(genFuncTables),
+	&genFuncTables[0]
+	};
+
+
+//
+// The following exported functions give the key translator access to
+// the control tables above
+//
+EXPORT_C void KeyDataSettings(TRadix &aRadix,TCtrlDigitsTermination &aCtrlDigitsTermination,TInt &aDefaultCtrlDigitsMaxCount,
+							  TInt &aMaximumCtrlDigitsMaxCount)
+	{
+	aRadix=EDecimal;
+	aCtrlDigitsTermination=ETerminationByCtrlUp;
+	aDefaultCtrlDigitsMaxCount=3;
+	aMaximumCtrlDigitsMaxCount=10;
+	}
+
+EXPORT_C void KeyDataFuncTable(SFuncTables &aFuncTables)
+	{
+	aFuncTables=FuncTables;
+	}
+
+EXPORT_C void KeyDataConvTable(SConvTable &aConvTable, TUint &aConvTableFirstScanCode,TUint &aConvTableLastScanCode,
+							 SScanCodeBlockList &aKeypadScanCode,SKeyCodeList &aNonAutorepKeyCodes)
+	{
+	aConvTable=ConvTable;
+	aConvTableFirstScanCode=scanCodeBlock_base[0].firstScanCode;
+	aConvTableLastScanCode=scanCodeBlock_base[ARRAY_LENGTH(scanCodeBlock_base)-1].lastScanCode;
+	aKeypadScanCode=ConvTableKeypadScanCodes;
+	aNonAutorepKeyCodes=ConvTableNonAutorepKeyCodes;
+	}