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

@@ -29,8 +29,9 @@ from datetime import date
# Modifying Python Path, which is dumb, but the only way to import up one directory...
sys.path.append( os.path.expanduser('..') )

from kll_lib.containers import *
from kll_lib.backends import *
from kll_lib.containers import *
from kll_lib.hid_dict import *


### Classes ###
@@ -40,9 +41,16 @@ class Backend( BackendBase ):
templatePaths = ["templates/kiibohdKeymap.h", "templates/kiibohdDefs.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
@@ -146,7 +154,7 @@ class Backend( BackendBase ):
# Needed for USB behaviour, otherwise, repeated keys will not work
if sequence > 0:
# <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
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
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
# Required by USB to end at sequence without holding the key down
if len( macros.resultsIndexSorted[ result ] ) > 1:
# <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
self.fill_dict['ResultMacros'] += "0 };\n"

+ 12
- 1
examples/simple2.kll View File

@@ -10,6 +10,9 @@ mydefine2 => myCdef2;
mydefine3 => myCdef3;
mynumber => myCnumber;
usbKeyOut => Output_usbCodeSend_capability( usbCode : 1 );
consCtrlOut => Output_consCtrlSend_capability( consCode : 2 );
noneOut => Output_noneSend_capability();
sysCtrlOut => Output_sysCtrlSend_capability( sysCode : 1 );
myCapability2 => myFunc2();
myCapability3 => myFunc3( myArg1 : 2 );
myCapability => myFunc( myArg1 : 1, myArg2 : 4 );
@@ -17,7 +20,7 @@ myCapability => myFunc( myArg1 : 1, myArg2 : 4 );
S0x3 : myCapability2();
S0x4 : myCapability( 0x8, 0x25 );
S0x12 : U[122] + U[123];
S0x6 : 'abcdDfF';
S0x6 : 'abcdDfF'; # TODO
S0x40 : U[0x1];
S0x40 : U[0x1-0x4];
S0x0B : U["Esc"];
@@ -28,3 +31,11 @@ S[ 0x2 - 0x9, 0x10 ] :+ U"r";
S0x0B :- U["Esc"];
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

@@ -20,19 +20,19 @@
### Imports ###

import argparse
import importlib
import io
import os
import re
import sys
import token
import importlib

from tokenize import generate_tokens
from re import VERBOSE
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.hid_dict import *

from funcparserlib.lexer import make_tokenizer, Token, LexerError
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]+', ) ),
( 'USBCode', ( r'U(("[^"]+")|(0x[0-9a-fA-F]+)|([0-9]+))', ) ),
( '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]+))', ) ),
( 'ScanCodeStart', ( r'S\[', ) ),
( 'CodeEnd', ( r'\]', ) ),
@@ -148,6 +154,7 @@ def tokenize( string ):
( 'Dash', ( r'-', ) ),
( 'Plus', ( r'\+', ) ),
( 'Parenthesis', ( r'\(|\)', ) ),
( 'None', ( r'None', ) ),
( 'Number', ( r'-?(0x[0-9a-fA-F]+)|(0|([1-9][0-9]*))', VERBOSE ) ),
( 'Name', ( r'[A-Za-z_][A-Za-z_0-9]*', ) ),
( 'VariableContents', ( r'''[^"' ;:=>()]+''', ) ),
@@ -180,26 +187,73 @@ def make_scanCode( token ):
raise
return scanCode

def make_usbCode( token ):
def make_hidCode( type, token ):
# If first character is a U, strip
if token[0] == "U":
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 '"' in token:
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:
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
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
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 ):
# Shifted Characters, and amount to move by to get non-shifted version
@@ -222,7 +276,7 @@ def make_seqString( token ):
)

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)
for char in token[1:-1]:
@@ -240,7 +294,7 @@ def make_seqString( token ):

# Do KLL HID Lookup on non-shifted character
# 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
charCombo = []
@@ -275,27 +329,40 @@ def make_scanCode_range( rangeVals ):
return list( range( start, end + 1 ) )

# 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
def make_usbCode_range( rangeVals ):
def make_hidCode_range( type, rangeVals ):
# Check if already integers
if isinstance( rangeVals[0], int ):
start = rangeVals[0]
else:
start = make_usbCode( rangeVals[0] )
start = make_hidCode( type, rangeVals[0] )[1]

if isinstance( rangeVals[1], int ):
end = rangeVals[1]
else:
end = make_usbCode( rangeVals[1] )
end = make_hidCode( type, rangeVals[1] )[1]

# Swap start, end if start is greater than end
if start > end:
start, end = end, start

# 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
@@ -387,17 +454,19 @@ def optionExpansion( sequences ):


# Converts USB Codes into Capabilities
def usbCodeToCapability( items ):
# These are tuples (<type>, <integer>)
def hidCodeToCapability( items ):
# Items already converted to variants using optionExpansion
for variant in range( 0, len( items ) ):
# Sequence of Combos
for sequence in range( 0, len( items[ variant ] ) ):
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
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


@@ -464,6 +533,8 @@ set_define = unarg( eval_define )

usbCode = tokenType('USBCode') >> make_usbCode
scanCode = tokenType('ScanCode') >> make_scanCode
consCode = tokenType('ConsCode') >> make_consCode
sysCode = tokenType('SysCode') >> make_sysCode
name = tokenType('Name')
number = tokenType('Number') >> make_number
comma = tokenType('Comma')
@@ -490,25 +561,49 @@ scanCode_sequence = oneplus( scanCode_combo + skip( maybe( comma ) ) )

# USB Codes
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_listElem = ( number | usbCode_listElemTag ) >> listElem
usbCode_listElem = ( usbCode_number | usbCode_listElemTag ) >> listElem
usbCode_innerList = oneplus( ( usbCode_range | usbCode_listElem ) + skip( maybe( comma ) ) ) >> flatten
usbCode_expanded = skip( usbCode_start ) + usbCode_innerList + skip( code_end )
usbCode_elem = usbCode >> listElem
usbCode_combo = oneplus( ( usbCode_expanded | usbCode_elem ) + skip( maybe( plus ) ) ) >> listElem
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
capFunc_arguments = many( number + skip( maybe( comma ) ) ) >> listToTuple
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

# Trigger / Result Codes
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

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