public static UserDataFile Load(KeyboardState keyboard, string file) { if (!File.Exists(file)) { return(null); } UserDataFile result = new UserDataFile(); result.Load(keyboard, file, GroupType.Lighting, GroupType.Macro); result.Load(keyboard, file, GroupType.Layer); return(result); }
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(); }
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; } } }
public void SetLighting(KeyboardLayer layer, UserDataFile userData) { List <UserDataFile.LightingEffect> lightingEffects = userData.GetLightingEffects(layer); if (lightingEffects.Count > 0 || userData.NoLighting || userData.NoLightingLayers.Contains(layer)) { WritePacketNoResponse(OpCodes.LayerResetDataType, (byte)layer, null, (byte)KeyboardLayerDataType.Lighting); } if (lightingEffects.Count > 0) { using (Packet packet = new Packet()) { const int maxEffects = UserDataFile.LightingEffect.MaxEffects; packet.WriteBytes(new byte[maxEffects * (4 * 4)]); List <Tuple <int, int, int, int> > dataOffsets = new List <Tuple <int, int, int, int> >(); for (int i = 0; i < Math.Min(maxEffects, lightingEffects.Count); i++) { UserDataFile.LightingEffect lightingEffect = lightingEffects[i]; if (lightingEffect != null) { int data1Offset = packet.Index; int data1Count = 0; switch (lightingEffect.Type) { case LightingEffectType.Static: { data1Count = 1; packet.WriteUInt16((ushort)lightingEffect.Type); packet.WriteUInt16((ushort)(UserDataFile.LightingEffect.NumStaticLightingBytes)); uint[] keyColors = new uint[UserDataFile.LightingEffect.NumStaticLightingBytes / 4]; foreach (KeyValuePair <int, uint> keyColor in lightingEffect.KeyColors) { keyColors[keyColor.Key] = keyColor.Value; } foreach (uint color in keyColors) { packet.WriteUInt32(color); } } break; case LightingEffectType.Dynamic: { data1Count = lightingEffect.TotalFrames; foreach (UserDataFile.LightingEffect.Frame frame in lightingEffect.Frames) { for (int j = 0; j < frame.Count; j++) { packet.WriteUInt16((ushort)lightingEffect.Type); packet.WriteUInt16(22); // 22 bytes of data (176 bits) byte[] byteBits = new byte[22]; foreach (int keyCode in frame.KeyCodes) { int byteIndex = keyCode / 8; int bitIndex = keyCode % 8; byteBits[byteIndex] |= (byte)(1 << bitIndex); } packet.WriteBytes(byteBits); } } } break; } int data2Offset = packet.Index; int data2Count = 0; switch (lightingEffect.Type) { case LightingEffectType.Static: data2Offset = 0; data2Count = 0; break; case LightingEffectType.Dynamic: data2Count = lightingEffect.Params.Count; foreach (UserDataFile.LightingEffect.Param param in lightingEffect.Params) { packet.WriteByte((byte)param.ColorType); packet.WriteByte(32); // The size of the param buffer? (total size including self) // The keys impacted by the param (as a bit array) byte[] byteBits = new byte[22]; foreach (int keyCode in param.Keys) { int byteIndex = keyCode / 8; int bitIndex = keyCode % 8; byteBits[byteIndex] |= (byte)(1 << bitIndex); } packet.WriteBytes(byteBits); packet.WriteUInt32(param.Color); if (param.UseRawValues) { packet.WriteUInt16((ushort)param.Val1); packet.WriteUInt16((ushort)param.Val2); } else { switch (param.ColorType) { case LightingEffectColorType.Breathing: packet.WriteUInt16((ushort)(param.Val1 == 0 ? 0 : 100 / param.Val1)); packet.WriteUInt16((ushort)param.Val2); // "StayCount" break; default: // NOTE: RGB values seem to use 0x26 for the 2nd value? Is this just a random uninitialized variable? packet.WriteUInt16((ushort)(param.Val1 == 0 ? 0 : 360 / param.Val1)); packet.WriteUInt16(0); break; } } } break; } dataOffsets.Add(new Tuple <int, int, int, int>(data1Offset, data1Count, data2Offset, data2Count)); } } int tempIndex = packet.Index; packet.Index = 0; for (int i = 0; i < maxEffects; i++) { Tuple <int, int, int, int> offsets = i < lightingEffects.Count ? dataOffsets[i] : null; if (offsets != null) { packet.WriteInt32(offsets.Item1); packet.WriteInt32(offsets.Item2); packet.WriteInt32(offsets.Item3); packet.WriteInt32(offsets.Item4); } else { packet.WriteInt32(-1); packet.WriteInt32(-1); packet.WriteInt32(-1); packet.WriteInt32(-1); } } packet.Index = tempIndex; WritePacketNoResponse(OpCodes.LayerSetLightValues, (byte)layer, packet); } } }
public void SetMacros(KeyboardLayer layer, UserDataFile userData) { WritePacketNoResponse(OpCodes.LayerResetDataType, (byte)layer, null, (byte)KeyboardLayerDataType.Macros); // The following check has been disabled so that the WebGUI can assign macros without having to setup the keys /*if (userData.GetNumMacros(layer) == 0) * { * return; * }*/ using (Packet packet = new Packet()) { // TODO: This should be improved to only send the macros to the layers that require the macro foreach (UserDataFile.Macro macro in userData.Macros.Values) { if (macro.Id < 0) { continue; } if (macro.Actions.Count * 2 > byte.MaxValue) { Program.Log("Macro '" + macro.Name + "' has too many actions (" + macro.Actions.Count + ", limit is " + (byte.MaxValue / 2) + ")"); continue; } if (macro.Actions.Count == 0 && macro.Id >= 0) { Program.Log("Macro '" + macro.Name + "' doesn't have any actions!"); continue; } packet.WriteUInt16(0x55AA);// Macro magic (21930 / 0x55AA / AA 55) // Crc to be filled out once all data is written int crcIndex = packet.Index; packet.WriteUInt16(0); byte numActionInts = (byte)((macro.Actions.Count * 2) - (macro.UseTrailingDelay ? 0 : 1)); packet.WriteByte(numActionInts); packet.WriteByte((byte)macro.Id); packet.WriteByte((byte)macro.RepeatType); packet.WriteByte(macro.RepeatCount); int crcDataStartIndex = packet.Index; int crcDataEndIndex = packet.Index + (numActionInts * 4); for (int i = 0; i < 63; i++) { if (i < macro.Actions.Count) { UserDataFile.Macro.Action action = macro.Actions[i]; packet.WriteByte(action.KeyCode); packet.WriteByte((byte)action.Modifier); packet.WriteByte((byte)action.State); packet.WriteByte((byte)action.Type); if (i < macro.Actions.Count - 1 || (macro.UseTrailingDelay && i == macro.Actions.Count - 1)) { packet.WriteUInt16(action.Delay); //TODO: Investigate! (ushort)(action.Delay == 0 ? 0 : action.Delay / 2));// Delay seems to be doubled? packet.WriteByte(0); // Always 0? packet.WriteByte(3); // Always 3? (1/2 use no delay, 0/4 (and maybe others) seem to never stop pressing the key) } else { packet.WriteInt32(0); } } else { packet.WriteInt64(0); } } byte[] buffer = packet.GetBuffer(); byte[] bytesToCrc = new byte[crcDataEndIndex - crcDataStartIndex]; Buffer.BlockCopy(buffer, crcDataStartIndex, bytesToCrc, 0, bytesToCrc.Length); ushort crc = Crc16.GetCrc(bytesToCrc); // Always 0? packet.WriteByte(0); int tempIndex = packet.Index; packet.Index = crcIndex; packet.WriteUInt16(crc); packet.Index = tempIndex; } WritePacketNoResponse(OpCodes.LayerSetMacros, (byte)layer, packet); } }
static void Main(string[] args) { 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 (args.Length > 0 && args[0].ToLower() == "clog") { CommandLogger.Run(); return; } KeyboardDeviceManager.Connected += (KeyboardDevice device) => { Log("Connected to device '" + device.State.ModelName + "' model:" + device.State.ModelId + " fw:" + device.State.FirmwareVersion); 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 + "'"); }; KeyboardDeviceManager.StartListener(); bool running = true; while (running) { string line = Console.ReadLine(); 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 "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.DriverValue); } } } } 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 + " = " + (DriverValue)key.DriverValue + (showLocationCodeInfo ? " (" + key.LocationCode + ")" : string.Empty)); } foundKey = true; } } } } } break; } } KeyboardDeviceManager.StopListener(); }