<commit_before>#!/bin/env python
from __future__ import print_function
import sys
import os
import argparse
import pprint
import itertools
import json
import collections
import time
import usb.core
import usb.util


def main(argv):
    cfg = parseArgs(argv)
    if cfg.print or (cfg.read_file is not None):
        mouseMapping = readMouseMappingFromMouse(cfg.debug)
        if cfg.print:
            print("Printing mouse config...")
            print(mouseMapping)
        if cfg.read_file is not None:
            saveMouseMappingToFile(cfg.read_file, cfg.overwrite_file, mouseMapping)
    if cfg.write_file is not None:
        mouseMapping = readMouseMappingFromFile(cfg.write_file, cfg.debug)
        writeMouseMappingToMouse(mouseMapping, cfg.debug, cfg.dry_run)

        
def readMouseMappingFromMouse(debug):
    print("Reading mouse config from mouse...")
    mouseMapping = G600MouseMapping()
    rawModeBytesList = readUsbMouseMappingRawBytes(debug)
    mouseMapping.fromModeRawBytesList(rawModeBytesList)
    print("... done reading mouse config from mouse")
    return mouseMapping

def readMouseMappingFromFile(fileHandle, debug):
    print("Reading mouse config from file...")
    mouseMapping = G600MouseMapping()
    mouseMapping.json = fileHandle.read()
    print("... done reading mouse config from file")
    return mouseMapping

def saveMouseMappingToFile(fileName, forceWrite, mouseMapping):
    print("Saving the mouse config to disk...")
    if os.path.isfile(fileName) and not forceWrite:
        raise Exception("File already exists and overwrite-file flag not set")
    with open(fileName,"w") as fileHandle:
        fileHandle.write(mouseMapping.json)
    print("...done the read mouse config to disk")

def writeMouseMappingToMouse(mouseMapping, debug, dryRun):
    print("Writing the mouse config to the mouse...")
    rawModeBytesList = mouseMapping.toModeRawBytesList()
    writeUsbMouseMappingRawBytes(rawModeBytesList, debug, dryRun)
    print("...done writing read mouse config to the mouse")

def parseArgs(argv):
    parser = argparse.ArgumentParser(description='Utility to read/write logitech g600 mouse key maps.  In most cases, this requires root (ie, run sudo <this script>)')
    if len(argv) == 1: 
        argv.append('-h') 

    rdWrGroup = parser.add_mutually_exclusive_group()
    parser.add_argument('-p', '--print',
                        help='Print the current mappings stored in the mouse',
                        action='store_true',)
    rdWrGroup.add_argument('-r', '--read-file',
                           help='Read current settings stored in the mouse and save to the file specified',
    )
    parser.add_argument('-f', '--overwrite-file',
                        help='Force overwrite of settings file if it already exists during read-file operation.',
                        action='store_true',)
    rdWrGroup.add_argument('-w', '--write-file',
                           type=argparse.FileType('r'),
                           help='Write the settings in the specified file to the mouse',
    )
    parser.add_argument('-n', '--dry-run',
                        help='For testing writes to the mouse, intended to be used in conjunction with debug, will do everything except for actually send the usb programming messages.',
                        action='store_true',)
    parser.add_argument('-d', '--debug',
                        help='Turn on debug printing',
                        action='store_true',)

    cfg = parser.parse_args()
    return cfg

################################################################################
## usb read/write to the mouse control interface.
## Operates on a 3 element sequence where each element is a bytearray()
IDVENDOR = 0x046d
IDPRODUCT = 0xc24a
G600_CONTROL_INTERFACE = 1
G600_REPORT_IDS = (0x03f3, 0x03f4, 0x03f5)  # one for each of the three mouse "modes"

G600_READ_REQTYPE = 0xA1
G600_READ_REQ = 0x01
G600_READ_IDX = G600_CONTROL_INTERFACE
G600_READ_LENGTH = 154
def readUsbMouseMappingRawBytes(debug=False):
    """Returns three element list.
    One for each of the mouse "modes."
    Each list element is a bytearray() type.
    """
    if debug: print("About to read USB...")
    dev = usb.core.find(idVendor=IDVENDOR, idProduct=IDPRODUCT)<commit_msg>Feature complete:  Behaves in a more understandable fashion, like a simple copy command. The source and dest can either be a file or the MOUSE.<commit_after>#!/bin/env python
"""Utility to read/write logitech g600 mouse key maps.  
Behaves like cp, ie, give it a source and destination.
In most cases, this requires root (ie, run sudo <this script>).
Mouse configurations are stored in a human readable json format.
Note: MOUSE is a special keyword that specifies the mouse rather than a file.

For example, to copy the current mouse config to a file called mouse_config.json:
$ sudo ./g600prog.py MOUSE mouse_config.json

Copying a custom_config.json file to the mouse:
$ sudo ./g600prog.py custom_config.json MOUSE 

Leaving off the second argument causes it to print to stdout.
So, to print your current mouse config:
$ sudo ./g600prog.py MOUSE"""
from __future__ import print_function
import sys
import os
import argparse
import pprint
import itertools
import json
import collections
import time
import usb.core
import usb.util


def main(argv):
    cfg = parseArgs(argv)
    if cfg.SOURCE == "MOUSE":
        mouseMapping = readMouseMappingFromMouse(cfg.debug)
    else:
        mouseMapping = readMouseMappingFromFile(cfg.SOURCE, cfg.debug)
    if cfg.DESTINATION is None:
        print(mouseMapping)
    elif cfg.DESTINATION == "MOUSE":
        writeMouseMappingToMouse(mouseMapping, cfg.debug, cfg.dry_run)
    else:
        saveMouseMappingToFile(cfg.DESTINATION, cfg.overwrite_file, mouseMapping)

        
def readMouseMappingFromMouse(debug):
    print("Reading mouse config from mouse...")
    mouseMapping = G600MouseMapping()
    rawModeBytesList = readUsbMouseMappingRawBytes(debug)
    mouseMapping.fromModeRawBytesList(rawModeBytesList)
    print("... done reading mouse config from mouse")
    return mouseMapping

def readMouseMappingFromFile(fileName, debug):
    print("Reading mouse config from file >{}< ...".format(fileName))
    mouseMapping = G600MouseMapping()
    with open(fileName, 'r') as fileHandle:
        mouseMapping.json = fileHandle.read()
    print("... done reading mouse config from file")
    return mouseMapping

def saveMouseMappingToFile(fileName, forceWrite, mouseMapping):
    print("Saving the mouse config to file >{}< ...".format(fileName))
    if os.path.isfile(fileName) and not forceWrite:
        raise Exception("File already exists and overwrite-file flag not set")
    with open(fileName, "w") as fileHandle:
        fileHandle.write(mouseMapping.json)
    print("...done saving the mouse config to file")

def writeMouseMappingToMouse(mouseMapping, debug, dryRun):
    print("Writing the mouse config to the mouse...")
    rawModeBytesList = mouseMapping.toModeRawBytesList()
    writeUsbMouseMappingRawBytes(rawModeBytesList, debug, dryRun)
    print("...done writing read mouse config to the mouse")

def parseArgs(argv):
    description = __doc__
    parser = argparse.ArgumentParser(description=description, formatter_class=argparse.RawDescriptionHelpFormatter)
    if len(argv) not in (2, 3): 
        argv.append('-h') 

    parser.add_argument('SOURCE',
                        help='Configuration source, can be MOUSE for the mouse itself or a filename.',
    )
    parser.add_argument('DESTINATION', nargs='?', default=None,
                        help='Optional configuration destination, can be the MOUSE or filename.  If omitted, prints to stdout.',
    )
    parser.add_argument('-f', '--overwrite-file',
                        help='Normally, if the destination file already exists, the program will terminate.  This option forces the overwrite of DESTINATION even if it exists.',
                        action='store_true',)
    parser.add_argument('-n', '--dry-run',
                        help='For testing writes to the mouse, intended to be used in conjunction with debug, will do everything except for actually send the usb programming messages.',
                        action='store_true',)
    parser.add_argument('-d', '--debug',
                        help='Turn on debug printing.',
                        action='store_true',)

    cfg = parser.parse_args()
    return cfg

################################################################################
## usb read/write to the mouse control interface.
## Operates on a 3 element sequence where each element is a bytearray()
IDVENDOR = 0x046d
IDPRODUCT = 0xc24a
G600_CONTROL_INTERFACE = 1
G600_REPORT_IDS = (0x03f3, 0x03f4, 0x03f5)  # one for each of the three mouse "modes"

G600_READ_REQTYPE = 0xA1
G600_READ_REQ = 0x01
G600_READ_IDX = G600_CONTROL_INTERFACE
G600_READ_LENGTH = 154
def readUsbMouseMappingRawBytes(debug=False):
    """Returns three element list.
    One for each of the mouse "modes."
    Each list element is a bytearray() type.
    """
    if debug: print("About to read USB...")
    dev = usb.core.find(idVendor=IDVENDOR, idProduct=IDPRODUCT)
{'fraction_non_alphanumeric': 0.10696409140369967, 'fraction_numerical': 0.014145810663764961, 'mean_word_length': 3.3089545241443976, 'pattern_counts': {'":': 2, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1293492', 'n_tokens_mistral': 2644, 'n_tokens_neox': 2516, 'n_words': 832}