2012-03-12 4 views
3

Я застрял при попытке использовать SystemParametersInfo. Я использую клавиатуру Dvorak, поэтому я пытаюсь сделать exe, чтобы дважды щелкнуть каждый раз, когда хочу изменить раскладку клавиатуры. Я использую SystemParametersInfo с C#. Я могу получить текущий язык ввода просто отлично. Но когда я пытаюсь установить язык ввода, я получаю возвращаемое значение false, и язык ввода не изменяется.Помощь с использованием SystemParametersInfo

Заранее благодарю за любую помощь.

Вот код, я использую:

class KeyboardSwitcher 
{ 
    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    public static extern bool SystemParametersInfo(uint uiAction, uint uiParam, ref uint pvParam, uint fWinIni); 

    private const uint SPI_GETDEFAULTINPUTLANG = 0x0059; 
    private const uint SPI_SETDEFAULTINPUTLANG = 0x005A; 
    private const uint SPIF_UPDATEINIFILE = 0x01; 
    private const uint SPIF_SENDWININICHANGE = 0x02; 
    private const uint DVORAK = 0xF0020409; 
    private const uint QWERTY = 0x04090409; 

    static void Main(string[] args) 
    { 
     uint currentLayout = 0; 
     uint newLayout = 0; 
     bool result = false; 
     int error = 0; 

     SystemParametersInfo(SPI_GETDEFAULTINPUTLANG, 0, ref currentLayout, 0); 
     if(currentLayout != DVORAK) { 
      newLayout = DVORAK; 
      /*result = SystemParametersInfo(SPI_SETDEFAULTINPUTLANG, 0, ref newLayout, SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE);*/ 
      result = SystemParametersInfo(SPI_SETDEFAULTINPUTLANG, 0, ref newLayout, SPIF_SENDWININICHANGE); 
      error = Marshal.GetLastWin32Error(); 
     } 
     else { 
      newLayout = QWERTY; 
      /*result = SystemParametersInfo(SPI_SETDEFAULTINPUTLANG, 0, ref newLayout, SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE);*/ 
      result = SystemParametersInfo(SPI_SETDEFAULTINPUTLANG, 0, ref newLayout, SPIF_SENDWININICHANGE); 
      error = Marshal.GetLastWin32Error(); 
     } 

     Console.WriteLine(">>> Current Layout <<<"); 
     Console.WriteLine("0x" +currentLayout.ToString("X")); 
     Console.WriteLine(">>> New Layout <<<"); 
     Console.WriteLine("0x" +newLayout.ToString("X")); 
     Console.WriteLine("Change Successful >>> " +result); 
     Console.WriteLine(error); 
     Console.WriteLine(">>> Final Layout <<<"); 
     uint finalLayout = 0; 
     SystemParametersInfo(SPI_GETDEFAULTINPUTLANG, 0, ref finalLayout, 0); 
     Console.WriteLine("0x" +finalLayout.ToString("X")); 
     Console.WriteLine("Press any key to continue..."); 
     Console.ReadKey(true); 
    } 
} 

UPDATE:

Я бросил в Console.WriteLine (Marshal.GetLastWin32Error()); с остальными операциями печати и возвращается 0. Перед чтением комментариев я также попробовал GetLastError(), импортировав Kernel32.dll, и он также вернулся 0. Спасибо за ваши ответы.

ОБНОВЛЕНИЕ 2: Я изменил свой код, чтобы показать использование GetLastWin32Error().

Вот результат, когда у меня установлен Dvorak в качестве языка ввода по умолчанию.

>>> Current Layout <<< 
0xF0020409 
>>> New Layout <<< 
0x4090409 
Change Successful >>> True 
Error Code >>> 0 
>>> Final Layout <<< 
0x4090409 
Press any key to continue... 

Вот результат, когда у меня есть Qwerty в качестве языка ввода по умолчанию.

>>> Current Layout <<< 
0x4090409 
>>> New Layout <<< 
0xF0020409 
Change Successful >>> True 
Error Code >>> 0 
>>> Final Layout <<< 
0xF0020409 
Press any key to continue... 

Я получил шестигранные значения для макетов использовать SPI_GETDEFAULTINPUTLANG, когда я был каждый макет установлен по умолчанию. Как вы думаете, значение, которое оно возвращает, может отличаться от значения, которое мне нужно отправить?

Я провел некоторое исследование по классу InputLanguage, и я не считаю, что он подходит для этой ситуации, потому что свойство DefaultInputLanguage не имеет сеттера, и нет других методов для установки языка ввода по умолчанию.

UPDATE 3: Когда я изменяю четвертый параметр SystemParametersInfo только на SPIF_SENDWININICHANGE, он становится намного ближе к работе. Результат SET - True, и когда я запускаю программу обратно, она переключает язык взад и вперед. Таким образом, это означает, что что-то в Windows действительно меняется. Тем не менее, изменение нового отражается в панели управления, и клавиатура фактически не изменяется. Я чувствую, что мне нужен SPIF_UPDATEINIFILE, чтобы продвинуть изменение. Значение, которое я использую, правильно, не так ли? Я также обновил код и вывод, чтобы результат был немного более подробным.

+0

Что говорит GetLastError? –

+0

@Carey Вы имеете в виду Marshal.GetLastWin32Error. Никогда не вызывайте 'GetLastError' из управляемого кода. –

+0

К сожалению, не заметил тег. Так что да, сделайте это GetLastWin32Error. –

ответ

1

Чтобы сообщить программе, что язык был изменен без перезапуска, вам необходимо отправить окно приложения WM_INPUTLANGCHANGEREQUEST, а затем сообщение WM_INPUTLANGCHANGE, где lParam является идентификатором локали.