Localization problems

Mar 6, 2010 at 7:46 AM

Hi.

Well, the suite works well in localized environments, including right-to-left contexts; thank you very much. but there are two major problems with KeyTips:

First and the simpler: if the keyboard is set to another layout than English, typing the Tip will not choose the appropriate item. This is in contrast with Office 2007 implementation where even with totally different keyboard layouts such as Arabic, typing the key will do.

Second: if the Keys property is set to a non ASCII character, there is no way to select that item using keyboard.

A suggested solution will be:

1-The Keys property should be changed to two different properties: ShownKeys and ActualKeys.
2-The actual key should perform based on the key being typed, not the resulting character, which is changed based on the active keyboard layout.

PS: one minor problem in an Right-To-Left context is that the Round corner in the bottom of the File shortcut should be reflected horizontally.

Bests,
Alireza

Coordinator
Mar 6, 2010 at 8:38 AM
Edited Mar 6, 2010 at 8:39 AM

Hello, Alireza.
This is good question, actually.

if the keyboard is set to another layout than English, typing the Tip will not choose the appropriate item
As a matter of fact I have Russian and English keyboard layouts. When I change the current layout keytips is selected correctly in my case. Please, provide additional info: what keyboards layouts and OS do you have.

if the Keys property is set to a non ASCII character, there is no way to select that item using keyboard. A suggested solution will be...
Yes, this is open question for us. One way to do it is what is you said. The better way is automatic keyboard layout consideration. And you know, .NET Framework provides the required functionality:
KeyConverter.ConvertToString(ITypeDescriptorContext, CultureInfo, Object) http://msdn.microsoft.com/en-us/library/system.windows.input.keyconverter.converttostring.aspx
BUT, this doesn't work on my PC, I submitted this in connect https://connect.microsoft.com/WPF/feedback/details/516844/keyconverter-converttostring-ignores-cultureinfo-parameter

Daniel

Mar 6, 2010 at 11:00 AM

Well Daniel, thanks for the good idea, this would be a great solution, but the method you mentioned does not work for me as well.
So I joined the connection you've created.

have a good time,

Alireza

Mar 6, 2010 at 2:33 PM

Hi

Actually the KeyConverter is not supposed to support keyboard layouts. The CultureInfo object is used by other converters to support culture specific changes in displaying information such as Date and numerals.

The more I searched for a suitable managed class to do this translation the less I found, but these unmanaged functions seem to do the trick:

ToUnicodeEx() http://msdn.microsoft.com/en-us/library/ms646322%28VS.85%29.aspx

VkKeyScanEx() http://msdn.microsoft.com/en-us/library/ms646332%28VS.85%29.aspx

well, I'm going to create a managed c++ class to proxy these and I'll inform you of any result.

Bests

Mar 9, 2010 at 8:12 AM

Hi. This class is still incomplete, but does what you expect from KeyConverter.ConvertToString.

If you use it, tell me to inform you of any updates.

public class KeyboardTranslator
	{
		#region interoperability
		[DllImport("user32.dll", CharSet = CharSet.Unicode, EntryPoint = "MapVirtualKeyExW", ExactSpelling = true)]
		private static extern uint MapVirtualKeyEx(uint uCode, uint uMapType, IntPtr dwhkl);

		[DllImport("user32.dll", CharSet = CharSet.Unicode, EntryPoint = "LoadKeyboardLayoutW", ExactSpelling = true)]
		private static extern IntPtr LoadKeyboardLayout(string pwszKLID, uint Flags);

		[DllImport("user32.dll", ExactSpelling = true)]
		private static extern bool UnloadKeyboardLayout(IntPtr hkl);

		[DllImport("user32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
		private static extern int ToUnicodeEx(uint wVirtKey, uint wScanCode, byte[] lpKeyState, StringBuilder pwszBuff, int cchBuff, uint wFlags, IntPtr dwhkl);

		[DllImport("user32.dll", CharSet = CharSet.Unicode, EntryPoint = "VkKeyScanExW", ExactSpelling = true)]
		private static extern ushort VkKeyScanEx(char ch, IntPtr dwhkl);

		[DllImport("user32.dll", ExactSpelling = true)]
		private static extern int GetKeyboardLayoutList(int nBuff, [Out, MarshalAs(UnmanagedType.LPArray)] IntPtr[] lpList);

		private const uint KLF_NOTELLSHELL = 0x00000080;
		#endregion

		IntPtr[] _existingLayouts;
		IntPtr _handleToKeyboardLayout;
		public KeyboardTranslator(CultureInfo culture)
		{
			int keyboardsCount = GetKeyboardLayoutList(0, null);
			_existingLayouts = new IntPtr[keyboardsCount];
			GetKeyboardLayoutList(keyboardsCount, _existingLayouts);
			_handleToKeyboardLayout = LoadKeyboardLayout(culture.KeyboardLayoutId.ToString("X").PadLeft(8, '0'), KLF_NOTELLSHELL);
		}

		static byte[] nullStates;
		static KeyboardTranslator()
		{
			nullStates = new byte[256];
		}
		
		private static char? TranslateKey(Key key, IntPtr handleToKeyboardLayout, ModifierKeys modifier = ModifierKeys.None)
		{
			int virtualKey = KeyInterop.VirtualKeyFromKey(key);
			uint scanCode = MapVirtualKeyEx((uint)virtualKey, 0, handleToKeyboardLayout);
			StringBuilder sb = new StringBuilder(10);
			int result;
			do
			{
				result = ToUnicodeEx((uint)virtualKey, scanCode, nullStates, sb, sb.Capacity, 0, handleToKeyboardLayout);
			} while (result > 1);
			if (result == 1)
				return sb.ToString()[0];
			return null;
		}

		public char? TranslateKey(Key key)
		{
			return TranslateKey(key, _handleToKeyboardLayout);
		}

		~KeyboardTranslator()
		{
			if (!_existingLayouts.Contains(_handleToKeyboardLayout))
				UnloadKeyboardLayout(_handleToKeyboardLayout);
		}
	}
Bests, Alireza

Coordinator
Mar 9, 2010 at 9:32 AM

Thank you for your help, Alireza!

Actually We have written something like this. BUT I have just read your code and fix our ;-)
Please, say why do you use do {...} while (result > 1);

Now user can write culture specific characters in KeyTip.Keys.
(CultureInfo.CurrentUICulture must be to the right culture to make it works properly).
It must work exactly as Microsoft Office 2007/2010.
Can you download the latest sources and test how it works in your environment?

Thanks again, Daniel

Mar 13, 2010 at 8:13 AM
Edited Mar 13, 2010 at 8:14 AM

Hi daVinci,

Glad to hear that, I'll test the new version ASAP.

The reason for the loop you mentioned is that some previous calls to the same function using the same layout may leave keys in the buffer and the result of the function call will be distorted by them.
Well, such scenario is not likely to happen in languages I'm working with, but according to the documentations, it seems necessary for some languages.

There is only one more concern: if in a certain language/layout, pressing a key will create multiple characters, the UI will trap in the loop. I don't know if such a layout/key exists,
but in that case we'll have to limit the maximum iterations allowed by the loop.

Bests and thanks for the great tool,
Alireza