Archived
1
0

Adding media key support to KLL compiler (0.3b)

- Full HID dictionaries for LED, Consumer Control and System Control
- Re-organized parameter passing (will help with future kll spec additions)
This commit is contained in:
Jacob Alexander 2015-05-10 14:52:07 -07:00
parent 1c983492d7
commit d91c0fb23f
4 changed files with 1617 additions and 507 deletions

View File

@ -29,8 +29,9 @@ from datetime import date
# Modifying Python Path, which is dumb, but the only way to import up one directory... # Modifying Python Path, which is dumb, but the only way to import up one directory...
sys.path.append( os.path.expanduser('..') ) sys.path.append( os.path.expanduser('..') )
from kll_lib.containers import *
from kll_lib.backends import * from kll_lib.backends import *
from kll_lib.containers import *
from kll_lib.hid_dict import *
### Classes ### ### Classes ###
@ -40,9 +41,16 @@ class Backend( BackendBase ):
templatePaths = ["templates/kiibohdKeymap.h", "templates/kiibohdDefs.h"] templatePaths = ["templates/kiibohdKeymap.h", "templates/kiibohdDefs.h"]
outputPaths = ["generatedKeymap.h", "kll_defs.h"] outputPaths = ["generatedKeymap.h", "kll_defs.h"]
# USB Code Capability Name requiredCapabilities = {
def usbCodeCapability( self ): 'CONS' : 'consCtrlOut',
return "usbKeyOut"; 'NONE' : 'noneOut',
'SYS' : 'sysCtrlOut',
'USB' : 'usbKeyOut',
}
# Capability Lookup
def capabilityLookup( self, type ):
return self.requiredCapabilities[ type ];
# TODO # TODO
@ -146,7 +154,7 @@ class Backend( BackendBase ):
# Needed for USB behaviour, otherwise, repeated keys will not work # Needed for USB behaviour, otherwise, repeated keys will not work
if sequence > 0: if sequence > 0:
# <single element>, <usbCodeSend capability>, <USB Code 0x00> # <single element>, <usbCodeSend capability>, <USB Code 0x00>
self.fill_dict['ResultMacros'] += "1, {0}, 0x00, ".format( capabilities.getIndex( self.usbCodeCapability() ) ) self.fill_dict['ResultMacros'] += "1, {0}, 0x00, ".format( capabilities.getIndex( self.capabilityLookup('USB') ) )
# For each combo in the sequence, add the length of the combo # For each combo in the sequence, add the length of the combo
self.fill_dict['ResultMacros'] += "{0}, ".format( len( macros.resultsIndexSorted[ result ][ sequence ] ) ) self.fill_dict['ResultMacros'] += "{0}, ".format( len( macros.resultsIndexSorted[ result ][ sequence ] ) )
@ -160,13 +168,22 @@ class Backend( BackendBase ):
# Add each of the arguments of the capability # Add each of the arguments of the capability
for arg in range( 0, len( resultItem[1] ) ): for arg in range( 0, len( resultItem[1] ) ):
self.fill_dict['ResultMacros'] += "{0}, ".format( resultItem[1][ arg ] ) # If this is a CONSUMER_ element, needs to be split into 2 elements
if isinstance( resultItem[1][ arg ], str ) and re.match( '^CONSUMER_', resultItem[1][ arg ] ):
tag = resultItem[1][ arg ].split( '_', 1 )[1]
if '_' in tag:
tag = tag.replace( '_', '' )
lookupNum = kll_hid_lookup_dictionary['ConsCode'][ tag ][1]
byteForm = lookupNum.to_bytes( 2, byteorder='little' ) # XXX Yes, little endian from how the uC structs work
self.fill_dict['ResultMacros'] += "{0}, {1}, ".format( *byteForm )
else:
self.fill_dict['ResultMacros'] += "{0}, ".format( resultItem[1][ arg ] )
# If sequence is longer than 1, append a sequence spacer at the end of the sequence # If sequence is longer than 1, append a sequence spacer at the end of the sequence
# Required by USB to end at sequence without holding the key down # Required by USB to end at sequence without holding the key down
if len( macros.resultsIndexSorted[ result ] ) > 1: if len( macros.resultsIndexSorted[ result ] ) > 1:
# <single element>, <usbCodeSend capability>, <USB Code 0x00> # <single element>, <usbCodeSend capability>, <USB Code 0x00>
self.fill_dict['ResultMacros'] += "1, {0}, 0x00, ".format( capabilities.getIndex( self.usbCodeCapability() ) ) self.fill_dict['ResultMacros'] += "1, {0}, 0x00, ".format( capabilities.getIndex( self.capabilityLookup('USB') ) )
# Add list ending 0 and end of list # Add list ending 0 and end of list
self.fill_dict['ResultMacros'] += "0 };\n" self.fill_dict['ResultMacros'] += "0 };\n"

View File

@ -10,6 +10,9 @@ mydefine2 => myCdef2;
mydefine3 => myCdef3; mydefine3 => myCdef3;
mynumber => myCnumber; mynumber => myCnumber;
usbKeyOut => Output_usbCodeSend_capability( usbCode : 1 ); usbKeyOut => Output_usbCodeSend_capability( usbCode : 1 );
consCtrlOut => Output_consCtrlSend_capability( consCode : 2 );
noneOut => Output_noneSend_capability();
sysCtrlOut => Output_sysCtrlSend_capability( sysCode : 1 );
myCapability2 => myFunc2(); myCapability2 => myFunc2();
myCapability3 => myFunc3( myArg1 : 2 ); myCapability3 => myFunc3( myArg1 : 2 );
myCapability => myFunc( myArg1 : 1, myArg2 : 4 ); myCapability => myFunc( myArg1 : 1, myArg2 : 4 );
@ -17,7 +20,7 @@ myCapability => myFunc( myArg1 : 1, myArg2 : 4 );
S0x3 : myCapability2(); S0x3 : myCapability2();
S0x4 : myCapability( 0x8, 0x25 ); S0x4 : myCapability( 0x8, 0x25 );
S0x12 : U[122] + U[123]; S0x12 : U[122] + U[123];
S0x6 : 'abcdDfF'; S0x6 : 'abcdDfF'; # TODO
S0x40 : U[0x1]; S0x40 : U[0x1];
S0x40 : U[0x1-0x4]; S0x40 : U[0x1-0x4];
S0x0B : U["Esc"]; S0x0B : U["Esc"];
@ -28,3 +31,11 @@ S[ 0x2 - 0x9, 0x10 ] :+ U"r";
S0x0B :- U["Esc"]; S0x0B :- U["Esc"];
S127 + S128 : U"0"; S127 + S128 : U"0";
S0x41 : CONS[0x30];
S0x42 : CONS["Play"];
S0x43 : CONS0x31;
S0x45 : SYS[0xA0];
S0x46 : SYS["UnDock"];
S0x47 : SYS0xA2;

155
kll.py
View File

@ -20,19 +20,19 @@
### Imports ### ### Imports ###
import argparse import argparse
import importlib
import io import io
import os import os
import re import re
import sys import sys
import token import token
import importlib
from tokenize import generate_tokens
from re import VERBOSE
from pprint import pformat from pprint import pformat
from re import VERBOSE
from tokenize import generate_tokens
from kll_lib.hid_dict import *
from kll_lib.containers import * from kll_lib.containers import *
from kll_lib.hid_dict import *
from funcparserlib.lexer import make_tokenizer, Token, LexerError from funcparserlib.lexer import make_tokenizer, Token, LexerError
from funcparserlib.parser import (some, a, many, oneplus, skip, finished, maybe, skip, forward_decl, NoParseError) from funcparserlib.parser import (some, a, many, oneplus, skip, finished, maybe, skip, forward_decl, NoParseError)
@ -138,6 +138,12 @@ def tokenize( string ):
( 'Space', ( r'[ \t\r\n]+', ) ), ( 'Space', ( r'[ \t\r\n]+', ) ),
( 'USBCode', ( r'U(("[^"]+")|(0x[0-9a-fA-F]+)|([0-9]+))', ) ), ( 'USBCode', ( r'U(("[^"]+")|(0x[0-9a-fA-F]+)|([0-9]+))', ) ),
( 'USBCodeStart', ( r'U\[', ) ), ( 'USBCodeStart', ( r'U\[', ) ),
( 'ConsCode', ( r'CONS(("[^"]+")|(0x[0-9a-fA-F]+)|([0-9]+))', ) ),
( 'ConsCodeStart', ( r'CONS\[', ) ),
( 'SysCode', ( r'SYS(("[^"]+")|(0x[0-9a-fA-F]+)|([0-9]+))', ) ),
( 'SysCodeStart', ( r'SYS\[', ) ),
( 'LedCode', ( r'LED(("[^"]+")|(0x[0-9a-fA-F]+)|([0-9]+))', ) ),
( 'LedCodeStart', ( r'LED\[', ) ),
( 'ScanCode', ( r'S((0x[0-9a-fA-F]+)|([0-9]+))', ) ), ( 'ScanCode', ( r'S((0x[0-9a-fA-F]+)|([0-9]+))', ) ),
( 'ScanCodeStart', ( r'S\[', ) ), ( 'ScanCodeStart', ( r'S\[', ) ),
( 'CodeEnd', ( r'\]', ) ), ( 'CodeEnd', ( r'\]', ) ),
@ -148,6 +154,7 @@ def tokenize( string ):
( 'Dash', ( r'-', ) ), ( 'Dash', ( r'-', ) ),
( 'Plus', ( r'\+', ) ), ( 'Plus', ( r'\+', ) ),
( 'Parenthesis', ( r'\(|\)', ) ), ( 'Parenthesis', ( r'\(|\)', ) ),
( 'None', ( r'None', ) ),
( 'Number', ( r'-?(0x[0-9a-fA-F]+)|(0|([1-9][0-9]*))', VERBOSE ) ), ( 'Number', ( r'-?(0x[0-9a-fA-F]+)|(0|([1-9][0-9]*))', VERBOSE ) ),
( 'Name', ( r'[A-Za-z_][A-Za-z_0-9]*', ) ), ( 'Name', ( r'[A-Za-z_][A-Za-z_0-9]*', ) ),
( 'VariableContents', ( r'''[^"' ;:=>()]+''', ) ), ( 'VariableContents', ( r'''[^"' ;:=>()]+''', ) ),
@ -180,26 +187,73 @@ def make_scanCode( token ):
raise raise
return scanCode return scanCode
def make_usbCode( token ): def make_hidCode( type, token ):
# If first character is a U, strip # If first character is a U, strip
if token[0] == "U": if token[0] == "U":
token = token[1:] token = token[1:]
# CONS specifier
elif 'CONS' in token:
token = token[4:]
# SYS specifier
elif 'SYS' in token:
token = token[3:]
# If using string representation of USB Code, do lookup, case-insensitive # If using string representation of USB Code, do lookup, case-insensitive
if '"' in token: if '"' in token:
try: try:
usbCode = kll_hid_lookup_dictionary[ token[1:-1].upper() ] hidCode = kll_hid_lookup_dictionary[ type ][ token[1:-1].upper() ][1]
except LookupError as err: except LookupError as err:
print ( "{0} {1} is an invalid USB Code Lookup...".format( ERROR, err ) ) print ( "{0} {1} is an invalid USB HID Code Lookup...".format( ERROR, err ) )
raise raise
else: else:
usbCode = int( token, 0 ) # Already tokenized
if type == 'USBCode' and token[0] == 'USB' or type == 'SysCode' and token[0] == 'SYS' or type == 'ConsCode' and token[0] == 'CONS':
hidCode = token[1]
# Convert
else:
hidCode = int( token, 0 )
# Check size, to make sure it's valid # Check size if a USB Code, to make sure it's valid
if usbCode > 0xFF: if type == 'USBCode' and hidCode > 0xFF:
print ( "{0} USBCode value {1} is larger than 255".format( ERROR, usbCode ) ) print ( "{0} USBCode value {1} is larger than 255".format( ERROR, hidCode ) )
raise raise
return usbCode
# Return a tuple, identifying which type it is
if type == 'USBCode':
return make_usbCode_number( hidCode )
elif type == 'ConsCode':
return make_consCode_number( hidCode )
elif type == 'SysCode':
return make_sysCode_number( hidCode )
print ( "{0} Unknown HID Specifier '{1}'".format( ERROR, type ) )
raise
def make_usbCode( token ):
return make_hidCode( 'USBCode', token )
def make_consCode( token ):
return make_hidCode( 'ConsCode', token )
def make_sysCode( token ):
return make_hidCode( 'SysCode', token )
def make_hidCode_number( type, token ):
lookup = {
'ConsCode' : 'CONS',
'SysCode' : 'SYS',
'USBCode' : 'USB',
}
return ( lookup[ type ], token )
def make_usbCode_number( token ):
return make_hidCode_number( 'USBCode', token )
def make_consCode_number( token ):
return make_hidCode_number( 'ConsCode', token )
def make_sysCode_number( token ):
return make_hidCode_number( 'SysCode', token )
def make_seqString( token ): def make_seqString( token ):
# Shifted Characters, and amount to move by to get non-shifted version # Shifted Characters, and amount to move by to get non-shifted version
@ -222,7 +276,7 @@ def make_seqString( token ):
) )
listOfLists = [] listOfLists = []
shiftKey = kll_hid_lookup_dictionary["SHIFT"] shiftKey = kll_hid_lookup_dictionary['USBCode']["SHIFT"]
# Creates a list of USB codes from the string: sequence (list) of combos (lists) # Creates a list of USB codes from the string: sequence (list) of combos (lists)
for char in token[1:-1]: for char in token[1:-1]:
@ -240,7 +294,7 @@ def make_seqString( token ):
# Do KLL HID Lookup on non-shifted character # Do KLL HID Lookup on non-shifted character
# NOTE: Case-insensitive, which is why the shift must be pre-computed # NOTE: Case-insensitive, which is why the shift must be pre-computed
usbCode = kll_hid_lookup_dictionary[ processedChar.upper() ] usbCode = kll_hid_lookup_dictionary['USBCode'][ processedChar.upper() ]
# Create Combo for this character, add shift key if shifted # Create Combo for this character, add shift key if shifted
charCombo = [] charCombo = []
@ -275,27 +329,40 @@ def make_scanCode_range( rangeVals ):
return list( range( start, end + 1 ) ) return list( range( start, end + 1 ) )
# Range can go from high to low or low to high # Range can go from high to low or low to high
# Warn on 0-9 (as this does not do what one would expect) TODO # Warn on 0-9 for USBCodes (as this does not do what one would expect) TODO
# Lookup USB HID tags and convert to a number # Lookup USB HID tags and convert to a number
def make_usbCode_range( rangeVals ): def make_hidCode_range( type, rangeVals ):
# Check if already integers # Check if already integers
if isinstance( rangeVals[0], int ): if isinstance( rangeVals[0], int ):
start = rangeVals[0] start = rangeVals[0]
else: else:
start = make_usbCode( rangeVals[0] ) start = make_hidCode( type, rangeVals[0] )[1]
if isinstance( rangeVals[1], int ): if isinstance( rangeVals[1], int ):
end = rangeVals[1] end = rangeVals[1]
else: else:
end = make_usbCode( rangeVals[1] ) end = make_hidCode( type, rangeVals[1] )[1]
# Swap start, end if start is greater than end # Swap start, end if start is greater than end
if start > end: if start > end:
start, end = end, start start, end = end, start
# Iterate from start to end, and generate the range # Iterate from start to end, and generate the range
return list( range( start, end + 1 ) ) listRange = list( range( start, end + 1 ) )
pass
# Convert each item in the list to a tuple
for item in range( len( listRange ) ):
listRange[ item ] = make_hidCode_number( type, listRange[ item ] )
return listRange
def make_usbCode_range( rangeVals ):
return make_hidCode_range( 'USBCode', rangeVals )
def make_sysCode_range( rangeVals ):
return make_hidCode_range( 'SysCode', rangeVals )
def make_consCode_range( rangeVals ):
return make_hidCode_range( 'ConsCode', rangeVals )
## Base Rules ## Base Rules
@ -387,17 +454,19 @@ def optionExpansion( sequences ):
# Converts USB Codes into Capabilities # Converts USB Codes into Capabilities
def usbCodeToCapability( items ): # These are tuples (<type>, <integer>)
def hidCodeToCapability( items ):
# Items already converted to variants using optionExpansion # Items already converted to variants using optionExpansion
for variant in range( 0, len( items ) ): for variant in range( 0, len( items ) ):
# Sequence of Combos # Sequence of Combos
for sequence in range( 0, len( items[ variant ] ) ): for sequence in range( 0, len( items[ variant ] ) ):
for combo in range( 0, len( items[ variant ][ sequence ] ) ): for combo in range( 0, len( items[ variant ][ sequence ] ) ):
# Only convert if an integer, otherwise USB Code doesn't need converting if items[ variant ][ sequence ][ combo ][0] in backend.requiredCapabilities.keys():
if isinstance( items[ variant ][ sequence ][ combo ], int ):
# Use backend capability name and a single argument # Use backend capability name and a single argument
items[ variant ][ sequence ][ combo ] = tuple( [ backend.usbCodeCapability(), tuple( [ hid_lookup_dictionary[ items[ variant ][ sequence ][ combo ] ] ] ) ] ) items[ variant ][ sequence ][ combo ] = tuple(
[ backend.capabilityLookup( items[ variant ][ sequence ][ combo ][0] ),
tuple( [ hid_lookup_dictionary[ items[ variant ][ sequence ][ combo ] ] ] ) ]
)
return items return items
@ -464,6 +533,8 @@ set_define = unarg( eval_define )
usbCode = tokenType('USBCode') >> make_usbCode usbCode = tokenType('USBCode') >> make_usbCode
scanCode = tokenType('ScanCode') >> make_scanCode scanCode = tokenType('ScanCode') >> make_scanCode
consCode = tokenType('ConsCode') >> make_consCode
sysCode = tokenType('SysCode') >> make_sysCode
name = tokenType('Name') name = tokenType('Name')
number = tokenType('Number') >> make_number number = tokenType('Number') >> make_number
comma = tokenType('Comma') comma = tokenType('Comma')
@ -490,25 +561,49 @@ scanCode_sequence = oneplus( scanCode_combo + skip( maybe( comma ) ) )
# USB Codes # USB Codes
usbCode_start = tokenType('USBCodeStart') usbCode_start = tokenType('USBCodeStart')
usbCode_range = ( number | unString ) + skip( dash ) + ( number | unString ) >> make_usbCode_range usbCode_number = number >> make_usbCode_number
usbCode_range = ( usbCode_number | unString ) + skip( dash ) + ( number | unString ) >> make_usbCode_range
usbCode_listElemTag = unString >> make_usbCode usbCode_listElemTag = unString >> make_usbCode
usbCode_listElem = ( number | usbCode_listElemTag ) >> listElem usbCode_listElem = ( usbCode_number | usbCode_listElemTag ) >> listElem
usbCode_innerList = oneplus( ( usbCode_range | usbCode_listElem ) + skip( maybe( comma ) ) ) >> flatten usbCode_innerList = oneplus( ( usbCode_range | usbCode_listElem ) + skip( maybe( comma ) ) ) >> flatten
usbCode_expanded = skip( usbCode_start ) + usbCode_innerList + skip( code_end ) usbCode_expanded = skip( usbCode_start ) + usbCode_innerList + skip( code_end )
usbCode_elem = usbCode >> listElem usbCode_elem = usbCode >> listElem
usbCode_combo = oneplus( ( usbCode_expanded | usbCode_elem ) + skip( maybe( plus ) ) ) >> listElem usbCode_combo = oneplus( ( usbCode_expanded | usbCode_elem ) + skip( maybe( plus ) ) ) >> listElem
usbCode_sequence = oneplus( ( usbCode_combo | seqString ) + skip( maybe( comma ) ) ) >> oneLayerFlatten usbCode_sequence = oneplus( ( usbCode_combo | seqString ) + skip( maybe( comma ) ) ) >> oneLayerFlatten
# Cons Codes
consCode_start = tokenType('ConsCodeStart')
consCode_number = number >> make_consCode_number
consCode_range = ( consCode_number | unString ) + skip( dash ) + ( number | unString ) >> make_consCode_range
consCode_listElemTag = unString >> make_consCode
consCode_listElem = ( consCode_number | consCode_listElemTag ) >> listElem
consCode_innerList = oneplus( ( consCode_range | consCode_listElem ) + skip( maybe( comma ) ) ) >> flatten
consCode_expanded = skip( consCode_start ) + consCode_innerList + skip( code_end )
consCode_elem = consCode >> listElem
# Sys Codes
sysCode_start = tokenType('SysCodeStart')
sysCode_number = number >> make_sysCode_number
sysCode_range = ( sysCode_number | unString ) + skip( dash ) + ( number | unString ) >> make_sysCode_range
sysCode_listElemTag = unString >> make_sysCode
sysCode_listElem = ( sysCode_number | sysCode_listElemTag ) >> listElem
sysCode_innerList = oneplus( ( sysCode_range | sysCode_listElem ) + skip( maybe( comma ) ) ) >> flatten
sysCode_expanded = skip( sysCode_start ) + sysCode_innerList + skip( code_end )
sysCode_elem = sysCode >> listElem
# HID Codes
hidCode_elem = usbCode_expanded | usbCode_elem | sysCode_expanded | sysCode_elem | consCode_expanded | consCode_elem
# Capabilities # Capabilities
capFunc_arguments = many( number + skip( maybe( comma ) ) ) >> listToTuple capFunc_arguments = many( number + skip( maybe( comma ) ) ) >> listToTuple
capFunc_elem = name + skip( parenthesis('(') ) + capFunc_arguments + skip( parenthesis(')') ) >> capArgExpander >> listElem capFunc_elem = name + skip( parenthesis('(') ) + capFunc_arguments + skip( parenthesis(')') ) >> capArgExpander >> listElem
capFunc_combo = oneplus( ( usbCode_expanded | usbCode_elem | capFunc_elem ) + skip( maybe( plus ) ) ) >> listElem capFunc_combo = oneplus( ( hidCode_elem | capFunc_elem ) + skip( maybe( plus ) ) ) >> listElem
capFunc_sequence = oneplus( ( capFunc_combo | seqString ) + skip( maybe( comma ) ) ) >> oneLayerFlatten capFunc_sequence = oneplus( ( capFunc_combo | seqString ) + skip( maybe( comma ) ) ) >> oneLayerFlatten
# Trigger / Result Codes # Trigger / Result Codes
triggerCode_outerList = scanCode_sequence >> optionExpansion triggerCode_outerList = scanCode_sequence >> optionExpansion
triggerUSBCode_outerList = usbCode_sequence >> optionExpansion >> usbCodeToCapability triggerUSBCode_outerList = usbCode_sequence >> optionExpansion >> hidCodeToCapability
resultCode_outerList = capFunc_sequence >> optionExpansion >> usbCodeToCapability resultCode_outerList = capFunc_sequence >> optionExpansion >> hidCodeToCapability
## Main Rules ## Main Rules

File diff suppressed because it is too large Load Diff