示例#1
0
        static void Main(string[] args)
        {
            BasePath     = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
            DataBasePath = Path.Combine(BasePath, DataBasePath);
            UserDataPath = Path.Combine(BasePath, UserDataPath);

            if (!Localization.Load())
            {
                LogFatalError("Failed to load localization data");
                return;
            }
            if (!KeyValues.Load())
            {
                LogFatalError("Failed to load the key data");
                return;
            }
            if (!KeyboardState.Load())
            {
                LogFatalError("Failed to load keyboard data");
                return;
            }

#if COMMAND_LOGGER_ENABLED
            if (args.Length > 0 && args[0].ToLower() == "clog")
            {
                CommandLogger.Run();
                return;
            }
#endif

            KeyboardDeviceManager.Connected += (KeyboardDevice device) =>
            {
                Log("Connected to device '" + device.State.ModelName + "' model:" + device.State.ModelId +
                    " fw:" + device.State.FirmwareVersion);
                WebGUI.UpdateDeviceList();

                string file = GetUserDataFile(device);
                if (!string.IsNullOrEmpty(file))
                {
                    try
                    {
                        string dir = Path.GetDirectoryName(file);
                        if (!Directory.Exists(dir))

                        {
                            Directory.CreateDirectory(dir);
                        }
                        if (!File.Exists(file))
                        {
                            File.WriteAllText(file, string.Empty, Encoding.UTF8);
                        }
                    }
                    catch
                    {
                    }
                }
            };
            KeyboardDeviceManager.Disconnected += (KeyboardDevice device) =>
            {
                Log("Disconnected from device '" + device.State.ModelName + "'");
                WebGUI.UpdateDeviceList();
            };
            KeyboardDeviceManager.StartListener();

            bool running      = true;
            bool hasNullInput = false;
            while (running)
            {
                string line = Console.ReadLine();
                if (line == null)
                {
                    // Handler for potential issue where ReadLine() returns null - see https://github.com/pixeltris/GK6X/issues/8
                    if (hasNullInput)
                    {
                        Console.WriteLine("Cannot read from command line. Exiting.");
                        break;
                    }
                    hasNullInput = true;
                    continue;
                }
                hasNullInput = false;
                string[] splitted = line.Split();
                switch (splitted[0].ToLower())
                {
                case "close":
                case "exit":
                case "quit":
                    running = false;
                    break;

                case "cls":
                case "clear":
                    Console.Clear();
                    break;

                case "update_data":
                    if (splitted.Length > 1)
                    {
                        string path      = line.TrimStart();
                        int    spaceChar = path.IndexOf(' ');
                        if (spaceChar > 0)
                        {
                            path = path.Substring(spaceChar).Trim();
                        }
                        bool isValidPath = false;
                        try
                        {
                            if (Directory.Exists(path))
                            {
                                isValidPath = true;
                            }
                        }
                        catch
                        {
                        }
                        if (isValidPath)
                        {
                            UpdateDataFiles(path);
                            Log("done");
                        }
                        else
                        {
                            Log("Couldn't find path '" + path + "'");
                        }
                    }
                    else
                    {
                        Log("Bad input. Expected folder name.");
                    }
                    break;

                case "gui":
                    WebGUI.Run();
                    break;

                case "gui_le":
                {
                    string userDataPath = WebGUI.UserDataPath;
                    string leName       = line.Trim();
                    int    spaceIndex   = leName.IndexOf(' ');
                    if (spaceIndex > 0)
                    {
                        leName = leName.Substring(spaceIndex).Trim();
                    }
                    else
                    {
                        leName = null;
                    }
                    if (!string.IsNullOrEmpty(leName))
                    {
                        if (!string.IsNullOrEmpty(userDataPath) && Directory.Exists(userDataPath))
                        {
                            string leDir      = Path.Combine(userDataPath, "Account", "0", "LE");
                            string leListFile = Path.Combine(leDir, "lelist.json");
                            if (File.Exists(leListFile))
                            {
                                bool          foundFile = false;
                                List <object> leList    = MiniJSON.Json.Deserialize(File.ReadAllText(leListFile)) as List <object>;
                                if (leList != null)
                                {
                                    foreach (object item in leList)
                                    {
                                        Dictionary <string, object> guidName = item as Dictionary <string, object>;
                                        if (guidName["Name"].ToString() == leName)
                                        {
                                            string leFileName = Path.Combine(leDir, guidName["GUID"].ToString() + ".le");
                                            if (File.Exists(leFileName))
                                            {
                                                foreach (char c in System.IO.Path.GetInvalidFileNameChars())
                                                {
                                                    leName = leName.Replace(c, '_');
                                                }
                                                string effectString = Encoding.UTF8.GetString(CMFile.Load(leFileName));
                                                effectString = CMFile.FormatJson(effectString);
                                                File.WriteAllText(Path.Combine(DataBasePath, "lighting", leName + ".le"), effectString);
                                                Program.Log("Copied '" + leName + "'");
                                                foundFile = true;
                                            }
                                        }
                                    }
                                }
                                if (!foundFile)
                                {
                                    Program.Log("Failed to find lighting effect '" + leName + "' (it's case sensitive)");
                                }
                            }
                            else
                            {
                                Program.Log("Failed to find file '" + leListFile + "'");
                            }
                        }
                    }
                    else
                    {
                        Program.Log("Invalid input. Expected lighting effect name.");
                    }
                }
                break;

                case "findkeys":
                {
                    Log(string.Empty);
                    Log("This is used to identify keys. Press keys to see their values. Missing keys will generally show up as '(null)' and they need to be mapped in the data files Data/devuces/YOUR_MODEL_ID/");
                    Log("The 'S' values are what you want to use to map keys in your UserData file.");
                    Log(string.Empty);
                    Log("Entering 'driver' mode and mapping all keys to callbacks.");
                    Log(string.Empty);
                    KeyboardDevice[] devices;
                    if (TryGetDevices(out devices))
                    {
                        foreach (KeyboardDevice device in devices)
                        {
                            device.SetLayer(KeyboardLayer.Driver);
                            device.SetIdentifyDriverMacros();
                        }
                    }
                }
                break;

                case "map":
                case "unmap":
                {
                    bool             map = splitted[0].ToLower() == "map";
                    KeyboardDevice[] devices;
                    KeyboardLayer    targetLayer;
                    bool             targetLayerIsFn;
                    TryParseLayer(splitted, 1, out targetLayer, out targetLayerIsFn);
                    bool hasTargetLayer = targetLayer != KeyboardLayer.Invalid;
                    if (TryGetDevices(out devices))
                    {
                        foreach (KeyboardDevice device in devices)
                        {
                            UserDataFile userData = UserDataFile.Load(device.State, GetUserDataFile(device));
                            if (userData == null)
                            {
                                Log("Couldn't find user data file '" + GetUserDataFile(device) + "'");
                                continue;
                            }

                            foreach (KeyValuePair <KeyboardLayer, KeyboardStateLayer> layer in device.State.Layers)
                            {
                                if (layer.Key == KeyboardLayer.Driver)
                                {
                                    continue;
                                }

                                if (hasTargetLayer && layer.Key != targetLayer)
                                {
                                    continue;
                                }

                                device.SetLighting(layer.Key, userData);
                                device.SetMacros(layer.Key, userData);

                                for (int i = 0; i < 2; i++)
                                {
                                    bool fn = i == 1;
                                    if (targetLayer != KeyboardLayer.Invalid && fn != targetLayerIsFn)
                                    {
                                        continue;
                                    }

                                    // Setting keys to 0xFFFFFFFF is preferable compared to using what is defined in
                                    // files as this will use what is defined in the firmware.
                                    uint[] driverValues = new uint[device.State.MaxLogicCode];
                                    for (int j = 0; j < driverValues.Length; j++)
                                    {
                                        driverValues[j] = KeyValues.UnusedKeyValue;
                                    }

                                    if (map)
                                    {
                                        UserDataFile.Layer userDataLayer;
                                        if (fn)
                                        {
                                            userData.FnLayers.TryGetValue(layer.Key, out userDataLayer);
                                        }
                                        else
                                        {
                                            userData.Layers.TryGetValue(layer.Key, out userDataLayer);
                                        }
                                        if (userDataLayer != null)
                                        {
                                            for (int j = 0; j < driverValues.Length; j++)
                                            {
                                                KeyboardState.Key key = device.State.GetKeyByLogicCode(j);
                                                if (key != null)
                                                {
                                                    driverValues[j] = userDataLayer.GetKey(key);
                                                }
                                            }
                                        }
                                    }
                                    device.SetKeys(layer.Key, driverValues, fn);
                                }
                            }

                            // This is required to "refresh" the keyboard with the updated key info
                            if (hasTargetLayer)
                            {
                                device.SetLayer(targetLayer);
                            }
                            else
                            {
                                device.SetLayer(KeyboardLayer.Base);
                            }
                            Log("Done");
                        }
                    }
                }
                break;

                case "dumpkeys":
                {
                    int targetRow = -1;
                    if (splitted.Length > 1)
                    {
                        if (!int.TryParse(splitted[1], out targetRow))
                        {
                            targetRow = -1;
                        }
                    }
                    bool showLocationCodeInfo = false;
                    if (splitted.Length > 2)
                    {
                        showLocationCodeInfo = splitted[2] == "ex";
                    }

                    KeyboardDevice[] devices;
                    if (TryGetDevices(out devices))
                    {
                        foreach (KeyboardDevice device in devices)
                        {
                            Log("====== " + device.State.ModelId + " ======");
                            bool foundKey = false;
                            int  lastLeft = int.MinValue;
                            int  row      = 1;
                            foreach (KeyboardState.Key key in device.State.KeysByLocationCode.Values.OrderBy(
                                         x => x.Position.Top).ThenBy(x => x.Position.Left))
                            {
                                if (key.Position.Left >= 0)
                                {
                                    if (lastLeft > key.Position.Left && foundKey)
                                    {
                                        if (targetRow == -1)
                                        {
                                            Log("--------");
                                        }
                                        foundKey = false;
                                        row++;
                                    }
                                    lastLeft = key.Position.Left;
                                }

                                if (string.IsNullOrEmpty(key.KeyName) || !key.KeyName.StartsWith("LED-"))
                                {
                                    if (targetRow == -1 || row == targetRow)
                                    {
                                        Log(key.KeyName + " = " + key.DriverValueName +
                                            (showLocationCodeInfo ? " (" + key.LocationCode + ")" : string.Empty));
                                    }
                                    foundKey = true;
                                }
                            }
                        }
                    }
                }
                break;
                }
            }

            KeyboardDeviceManager.StopListener();
        }
示例#2
0
        private static void UpdateDataFiles(string srcDir)
        {
            List <string> additionalDirs = new List <string>();

            additionalDirs.Add("Tronsmart Radiant");
            for (int i = 0; i < additionalDirs.Count;)
            {
                string fullPath = Path.Combine(srcDir, additionalDirs[i]);
                if (Directory.Exists(fullPath))
                {
                    additionalDirs[i++] = GetDriverDir(fullPath);
                }
                else
                {
                    additionalDirs.RemoveAt(i);
                }
            }

            // Create a merged 'driver' directory containing all the data from all distributors (for the WebGUI)
            string combinedDriverDir = Path.Combine(srcDir, "driver_combined");

            srcDir = GetDriverDir(srcDir);
            if (string.IsNullOrEmpty(srcDir))
            {
                return;
            }

            if (!Directory.Exists(combinedDriverDir))
            {
                Directory.CreateDirectory(combinedDriverDir);
            }

            string dstDir        = Path.Combine(Program.BasePath, "Data");
            string leDir         = Path.Combine(srcDir, "res", "data", "le");
            string deviceDir     = Path.Combine(srcDir, "device");
            string modelListFile = Path.Combine(deviceDir, "modellist.json");

            // Format these files manually (https://beautifier.io/)
            string indexJsFile = Path.Combine(srcDir, "index.formatted.js");
            string zeroJsFile  = Path.Combine(srcDir, "0.formatted.js");

            if (!File.Exists(indexJsFile) || !File.Exists(zeroJsFile))
            {
                Log("Couldn't find formatted js files to process!");
                return;
            }

            if (File.Exists(indexJsFile) && File.Exists(zeroJsFile) && Directory.Exists(leDir) && Directory.Exists(deviceDir) && File.Exists(modelListFile))
            {
                Dictionary <string, object> models = new Dictionary <string, object>();

                foreach (string additionalDir in additionalDirs)
                {
                    string additionalLeDir = Path.Combine(additionalDir, "res", "data", "le");
                    if (Directory.Exists(additionalLeDir))
                    {
                        CMFile.DumpLighting(additionalLeDir, Path.Combine(dstDir, "lighting"));
                    }

                    string additionalDeviceDir = Path.Combine(additionalDir, "device");
                    if (Directory.Exists(additionalDeviceDir))
                    {
                        CopyFilesRecursively(new DirectoryInfo(additionalDeviceDir), new DirectoryInfo(Path.Combine(dstDir, "device")), false);
                        string additionalModelListFile = Path.Combine(additionalDeviceDir, "modellist.json");
                        if (File.Exists(additionalModelListFile))
                        {
                            ReadModelList(additionalModelListFile, models);
                        }
                    }

                    CopyFilesRecursively(new DirectoryInfo(additionalDir), new DirectoryInfo(combinedDriverDir), true);
                }
                CMFile.DumpLighting(leDir, Path.Combine(dstDir, "lighting"));
                CopyFilesRecursively(new DirectoryInfo(deviceDir), new DirectoryInfo(Path.Combine(dstDir, "device")), false);

                // TODO: Merge json files in /res/data/le/ and /res/data/macro/
                CopyFilesRecursively(new DirectoryInfo(srcDir), new DirectoryInfo(combinedDriverDir), true);

                // Combine modellist.json files
                ReadModelList(modelListFile, models);
                File.WriteAllText(Path.Combine(dstDir, "device", "modellist.json"), CMFile.FormatJson(MiniJSON.Json.Serialize(models.Values.ToList())));

                string langDir = Path.Combine(dstDir, "i18n", "langs");
                Directory.CreateDirectory(langDir);

                string indexJs     = File.ReadAllText(indexJsFile);
                int    commonIndex = 0;
                for (int i = 0; i < 2; i++)
                {
                    string langStr = FindContent(indexJs, "common: {", '{', '}', ref commonIndex);
                    if (!string.IsNullOrEmpty(langStr))
                    {
                        File.WriteAllText(Path.Combine(langDir, (i == 0 ? "en" : "zh") + ".json"), langStr);
                    }
                }

                string zeroJs  = File.ReadAllText(zeroJsFile);
                string keysStr = FindContent(zeroJs, "el-icon-kb-keyboard", '[', ']');
                if (!string.IsNullOrEmpty(keysStr))
                {
                    File.WriteAllText(Path.Combine(dstDir, "keys.json"), keysStr);
                }
            }
            else
            {
                Log("Missing directory / file!");
            }
        }
示例#3
0
        static void Run(bool asGUI)
        {
            BasePath     = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
            DataBasePath = Path.Combine(BasePath, DataBasePath);
            UserDataPath = Path.Combine(BasePath, UserDataPath);

            if (!Localization.Load())
            {
                LogFatalError("Failed to load localization data");
                return;
            }
            if (!KeyValues.Load())
            {
                LogFatalError("Failed to load the key data");
                return;
            }
            if (!KeyboardState.Load())
            {
                LogFatalError("Failed to load keyboard data");
                return;
            }

#if COMMAND_LOGGER_ENABLED
            if (args.Length > 0 && args[0].ToLower() == "clog")
            {
                CommandLogger.Run();
                return;
            }
#endif

            KeyboardDeviceManager.Connected += (KeyboardDevice device) =>
            {
                Log("Connected to device '" + device.State.ModelName + "' model:" + device.State.ModelId +
                    " fw:" + device.State.FirmwareVersion);
                WebGUI.UpdateDeviceList();

                string file = GetUserDataFile(device);
                if (!string.IsNullOrEmpty(file))
                {
                    try
                    {
                        string dir = Path.GetDirectoryName(file);
                        if (!Directory.Exists(dir))
                        {
                            Directory.CreateDirectory(dir);
                        }
                        if (!File.Exists(file))
                        {
                            File.WriteAllText(file, string.Empty, Encoding.UTF8);
                        }
                    }
                    catch
                    {
                    }
                }
            };
            KeyboardDeviceManager.Disconnected += (KeyboardDevice device) =>
            {
                Log("Disconnected from device '" + device.State.ModelName + "'");
                WebGUI.UpdateDeviceList();
            };
            KeyboardDeviceManager.StartListener();

            if (asGUI)
            {
                Process   currentProc = Process.GetCurrentProcess();
                Process[] procs       = Process.GetProcessesByName(currentProc.ProcessName);
                try
                {
                    foreach (Process proc in procs)
                    {
                        try
                        {
                            if (proc != currentProc && proc.Id != currentProc.Id)
                            {
                                proc.Kill();
                            }
                        }
                        catch
                        {
                        }
                    }
                }
                finally
                {
                    foreach (Process proc in procs)
                    {
                        proc.Close();
                    }
                }
                currentProc.Close();

                WebGUI.Run();
                while (WebGUI.LastPing > DateTime.Now - WebGUI.PingTimeout)
                {
                    Thread.Sleep(1000);
                }
                return;
            }

            bool running      = true;
            bool hasNullInput = false;
            while (running)
            {
                string line = Console.ReadLine();
                if (line == null)
                {
                    // Handler for potential issue where ReadLine() returns null - see https://github.com/pixeltris/GK6X/issues/8
                    if (hasNullInput)
                    {
                        Console.WriteLine("Cannot read from command line. Exiting.");
                        break;
                    }
                    hasNullInput = true;
                    continue;
                }
                hasNullInput = false;
                string[] splitted = line.Split();
                switch (splitted[0].ToLower())
                {
                case "close":
                case "exit":
                case "quit":
                    running = false;
                    break;

                case "cls":
                case "clear":
                    Console.Clear();
                    break;

                case "update_data":
                    if (splitted.Length > 1)
                    {
                        string path      = line.TrimStart();
                        int    spaceChar = path.IndexOf(' ');
                        if (spaceChar > 0)
                        {
                            path = path.Substring(spaceChar).Trim();
                        }
                        bool isValidPath = false;
                        try
                        {
                            if (Directory.Exists(path))
                            {
                                isValidPath = true;
                            }
                        }
                        catch
                        {
                        }
                        if (isValidPath)
                        {
                            UpdateDataFiles(path);
                            Log("done");
                        }
                        else
                        {
                            Log("Couldn't find path '" + path + "'");
                        }
                    }
                    else
                    {
                        Log("Bad input. Expected folder name.");
                    }
                    break;

                case "gui":
                    WebGUI.Run();
                    break;

                case "gui_to_txt":
                {
                    if (string.IsNullOrEmpty(WebGUI.UserDataPath))
                    {
                        Log("Load GUI first");
                    }
                    else
                    {
                        string userDataPath = WebGUI.UserDataPath;
                        int    accountId    = 0;
                        string accountDir   = Path.Combine(userDataPath, "Account", accountId.ToString());
                        if (Directory.Exists(accountDir))
                        {
                            foreach (KeyboardDevice device in KeyboardDeviceManager.GetConnectedDevices())
                            {
                                string deviceDir = Path.Combine(userDataPath, "Account", accountId.ToString(), "Devices", device.State.ModelId.ToString());
                                if (Directory.Exists(deviceDir))
                                {
                                    Dictionary <int, UserDataFile.Macro> macrosById = new Dictionary <int, UserDataFile.Macro>();
                                    UserDataFile userDataFile = new UserDataFile();
                                    foreach (string file in Directory.GetFiles(deviceDir, "*.cmf"))
                                    {
                                        string config = Encoding.UTF8.GetString(CMFile.Load(file));
                                        Dictionary <string, object> data = MiniJSON.Json.Deserialize(config) as Dictionary <string, object>;
                                        int           modelIndex         = (int)Convert.ChangeType(data["ModeIndex"], typeof(int));
                                        KeyboardLayer layer = (KeyboardLayer)modelIndex;

                                        //////////////////////////////////////////
                                        // Keys / macros (NOTE: Macros on different layers might wipe each other. look into.)
                                        //////////////////////////////////////////
                                        for (int i = 0; i < 2; i++)
                                        {
                                            string setStr = i == 0 ? "KeySet" : "FnKeySet";
                                            if (data.ContainsKey(setStr))
                                            {
                                                List <object> keys = data[setStr] as List <object>;
                                                foreach (object keyObj in keys)
                                                {
                                                    Dictionary <string, object> key = keyObj as Dictionary <string, object>;
                                                    int    keyIndex       = (int)Convert.ChangeType(key["Index"], typeof(int));
                                                    uint   driverValue    = KeyValues.UnusedKeyValue;
                                                    string driverValueStr = (string)key["DriverValue"];
                                                    if (driverValueStr.StartsWith("0x"))
                                                    {
                                                        if (uint.TryParse(driverValueStr.Substring(2), System.Globalization.NumberStyles.HexNumber, null, out driverValue))
                                                        {
                                                            if (KeyValues.GetKeyType(driverValue) == DriverValueType.Macro && key.ContainsKey("Task"))
                                                            {
                                                                Dictionary <string, object> task = key["Task"] as Dictionary <string, object>;
                                                                if (task != null && (string)task["Type"] == "Macro")
                                                                {
                                                                    Dictionary <string, object> taskData = task["Data"] as Dictionary <string, object>;
                                                                    string macroGuid = (string)taskData["GUID"];
                                                                    string macroFile = Path.Combine(userDataPath, "Account", accountId.ToString(), "Macro", macroGuid + ".cms");
                                                                    if (File.Exists(macroFile))
                                                                    {
                                                                        UserDataFile.Macro macro = new UserDataFile.Macro(null);
                                                                        macro.LoadFile(macroFile);
                                                                        macro.RepeatCount              = (byte)Convert.ChangeType(taskData["Repeats"], typeof(byte));
                                                                        macro.RepeatType               = (MacroRepeatType)(byte)Convert.ChangeType(taskData["StopMode"], typeof(byte));
                                                                        macro.Id                       = KeyValues.GetKeyData2(driverValue);
                                                                        macrosById[macro.Id]           = macro;
                                                                        userDataFile.Macros[macroGuid] = macro;
                                                                    }
                                                                }
                                                            }
                                                        }
                                                        else
                                                        {
                                                            driverValue = KeyValues.UnusedKeyValue;
                                                        }
                                                    }
                                                    if (keyIndex >= 0 && keyIndex < device.State.MaxLogicCode && driverValue != KeyValues.UnusedKeyValue)
                                                    {
                                                        KeyboardState.Key keyInfo = device.State.GetKeyByLogicCode(keyIndex);
                                                        if (keyInfo != null)
                                                        {
                                                            Dictionary <string, uint> vals = userDataFile.FindOrAddLayer(layer, i > 0).Keys;
                                                            if (Enum.IsDefined(typeof(DriverValue), driverValue))
                                                            {
                                                                vals[keyInfo.DriverValueName.ToLower()] = driverValue;
                                                            }
                                                            else
                                                            {
                                                                Log("Failed to map index " + keyIndex + " to " + driverValue + " on layer " + layer +
                                                                    (i > 0 ? " fn" : string.Empty));
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }

                                        //////////////////////////////////////////
                                        // Lighting
                                        //////////////////////////////////////////
                                        Dictionary <string, UserDataFile.LightingEffect> effects = new Dictionary <string, UserDataFile.LightingEffect>();
                                        string[] leHeaders = { "ModeLE", "DriverLE" };
                                        foreach (string leHeader in leHeaders)
                                        {
                                            if (data.ContainsKey(leHeader))
                                            {
                                                List <object> leEntries = data[leHeader] as List <object>;
                                                if (leEntries == null)
                                                {
                                                    // There's only one ModeLE
                                                    leEntries = new List <object>();
                                                    leEntries.Add(data[leHeader]);
                                                }
                                                foreach (object entry in leEntries)
                                                {
                                                    Dictionary <string, object> modeLE = entry as Dictionary <string, object>;
                                                    string leGuid = (string)modeLE["GUID"];
                                                    if (!string.IsNullOrEmpty(leGuid))
                                                    {
                                                        string filePath = Path.Combine(userDataPath, "Account", accountId.ToString(), "LE", leGuid + ".le");
                                                        if (!effects.ContainsKey(leGuid) && File.Exists(filePath))
                                                        {
                                                            UserDataFile.LightingEffect le = new UserDataFile.LightingEffect(userDataFile, null);
                                                            le.Load(device.State, Encoding.UTF8.GetString(CMFile.Load(filePath)));
                                                            le.Layers.Add(layer);
                                                            userDataFile.LightingEffects[leGuid] = le;
                                                            effects[leGuid] = le;
                                                        }
                                                    }
                                                    else
                                                    {
                                                        object leDataObj;
                                                        if (modeLE.TryGetValue("LEData", out leDataObj))
                                                        {
                                                            Dictionary <string, object> leData = leDataObj as Dictionary <string, object>;
                                                            if (leData != null)
                                                            {
                                                                // This should be static lighting data only
                                                                UserDataFile.LightingEffect le = new UserDataFile.LightingEffect(userDataFile, null);
                                                                le.LoadStatic(device.State, leData);
                                                                le.Layers.Add(layer);
                                                                userDataFile.LightingEffects[Guid.NewGuid().ToString()] = le;
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                    userDataFile.SaveFromGUI(device.State, Path.Combine(UserDataPath, device.State.ModelId + "_exported.txt"));
                                    Log("Done");
                                    break;
                                }
                            }
                        }
                        else
                        {
                            Log("Account settings not found for account id " + accountId);
                        }
                    }
                }
                break;

                case "gui_le":
                {
                    string userDataPath = WebGUI.UserDataPath;
                    string leName       = line.Trim();
                    int    spaceIndex   = leName.IndexOf(' ');
                    if (spaceIndex > 0)
                    {
                        leName = leName.Substring(spaceIndex).Trim();
                    }
                    else
                    {
                        leName = null;
                    }
                    if (!string.IsNullOrEmpty(leName))
                    {
                        if (!string.IsNullOrEmpty(userDataPath) && Directory.Exists(userDataPath))
                        {
                            string leDir      = Path.Combine(userDataPath, "Account", "0", "LE");
                            string leListFile = Path.Combine(leDir, "lelist.json");
                            if (File.Exists(leListFile))
                            {
                                bool          foundFile = false;
                                List <object> leList    = MiniJSON.Json.Deserialize(File.ReadAllText(leListFile)) as List <object>;
                                if (leList != null)
                                {
                                    foreach (object item in leList)
                                    {
                                        Dictionary <string, object> guidName = item as Dictionary <string, object>;
                                        if (guidName["Name"].ToString() == leName)
                                        {
                                            string leFileName = Path.Combine(leDir, guidName["GUID"].ToString() + ".le");
                                            if (File.Exists(leFileName))
                                            {
                                                foreach (char c in System.IO.Path.GetInvalidFileNameChars())
                                                {
                                                    leName = leName.Replace(c, '_');
                                                }
                                                string effectString = Encoding.UTF8.GetString(CMFile.Load(leFileName));
                                                effectString = CMFile.FormatJson(effectString);
                                                File.WriteAllText(Path.Combine(DataBasePath, "lighting", leName + ".le"), effectString);
                                                Program.Log("Copied '" + leName + "'");
                                                foundFile = true;
                                            }
                                        }
                                    }
                                }
                                if (!foundFile)
                                {
                                    Program.Log("Failed to find lighting effect '" + leName + "' (it's case sensitive)");
                                }
                            }
                            else
                            {
                                Program.Log("Failed to find file '" + leListFile + "'");
                            }
                        }
                    }
                    else
                    {
                        Program.Log("Invalid input. Expected lighting effect name.");
                    }
                }
                break;

                case "findkeys":
                {
                    Log(string.Empty);
                    Log("This is used to identify keys. Press keys to see their values. Missing keys will generally show up as '(null)' and they need to be mapped in the data files Data/devuces/YOUR_MODEL_ID/");
                    Log("The 'S' values are what you want to use to map keys in your UserData file.");
                    Log(string.Empty);
                    Log("Entering 'driver' mode and mapping all keys to callbacks.");
                    Log(string.Empty);
                    KeyboardDevice[] devices;
                    if (TryGetDevices(out devices))
                    {
                        foreach (KeyboardDevice device in devices)
                        {
                            device.SetLayer(KeyboardLayer.Driver);
                            device.SetIdentifyDriverMacros();
                        }
                    }
                }
                break;

                case "map":
                case "unmap":
                {
                    bool             map = splitted[0].ToLower() == "map";
                    KeyboardDevice[] devices;
                    KeyboardLayer    targetLayer;
                    bool             targetLayerIsFn;
                    TryParseLayer(splitted, 1, out targetLayer, out targetLayerIsFn);
                    bool hasTargetLayer = targetLayer != KeyboardLayer.Invalid;
                    if (TryGetDevices(out devices))
                    {
                        foreach (KeyboardDevice device in devices)
                        {
                            UserDataFile userData = UserDataFile.Load(device.State, GetUserDataFile(device));
                            if (userData == null)
                            {
                                Log("Couldn't find user data file '" + GetUserDataFile(device) + "'");
                                continue;
                            }

                            foreach (KeyValuePair <KeyboardLayer, KeyboardStateLayer> layer in device.State.Layers)
                            {
                                if (layer.Key == KeyboardLayer.Driver)
                                {
                                    continue;
                                }

                                if (hasTargetLayer && layer.Key != targetLayer)
                                {
                                    continue;
                                }

                                device.SetLighting(layer.Key, userData);
                                device.SetMacros(layer.Key, userData);

                                for (int i = 0; i < 2; i++)
                                {
                                    bool fn = i == 1;
                                    if (targetLayer != KeyboardLayer.Invalid && fn != targetLayerIsFn)
                                    {
                                        continue;
                                    }

                                    // Setting keys to 0xFFFFFFFF is preferable compared to using what is defined in
                                    // files as this will use what is defined in the firmware.
                                    uint[] driverValues = new uint[device.State.MaxLogicCode];
                                    for (int j = 0; j < driverValues.Length; j++)
                                    {
                                        driverValues[j] = KeyValues.UnusedKeyValue;
                                    }

                                    if (map)
                                    {
                                        UserDataFile.Layer userDataLayer;
                                        if (fn)
                                        {
                                            userData.FnLayers.TryGetValue(layer.Key, out userDataLayer);
                                        }
                                        else
                                        {
                                            userData.Layers.TryGetValue(layer.Key, out userDataLayer);
                                        }
                                        if (userDataLayer != null)
                                        {
                                            for (int j = 0; j < driverValues.Length; j++)
                                            {
                                                KeyboardState.Key key = device.State.GetKeyByLogicCode(j);
                                                if (key != null)
                                                {
                                                    driverValues[j] = userDataLayer.GetKey(key);
                                                }
                                            }
                                        }
                                    }
                                    device.SetKeys(layer.Key, driverValues, fn);
                                }
                            }

                            // This is required to "refresh" the keyboard with the updated key info
                            if (hasTargetLayer)
                            {
                                device.SetLayer(targetLayer);
                            }
                            else
                            {
                                device.SetLayer(KeyboardLayer.Base);
                            }
                            Log("Done");
                        }
                    }
                }
                break;

                case "dumpkeys":
                {
                    int targetRow = -1;
                    if (splitted.Length > 1)
                    {
                        if (!int.TryParse(splitted[1], out targetRow))
                        {
                            targetRow = -1;
                        }
                    }
                    bool showLocationCodeInfo = false;
                    if (splitted.Length > 2)
                    {
                        showLocationCodeInfo = splitted[2] == "ex";
                    }

                    KeyboardDevice[] devices;
                    if (TryGetDevices(out devices))
                    {
                        foreach (KeyboardDevice device in devices)
                        {
                            Log("====== " + device.State.ModelId + " ======");
                            bool foundKey = false;
                            int  lastLeft = int.MinValue;
                            int  row      = 1;
                            foreach (KeyboardState.Key key in device.State.KeysByLocationCode.Values.OrderBy(
                                         x => x.Position.Top).ThenBy(x => x.Position.Left))
                            {
                                if (key.Position.Left >= 0)
                                {
                                    if (lastLeft > key.Position.Left && foundKey)
                                    {
                                        if (targetRow == -1)
                                        {
                                            Log("--------");
                                        }
                                        foundKey = false;
                                        row++;
                                    }
                                    lastLeft = key.Position.Left;
                                }

                                if (string.IsNullOrEmpty(key.KeyName) || !key.KeyName.StartsWith("LED-"))
                                {
                                    if (targetRow == -1 || row == targetRow)
                                    {
                                        Log(key.KeyName + " = " + key.DriverValueName +
                                            (showLocationCodeInfo ? " (" + key.LocationCode + ")" : string.Empty));
                                    }
                                    foundKey = true;
                                }
                            }
                        }
                    }
                }
                break;
                }
            }
        }