(key_string, 
             with_spaces=False,
             with_tabs=False, 
             with_newlines=False)
return keys
Converts `key_string` string to a list of 2-tuples, 
    ``(keycode,down)``, which  can be given to `playkeys`.

    `key_string` : str
        A string of keys.
    `with_spaces` : bool
        Whether to treat spaces as ``{SPACE}``. If `False`, spaces are ignored.
    `with_tabs` : bool
        Whether to treat tabs as ``{TAB}``. If `False`, tabs are ignored.
    `with_newlines` : bool
        Whether to treat newlines as ``{ENTER}``. If `False`, newlines are ignored.
Converts `key_string` string to a list of 2-tuples, 
    ``(keycode,down)``, which  can be given to `playkeys`.
Converts key_string string to a list of 2 - tuples ( keycode down ) which can be given to playkeys .
def str2keys(key_string, 
             with_spaces=False,
             with_tabs=False, 
             with_newlines=False):
    """
    Converts `key_string` string to a list of 2-tuples, 
    ``(keycode,down)``, which  can be given to `playkeys`.

    `key_string` : str
        A string of keys.
    `with_spaces` : bool
        Whether to treat spaces as ``{SPACE}``. If `False`, spaces are ignored.
    `with_tabs` : bool
        Whether to treat tabs as ``{TAB}``. If `False`, tabs are ignored.
    `with_newlines` : bool
        Whether to treat newlines as ``{ENTER}``. If `False`, newlines are ignored.
    """
    # reading input as a stack
    chars = list(key_string)
    chars.reverse()
    # results
    keys = []
    # for keeping track of whether shift, ctrl, & alt are pressed
    modifiers = {}
    for k in MODIFIERS.keys():
        modifiers[k] = False

    while chars:
        c = chars.pop()

        if c in MODIFIERS.keys():
            keys.append((MODIFIERS[c],True))
            modifiers[c] = True

        # group of chars, for applying a modifier
        elif c == '(':
            while c != ')':
                c = _next_char(chars,'`(` without `)`')
                if c == ')':
                    raise KeySequenceError('expected a character before `)`')

                if c == ' ' and with_spaces:
                    _handle_char(CODES['SPACE'], keys,  False)
                elif c == '\n' and with_newlines:
                    _handle_char(CODES['ENTER'], keys, False)
                elif c == '\t' and with_tabs:
                    _handle_char(CODES['TAB'], keys, False)
                else:
                    # if we need shift for this char and it's not already pressed
                    shift = (c.isupper() or c in SHIFT.keys()) and not modifiers['+']
                    if c in SHIFT.keys():
                        _handle_char(SHIFT[c], keys, shift)
                    else:
                        _handle_char(c.lower(), keys, shift)
                c = _next_char(chars,'`)` not found')
            _release_modifiers(keys,modifiers)

        # escaped code, modifier, or repeated char
        elif c == '{':
            saw_space = False
            name = [_next_char(chars)]
            arg = ['0']
            c = _next_char(chars, '`{` without `}`')
            while c != '}':
                if c == ' ':
                    saw_space = True
                elif c in '.0123456789' and saw_space:
                    arg.append(c)
                else:
                    name.append(c)
                c = _next_char(chars, '`{` without `}`')
            code = ''.join(name)
            arg = float('0' + ''.join(arg))
            if code == 'PAUSE':
                if not arg:
                    arg = PAUSE
                keys.append((None,arg))
            else:
                # always having 1 here makes logic 
                # easier -- we can always loop
                if arg == 0: 
                    arg = 1
                for i in range(int(arg)):
                    if code in CODES.keys():
                        _append_code(keys, CODES[code])
                    else:
                        # must be an escaped modifier or a 
                        # repeated char at this point
                        if len(code) > 1:
                            try:
                                # number in hex is also good (more keys are allowed)
                                _append_code(keys, int(code,16))
                                continue
                            except ValueError:
                                raise KeySequenceError('Unknown code: %s' % code)
                        # handling both {e 3} and {+}, {%}, {^}
                        shift = code in ESCAPE and not code in NO_SHIFT
                        # do shift if we've got an upper case letter
                        shift = shift or code[0].isupper()
                        c = code
                        if not shift:
                            # handle keys in SHIFT (!, @, etc...)
                            if c in SHIFT.keys():
                                c = SHIFT[c]
                                shift = True
                        _handle_char(c.lower(), keys, shift)
            _release_modifiers(keys,modifiers)

        # unexpected ")"
        elif c == ')':
            raise KeySequenceError('`)` should be preceeded by `(`')

        # unexpected "}"
        elif c == '}':
            raise KeySequenceError('`}` should be preceeded by `{`')

        # handling a single character
        else:
            if c == ' ' and not with_spaces:
                continue
            elif c == '\t' and not with_tabs:
                continue
            elif c == '\n' and not with_newlines:
                continue

            if c in ('~','\n'):
                _append_code(keys, CODES['ENTER'])
            elif c == ' ':
                _append_code(keys, CODES['SPACE'])
            elif c == '\t':
                _append_code(keys, CODES['TAB'])
            else:
                # if we need shift for this char and it's not already pressed
                shift = (c.isupper() or c in SHIFT.keys()) and not modifiers['+']
                if c in SHIFT.keys():
                    _handle_char(SHIFT[c], keys, shift)
                else:
                    _handle_char(c.lower(), keys, shift)
                _release_modifiers(keys,modifiers)

    _release_modifiers(keys,modifiers)
    return keys
def str2keys ( key_string , with_spaces = False , with_tabs = False , with_newlines = False ) : # reading input as a stack chars = list ( key_string ) chars . reverse ( ) # results keys = [ ] # for keeping track of whether shift, ctrl, & alt are pressed modifiers = { } for k in MODIFIERS . keys ( ) : modifiers [ k ] = False while chars : c = chars . pop ( ) if c in MODIFIERS . keys ( ) : keys . append ( ( MODIFIERS [ c ] , True ) ) modifiers [ c ] = True # group of chars, for applying a modifier elif c == '(' : while c != ')' : c = _next_char ( chars , '`(` without `)`' ) if c == ')' : raise KeySequenceError ( 'expected a character before `)`' ) if c == ' ' and with_spaces : _handle_char ( CODES [ 'SPACE' ] , keys , False ) elif c == '\n' and with_newlines : _handle_char ( CODES [ 'ENTER' ] , keys , False ) elif c == '\t' and with_tabs : _handle_char ( CODES [ 'TAB' ] , keys , False ) else : # if we need shift for this char and it's not already pressed shift = ( c . isupper ( ) or c in SHIFT . keys ( ) ) and not modifiers [ '+' ] if c in SHIFT . keys ( ) : _handle_char ( SHIFT [ c ] , keys , shift ) else : _handle_char ( c . lower ( ) , keys , shift ) c = _next_char ( chars , '`)` not found' ) _release_modifiers ( keys , modifiers ) # escaped code, modifier, or repeated char elif c == '{' : saw_space = False name = [ _next_char ( chars ) ] arg = [ '0' ] c = _next_char ( chars , '`{` without `}`' ) while c != '}' : if c == ' ' : saw_space = True elif c in '.0123456789' and saw_space : arg . append ( c ) else : name . append ( c ) c = _next_char ( chars , '`{` without `}`' ) code = '' . join ( name ) arg = float ( '0' + '' . join ( arg ) ) if code == 'PAUSE' : if not arg : arg = PAUSE keys . append ( ( None , arg ) ) else : # always having 1 here makes logic  # easier -- we can always loop if arg == 0 : arg = 1 for i in range ( int ( arg ) ) : if code in CODES . keys ( ) : _append_code ( keys , CODES [ code ] ) else : # must be an escaped modifier or a  # repeated char at this point if len ( code ) > 1 : try : # number in hex is also good (more keys are allowed) _append_code ( keys , int ( code , 16 ) ) continue except ValueError : raise KeySequenceError ( 'Unknown code: %s' % code ) # handling both {e 3} and {+}, {%}, {^} shift = code in ESCAPE and not code in NO_SHIFT # do shift if we've got an upper case letter shift = shift or code [ 0 ] . isupper ( ) c = code if not shift : # handle keys in SHIFT (!, @, etc...) if c in SHIFT . keys ( ) : c = SHIFT [ c ] shift = True _handle_char ( c . lower ( ) , keys , shift ) _release_modifiers ( keys , modifiers ) # unexpected ")" elif c == ')' : raise KeySequenceError ( '`)` should be preceeded by `(`' ) # unexpected "}" elif c == '}' : raise KeySequenceError ( '`}` should be preceeded by `{`' ) # handling a single character else : if c == ' ' and not with_spaces : continue elif c == '\t' and not with_tabs : continue elif c == '\n' and not with_newlines : continue if c in ( '~' , '\n' ) : _append_code ( keys , CODES [ 'ENTER' ] ) elif c == ' ' : _append_code ( keys , CODES [ 'SPACE' ] ) elif c == '\t' : _append_code ( keys , CODES [ 'TAB' ] ) else : # if we need shift for this char and it's not already pressed shift = ( c . isupper ( ) or c in SHIFT . keys ( ) ) and not modifiers [ '+' ] if c in SHIFT . keys ( ) : _handle_char ( SHIFT [ c ] , keys , shift ) else : _handle_char ( c . lower ( ) , keys , shift ) _release_modifiers ( keys , modifiers ) _release_modifiers ( keys , modifiers ) return keys