I encapsulated the key bindings of the game client into a reusable class that can be used for converting the key combinations stored as strings in the game client into .NET Keys values and associate the keys with the action bindings. These are the same key combination strings you would find in the WTF folder.
You will need to change the references to the memory reader/writer library to whatever flavour you use.
And this is how I dump all of the key bindings for a particular game client:Code:using System; using System.Collections.Generic; using Voodoo; using WarcraftVoodoo.Version41014333; using System.Windows.Forms; namespace WarcraftVoodoo { public class KeyBindings { // brute-force dictionary to quickly lookup key combinations stored as // strings and convert the string to a .NET Keys value private Dictionary<string, Keys> m_allPossibleKeys; // The raw key bindings stored in the game client. private CachedValue<Dictionary<string, string>> m_rawKeyBindgs; // The game client that this set of key bindings refers to. private GameClient m_gameClient; /// <summary> /// Construct a new key bindings instance for a game client. /// </summary> /// <param name="gc">The game client that this set of key bindings refers to.</param> public KeyBindings(GameClient gc) { m_gameClient = gc; CreateKeyCombinations(); // set up the reader delegate to read the raw key bindings from the game client m_rawKeyBindgs = new CachedValue<Dictionary<string, string>>(() => { return GetRawKeyBindings(); }); // key bindings don't change all that often, no point updating them 20 times a second m_rawKeyBindgs.UpdateInterval = TimeSpan.FromSeconds(30); } /// <summary> /// This function returns a dictionary of raw key combinations as strings /// as they are stored in the game client memory. The action binding is /// used as the dictionary key. /// </summary> public Dictionary<string, string> RawKeyBindings { get { return m_rawKeyBindgs.Value; } } /// <summary> /// This function returns a dictionary of key combinations in .NET Keys format /// along with the action binding that would be performed if that key combination /// were pressed by the user. The action binding is used as the dictionary key. /// /// Note that not all raw key bindings will be converted to interpreted key bindings, /// e.g. MOUSEBUTTON3 is not converted, nor is NUMLOCK. This is done for a number of /// technical reasons. /// </summary> public Dictionary<string, Keys> InterpretedKeyBindings { get { // convert the raw key bindings to interpreted key bindings. // TODO cache the interpreted key bindings rather than convert them on each request // TODO convert this loop to a cleaner LINQ version Dictionary<string, Keys> interpretedBindings = new Dictionary<string, Keys>(); foreach (KeyValuePair<string, string> rawBinding in m_rawKeyBindgs.Value) { if (m_allPossibleKeys.ContainsKey(rawBinding.Value) == true) { interpretedBindings[rawBinding.Key] = m_allPossibleKeys[rawBinding.Value]; } } return interpretedBindings; } } /// <summary> /// This function creates a dictionary of all possible valid keys /// with the three modifier keys applied to each key in the permissible /// combinations. /// This function is a brute-force method of looking up a key with modifiers /// string in the dictionary as it is extracted from the game client and /// converting it directly in to its .NET equivalent. /// This could also be done with a regular expression but this is a small /// speed optimisation at the expense of a little memory. /// </summary> private void CreateKeyCombinations() { Dictionary<string, System.Windows.Forms.Keys> dotNetKeys = new Dictionary<string, System.Windows.Forms.Keys>(); #region key mappings // This is fugly but gets the job done when needing to pre-populate the dictionary simply // Credit to amadmonk for typing out the original table. // Errors fixed by Emily Dearheart Stranger. dotNetKeys["0"] = Keys.D0; dotNetKeys["1"] = Keys.D1; dotNetKeys["2"] = Keys.D2; dotNetKeys["3"] = Keys.D3; dotNetKeys["4"] = Keys.D4; dotNetKeys["5"] = Keys.D5; dotNetKeys["6"] = Keys.D6; dotNetKeys["7"] = Keys.D7; dotNetKeys["8"] = Keys.D8; dotNetKeys["9"] = Keys.D9; dotNetKeys["-"] = Keys.OemMinus; dotNetKeys["="] = Keys.Oemplus; dotNetKeys["A"] = Keys.A; dotNetKeys["B"] = Keys.B; dotNetKeys["C"] = Keys.C; dotNetKeys["D"] = Keys.D; dotNetKeys["E"] = Keys.E; dotNetKeys["F"] = Keys.F; dotNetKeys["G"] = Keys.G; dotNetKeys["H"] = Keys.H; dotNetKeys["I"] = Keys.I; dotNetKeys["J"] = Keys.J; dotNetKeys["K"] = Keys.K; dotNetKeys["L"] = Keys.L; dotNetKeys["M"] = Keys.M; dotNetKeys["N"] = Keys.N; dotNetKeys["O"] = Keys.O; dotNetKeys["P"] = Keys.P; dotNetKeys["Q"] = Keys.Q; dotNetKeys["R"] = Keys.R; dotNetKeys["S"] = Keys.S; dotNetKeys["T"] = Keys.T; dotNetKeys["U"] = Keys.U; dotNetKeys["V"] = Keys.V; dotNetKeys["W"] = Keys.W; dotNetKeys["X"] = Keys.X; dotNetKeys["Y"] = Keys.Y; dotNetKeys["Z"] = Keys.Z; dotNetKeys["UP"] = Keys.Up; dotNetKeys["DOWN"] = Keys.Down; dotNetKeys["LEFT"] = Keys.Left; dotNetKeys["RIGHT"] = Keys.Right; dotNetKeys["SPACE"] = Keys.Space; //dotNetKeys["NUMLOCK"] = Keys.NumLock; // doesn't work w/PostMessage dotNetKeys["ESCAPE"] = Keys.Escape; dotNetKeys["F1"] = Keys.F1; dotNetKeys["F2"] = Keys.F2; dotNetKeys["F3"] = Keys.F3; dotNetKeys["F4"] = Keys.F4; dotNetKeys["F5"] = Keys.F5; dotNetKeys["F6"] = Keys.F6; dotNetKeys["F7"] = Keys.F7; dotNetKeys["F8"] = Keys.F8; dotNetKeys["F9"] = Keys.F9; dotNetKeys["F10"] = Keys.F10; dotNetKeys["F11"] = Keys.F11; dotNetKeys["F12"] = Keys.F12; dotNetKeys["F13"] = Keys.F13; dotNetKeys["F14"] = Keys.F14; dotNetKeys["F15"] = Keys.F15; dotNetKeys["F16"] = Keys.F16; dotNetKeys["F17"] = Keys.F17; dotNetKeys["F18"] = Keys.F18; dotNetKeys["F19"] = Keys.F19; dotNetKeys["F20"] = Keys.F20; dotNetKeys["F21"] = Keys.F21; dotNetKeys["F22"] = Keys.F22; dotNetKeys["F23"] = Keys.F23; dotNetKeys["F24"] = Keys.F24; dotNetKeys["PAGEUP"] = Keys.PageUp; dotNetKeys["PAGEDOWN"] = Keys.PageDown; dotNetKeys["ENTER"] = Keys.Return; dotNetKeys["INSERT"] = Keys.Insert; dotNetKeys["DELETE"] = Keys.Delete; dotNetKeys["HOME"] = Keys.Home; dotNetKeys["END"] = Keys.End; dotNetKeys["/"] = Keys.OemQuestion; dotNetKeys["'"] = Keys.Oem7; dotNetKeys["["] = Keys.OemOpenBrackets; dotNetKeys["]"] = Keys.OemCloseBrackets; dotNetKeys["TAB"] = Keys.Tab; dotNetKeys["NUMPAD0"] = Keys.NumPad0; dotNetKeys["NUMPAD1"] = Keys.NumPad1; dotNetKeys["NUMPAD2"] = Keys.NumPad2; dotNetKeys["NUMPAD3"] = Keys.NumPad3; dotNetKeys["NUMPAD4"] = Keys.NumPad4; dotNetKeys["NUMPAD5"] = Keys.NumPad5; dotNetKeys["NUMPAD6"] = Keys.NumPad6; dotNetKeys["NUMPAD7"] = Keys.NumPad7; dotNetKeys["NUMPAD8"] = Keys.NumPad8; dotNetKeys["NUMPAD9"] = Keys.NumPad9; dotNetKeys["NUMPADMULTIPLY"] = Keys.Multiply; dotNetKeys["NUMPADMINUS"] = Keys.Subtract; dotNetKeys["NUMPADPLUS"] = Keys.Add; dotNetKeys["NUMPADDIVIDE"] = Keys.Divide; #endregion m_allPossibleKeys = new Dictionary<string, Keys>(); // The magic value 8 is derived from the fact that there are three possible modifier // keys, Alt, Ctrl and Shift. Each modifier key can be either depressed or released. // With those details in mind, three modifier keys provides for eight possible // combinations of modifiers, or 2 ^ 3 possible combinations, whereby 2 // is a binary value indicating whether the key is pressed or released, // and 3 represents the three possible modifier keys. // (Yeah, clear as mud, there are 8 possible combinations given 3 distinct modifier keys.) const int ModifierCombinations = 8; for (int modifiers = 0; modifiers < ModifierCombinations; modifiers++) { // Assemble the key string with modifiers applied and the .NET Keys value with modifiers OR'ed in. // Note: Not using a string builder as the set up time is longer than the copying operation of // an immutable object. string modifierString = String.Empty; Keys modifierKeys = Keys.None; // apply the ALT key modifier if ((modifiers & 1) == 1) { modifierString = "ALT-"; modifierKeys |= Keys.Alt; } // apply the CTRL key modifier if ((modifiers & 2) == 2) { modifierString += "CTRL-"; modifierKeys |= Keys.Control; } // apply the SHIFT key modifier if ((modifiers & 4) == 4) { modifierString += "SHIFT-"; modifierKeys |= Keys.Shift; } // apply the assembled modifier to each of the possible valid keys foreach (KeyValuePair<string, Keys> keyKeys in dotNetKeys) { string baseKeyString = keyKeys.Key; Keys baseKey = keyKeys.Value; string finalKeyString = modifierString + baseKeyString; Keys finalKey = modifierKeys | baseKey; // store the .NET Keys value in the dictionary with the key string as the dictionary key m_allPossibleKeys[finalKeyString] = finalKey; } } } // TODO deprecated function on 11/03/01, delete after 11/09/01 if no longer needed //public Dictionary<string, Keys> GetInterpretedKeyBindings() //{ // Dictionary<string, System.Windows.Forms.Keys> remappedBindings = new Dictionary<string, System.Windows.Forms.Keys>(); // Dictionary<string, string> rawKeyBindings = GetRawKeyBindings(); // foreach (KeyValuePair<string, string> binding in rawKeyBindings) // { // Regex keysUsed = new Regex(@"(ALT-)?(CTRL-)?(SHIFT-)?([A-Z0-9-\][='`,\./*+;\\]*)"); // Match match = keysUsed.Match(binding.Value); // if (match.Success == false) // { // Log.LogError("I found a key, but I couldn't interpret it."); // } // else if (match.Groups.Count == 0) // { // Log.LogError("I found a key, but I couldn't interpret it."); // } // else // { // Keys remappedKeys = Keys.None; // if (match.Groups[1].Value.Equals("ALT-") == true) // { // remappedKeys |= Keys.Alt; // } // if (match.Groups[2].Value.Equals("CTRL-") == true) // { // remappedKeys |= Keys.Control; // } // if (match.Groups[3].Value.Equals("SHIFT-") == true) // { // remappedKeys |= Keys.Shift; // } // Keys key; // string keyString = match.Groups[4].Value.ToString(); // bool keyFound = keyToKeys.TryGetValue(keyString, out key); // if (keyFound) // { // remappedKeys |= key; // Log.LogDebug(String.Format("Interpreted {0} as {1} ({2})", binding.Key, remappedKeys, binding.Value)); // remappedBindings[binding.Key] = remappedKeys; // } // else // { // Log.LogInfo(String.Format(@"Found a key \"{0}\" but cannot interpret it", binding.Value)); // } // } // } // return remappedBindings; //} /// <summary> /// This function is an enumerator that iterates over the linked list of key bindings /// </summary> /// <returns>A pointer to the next key binding in the linked list</returns> private IEnumerable<uint> BindingsList() { // locate the key bindings linked list in game client memory and read the first binding in the list uint bindingsManager = m_gameClient.MemoryEditor.ReadUInt(m_gameClient.ToAbsoluteAddress(LocalPlayerAddress.KeyBindings)); uint currentAddress = m_gameClient.MemoryEditor.ReadUInt(bindingsManager + KeyBindingsOffset.First); while ((currentAddress != 0) && ((currentAddress & 1) == 0)) { yield return currentAddress; // read the next key binding in the linked list uint nextAddress = m_gameClient.MemoryEditor.ReadUInt(bindingsManager + KeyBindingsOffset.Next); currentAddress = m_gameClient.MemoryEditor.ReadUInt(currentAddress + nextAddress + sizeof(uint)); } } /// <summary> /// This function scans the linked list of key bindings in memory and returns /// a dictionary containing the key combination and the action binding that /// is performed when that particular key combination is pressed by the user. /// </summary> /// <returns>Dictionar of key combinations and action bindings. The action bindings are the dictionary keys.</returns> private Dictionary<string, string> GetRawKeyBindings() { // the maximum permissible string length to read const int MaxStringLength = 255; // for each key binding in the key bindings linked list // read the string that represents the key to be pressed // read the action binding that would occur if the key is pressed // store the key string in a dictionary with the action binding as the dictionary key Dictionary<string, string> keys = new Dictionary<string, string>(); foreach (uint addr in BindingsList()) { uint keyPtr = m_gameClient.MemoryEditor.ReadUInt(addr + KeyBindingsOffset.KeyString); string keyString = m_gameClient.MemoryEditor.ReadASCIIString(keyPtr, MaxStringLength); uint actionPtr = m_gameClient.MemoryEditor.ReadUInt(addr + KeyBindingsOffset.ActionString); string actionString = m_gameClient.MemoryEditor.ReadASCIIString(actionPtr, MaxStringLength); if (keyString.Length > 0 && actionString.Length > 0) { if (keys.ContainsKey(actionString) == false) { keys[actionString] = keyString; } } } return keys; } } }
Code:private void Debug_DumpLeadersKeyBindings() { PlayerCharacter leadPlayerCharacter = PartyManager.LeadPlayerCharacter; if (leadPlayerCharacter == null) { return; } WowLocalPlayer localPlayer = leadPlayerCharacter.LocalPlayer; if (localPlayer == null) { return; } Log.LogDebug(String.Format("These are all of the key bindings that {0} has.", localPlayer.Name)); Dictionary<string, Keys> bindings = localPlayer.KeyBindings.InterpretedKeyBindings; foreach (KeyValuePair<string, Keys> binding in bindings) { Log.LogDebug(String.Format("{0}\t\t{1}", binding.Key, binding.Value)); } }