Pretty Key Names in C # (Forms)

I have a combo box that is populated with an enumeration of Keys (winforms).

The problem is that the key names are not very clear to inexperienced users. For example, the average user may not know what “OemPipe”, or “HanjaMode” is. So, how can I solve this problem and have some better key names?

I am going to make a dictionary with keys and their names, but filling out the dictionary itself is very time-consuming.

+6
source share
6 answers

Create a resource file that matches key names with a user-friendly string. If the resource file does not matter for a specific key, just go to the name of the key (as you do now), so you only need to identify those that are hard to understand, and you should not do everything in front.

It also allows you to localize into different languages ​​if you want.

EDIT: added sample code. It is assumed that you have a resource file named "KeyNames.resx"

 foreach (var key in Enum.GetValues(typeof(Keys))) { var keyName = KeyNames.ResourceManager.GetString(key.ToString()); if (keyName == null) keyName = key.ToString(); comboBox1.Items.Add(keyName); } 
+7
source

I assume that you allow the user to assign keys from your application (for example, keyboard shortcuts or game controls). Unfortunately, there is no easy way to get friendly key descriptions (Microsoft does not provide one or equivalent APIs), so you will need to create the mapping yourself.

As the answer currently accepted shows, using a resource file is a great way to do this to ensure that your application is internationalized.

For reference, here is the full implementation of Keys enumeration enumeration that I wrote some time ago: (using a resource file is still recommended, however)

 public static string GetDescription(Keys key) { switch (key) { //letters case Keys.A: case Keys.B: case Keys.C: case Keys.D: case Keys.E: case Keys.F: case Keys.G: case Keys.H: case Keys.I: case Keys.J: case Keys.K: case Keys.L: case Keys.M: case Keys.N: case Keys.O: case Keys.P: case Keys.Q: case Keys.R: case Keys.S: case Keys.T: case Keys.U: case Keys.V: case Keys.W: case Keys.X: case Keys.Y: case Keys.Z: return Enum.GetName(typeof(Keys), key); //digits case Keys.D0: return "0"; case Keys.NumPad0: return "Number Pad 0"; case Keys.D1: return "1"; case Keys.NumPad1: return "Number Pad 1"; case Keys.D2: return "2"; case Keys.NumPad2: return "Number Pad 2"; case Keys.D3: return "3"; case Keys.NumPad3: return "Number Pad 3"; case Keys.D4: return "4"; case Keys.NumPad4: return "Number Pad 4"; case Keys.D5: return "5"; case Keys.NumPad5: return "Number Pad 5"; case Keys.D6: return "6"; case Keys.NumPad6: return "Number Pad 6"; case Keys.D7: return "7"; case Keys.NumPad7: return "Number Pad 7"; case Keys.D8: return "8"; case Keys.NumPad8: return "Number Pad 8"; case Keys.D9: return "9"; case Keys.NumPad9: return "Number Pad 9"; //punctuation case Keys.Add: return "Number Pad +"; case Keys.Subtract: return "Number Pad -"; case Keys.Divide: return "Number Pad /"; case Keys.Multiply: return "Number Pad *"; case Keys.Space: return "Spacebar"; case Keys.Decimal: return "Number Pad ."; //function case Keys.F1: case Keys.F2: case Keys.F3: case Keys.F4: case Keys.F5: case Keys.F6: case Keys.F7: case Keys.F8: case Keys.F9: case Keys.F10: case Keys.F11: case Keys.F12: case Keys.F13: case Keys.F14: case Keys.F15: case Keys.F16: case Keys.F17: case Keys.F18: case Keys.F19: case Keys.F20: case Keys.F21: case Keys.F22: case Keys.F23: case Keys.F24: return Enum.GetName(typeof(Keys), key); //navigation case Keys.Up: return "Up Arrow"; case Keys.Down: return "Down Arrow"; case Keys.Left: return "Left Arrow"; case Keys.Right: return "Right Arrow"; case Keys.Prior: return "Page Up"; case Keys.Next: return "Page Down"; case Keys.Home: return "Home"; case Keys.End: return "End"; //control keys case Keys.Back: return "Backspace"; case Keys.Tab: return "Tab"; case Keys.Escape: return "Escape"; case Keys.Enter: return "Enter"; case Keys.Shift: case Keys.ShiftKey: return "Shift"; case Keys.LShiftKey: return "Shift (Left)"; case Keys.RShiftKey: return "Shift (Right)"; case Keys.Control: case Keys.ControlKey: return "Control"; case Keys.LControlKey: return "Control (Left)"; case Keys.RControlKey: return "Control (Right)"; case Keys.Menu: case Keys.Alt: return "Alt"; case Keys.LMenu: return "Alt (Left)"; case Keys.RMenu: return "Alt (Right)"; case Keys.Pause: return "Pause"; case Keys.CapsLock: return "Caps Lock"; case Keys.NumLock: return "Num Lock"; case Keys.Scroll: return "Scroll Lock"; case Keys.PrintScreen: return "Print Screen"; case Keys.Insert: return "Insert"; case Keys.Delete: return "Delete"; case Keys.Help: return "Help"; case Keys.LWin: return "Windows (Left)"; case Keys.RWin: return "Windows (Right)"; case Keys.Apps: return "Context Menu"; //browser keys case Keys.BrowserBack: return "Browser Back"; case Keys.BrowserFavorites: return "Browser Favorites"; case Keys.BrowserForward: return "Browser Forward"; case Keys.BrowserHome: return "Browser Home"; case Keys.BrowserRefresh: return "Browser Refresh"; case Keys.BrowserSearch: return "Browser Search"; case Keys.BrowserStop: return "Browser Stop"; //media keys case Keys.VolumeDown: return "Volume Down"; case Keys.VolumeMute: return "Volume Mute"; case Keys.VolumeUp: return "Volume Up"; case Keys.MediaNextTrack: return "Next Track"; case Keys.Play: case Keys.MediaPlayPause: return "Play"; case Keys.MediaPreviousTrack: return "Previous Track"; case Keys.MediaStop: return "Stop"; case Keys.SelectMedia: return "Select Media"; //IME keys case Keys.HanjaMode: case Keys.JunjaMode: case Keys.HangulMode: case Keys.FinalMode: //duplicate values: Hanguel, Kana, Kanji case Keys.IMEAccept: case Keys.IMEConvert: //duplicate: IMEAceept case Keys.IMEModeChange: case Keys.IMENonconvert: return null; //special keys case Keys.LaunchMail: return "Launch Mail"; case Keys.LaunchApplication1: return "Launch Favorite Application 1"; case Keys.LaunchApplication2: return "Launch Favorite Application 2"; case Keys.Zoom: return "Zoom"; //oem keys case Keys.OemSemicolon: //oem1 return ";"; case Keys.OemQuestion: //oem2 return "?"; case Keys.Oemtilde: //oem3 return "~"; case Keys.OemOpenBrackets: //oem4 return "["; case Keys.OemPipe: //oem5 return "|"; case Keys.OemCloseBrackets: //oem6 return "]"; case Keys.OemQuotes: //oem7 return "'"; case Keys.OemBackslash: //oem102 return "/"; case Keys.Oemplus: return "+"; case Keys.OemMinus: return "-"; case Keys.Oemcomma: return ","; case Keys.OemPeriod: return "."; //unsupported oem keys case Keys.Oem8: case Keys.OemClear: return null; //unsupported other keys case Keys.None: case Keys.LButton: case Keys.RButton: case Keys.MButton: case Keys.XButton1: case Keys.XButton2: case Keys.Clear: case Keys.Sleep: case Keys.Cancel: case Keys.LineFeed: case Keys.Select: case Keys.Print: case Keys.Execute: case Keys.Separator: case Keys.ProcessKey: case Keys.Packet: case Keys.Attn: case Keys.Crsel: case Keys.Exsel: case Keys.EraseEof: case Keys.NoName: case Keys.Pa1: case Keys.KeyCode: case Keys.Modifiers: return null; default: throw new NotSupportedException(Enum.GetName(typeof(Keys), key)); } } 

You can convert this to a resource file by running the following program and then adding output.resx to your application as a resource.

 static void Main(string[] args) { using(ResXResourceWriter writer = new ResXResourceWriter("output.resx")) { //since there are duplicate values, we need to clumsily look at each name, then parse foreach (string name in Enum.GetNames(typeof(Keys))) { object value = Enum.Parse(typeof(Keys), name); string description = GetDescription((Keys)value); if (description != null) writer.AddResource(new ResXDataNode(name, description)); } } } 

This will give you a resource file that can be used in the explanation in the accepted answer.

+3
source

If you want to provide a description for some keys, you can loop System.Windows.Forms.Keys and provide a method with a default key rename name:

 private void Form1_Load(object sender, EventArgs e) { foreach (System.Windows.Forms.Keys key in Enum.GetValues(typeof(System.Windows.Forms.Keys))) { comboBoxKeys.Items.Add(new { Value = key, Description = GetDescription(key) }); } comboBoxKeys.DisplayMember = "Description"; } private string GetDescription(System.Windows.Forms.Keys key) { switch(key) { case Keys.OemPipe: return "Better oem pipe description"; case Keys.HanjaMode: return "Ninja mode"; default: return key.ToString(); // default name } } 
+1
source

“OEM” means “Original Equipment Manufacturer”. In other words, the company that makes the keyboard. These names are special because there is no special key on the “regular” keyboard to generate | or inclusion of Hanja radicals in Korean (hunch). To receive | you need to hold the Shift key on most layouts. Some keyboard makers may add keys to standard layouts that do this.

Which should give you some pause, these keys are unlikely to be available on the user's keyboard, so presenting them as possible key combinations is not useful. More importantly, using the line you exit Keys from is a bad idea in itself. This will give you a hell of a headache when you need to localize your application so that other 5 billion people in this world start paying customers.

+1
source

You cannot write code yourself. Here you can use an approach that is probably close to minimal effort:

 string GetBaseKeyDescription(Keys k) { switch (k & ~Keys.Modifiers) { case Keys.OemPipe: return "Pipe |"; case Keys.OemPeriod: return "Dot ."; case Keys.HanjaMode: return "(Description of HanjaMode key)"; default: return k.ToString(); } } 

I'm not sure if you need the & ~Keys.Modifiers or not - if you do, you probably want to write more code to handle the modifiers, but I did similar things before.

0
source

You can assign attributes to listings. This is the best way. Otherwise, you will have to maintain parallel dictionaries or a growing list of switch-case .

Here is how you would mark the enumeration:

 public enum MyEnums { [Description("OEM Pipe")] OemPipe, [Description("Hanja Mode")] HanjaMode } 

You can get the Description attribute using the extension method:

 public static string ToEnumDescription(this Enum value) { FieldInfo fi = value.GetType().GetField(value.ToString()); DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes( typeof(DescriptionAttribute), false); if (attributes != null && attributes.Length > 0) return attributes[0].Description; else return value.ToString(); } 

To really get a description of the enumeration, you would name it as follows:

 var enumAsText = theEnum.ToEnumDescription(); 

You can also do this:

 MyEnums.OemPipe.ToEnumDescription(); 
0
source

Source: https://habr.com/ru/post/912332/


All Articles