Browse Source

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)
master
Jacob Alexander 9 years ago
parent
commit
d91c0fb23f
4 changed files with 1622 additions and 512 deletions
  1. 24
    7
      backends/kiibohd.py
  2. 12
    1
      examples/simple2.kll
  3. 126
    31
      kll.py
  4. 1460
    473
      kll_lib/hid_dict.py

+ 24
- 7
backends/kiibohd.py View File

# 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 ###
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
def usbCodeCapability( self ):
return "usbKeyOut";
requiredCapabilities = {
'CONS' : 'consCtrlOut',
'NONE' : 'noneOut',
'SYS' : 'sysCtrlOut',
'USB' : 'usbKeyOut',
}

# Capability Lookup
def capabilityLookup( self, type ):
return self.requiredCapabilities[ type ];




# TODO # TODO
# 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 ] ) )


# 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"

+ 12
- 1
examples/simple2.kll View File

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 );
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"];
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;


+ 126
- 31
kll.py View File

### 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)
( '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'\]', ) ),
( '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'''[^"' ;:=>()]+''', ) ),
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 )

# Check size, to make sure it's valid
if usbCode > 0xFF:
print ( "{0} USBCode value {1} is larger than 255".format( ERROR, usbCode ) )
# 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 if a USB Code, to make sure it's valid
if type == 'USBCode' and hidCode > 0xFF:
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
) )


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]:


# 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 = []
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 ) )
pass
listRange = list( range( start, end + 1 ) )

# 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




# 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 isinstance( items[ variant ][ sequence ][ combo ], int ):
if items[ variant ][ sequence ][ combo ][0] in backend.requiredCapabilities.keys():
# 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






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')


# 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
resultCode_outerList = capFunc_sequence >> optionExpansion >> usbCodeToCapability
triggerUSBCode_outerList = usbCode_sequence >> optionExpansion >> hidCodeToCapability
resultCode_outerList = capFunc_sequence >> optionExpansion >> hidCodeToCapability




## Main Rules ## Main Rules

+ 1460
- 473
kll_lib/hid_dict.py
File diff suppressed because it is too large
View File