Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > Проблема с SendInput


Автор: under_sun 5.11.2008, 22:13
Приветствую.

Следующий код делает окно с дискриптором g_hWnd активным и посылает туда комбинацию клавиш Shift+O:
Код

LPARAM extraInfo = GetMessageExtraInfo();

INPUT keys[2] = { 
    { INPUT_KEYBOARD, { VK_SHIFT, 0, 0, 0, extraInfo } },
    { INPUT_KEYBOARD, { VkKeyScan('О'), 0, 0, 0, extraInfo } }
};

if ( IsIconic ( g_hWnd ) )
    ShowWindow( g_hWnd, SW_SHOWNORMAL );
        
SetForegroundWindow( g_hWnd );
    
SendInput( 2, keys, sizeof( INPUT ) );

Проблема в следующем: если мы посылаем комбинацию этих клавиш, например, в блокнот, то нормально печатается 'O'. Но если затем начинаем там набирать текст, то продолжают печататься заглавные буквы, как-будто Shift продолжает быть в нажатом состоянии.
Если использовать AttachThreadInput( GetWindowThreadProcessId( g_hWnd, NULL), GetCurrentThreadId(), TRUE ), ситуация та же.
Что я делаю не так?

Автор: GremlinProg 6.11.2008, 01:26
Цитата(under_sun @  6.11.2008,  00:13 Найти цитируемый пост)
то продолжают печататься заглавные буквы, как-будто Shift продолжает быть в нажатом состоянии

так и есть, поскольку код отпускания клавиш отсутствует.
Код

typedef struct tagKEYBDINPUT {
    WORD wVk;
    WORD wScan;
    DWORD dwFlags;
    DWORD time;
    ULONG_PTR dwExtraInfo;
} KEYBDINPUT, *PKEYBDINPUT;

ключевые поля: wVk и dwFlags.
флаг KEYEVENTF_KEYUP отпускает клавишу, если он отсутствует, значит клавиша нажата.
если для обычных клавиш это не так важно, то для управляющих, таких как Ctrl, Shift, Caps и т.п. это существенно.
у тебя получается, что SHIFT залипла.

добавь код, отпускающий шифт.

Автор: under_sun 6.11.2008, 22:23
Сделал так:
Код

INPUT keys[2] = { 
    { INPUT_KEYBOARD, { VK_SHIFT, 0, KEYEVENTF_KEYUP, 0, extraInfo } },
    { INPUT_KEYBOARD, { VkKeyScan('O'), 0, 0, 0, extraInfo } }
};

Не знаю почему, но проблема осталась.
Пробовал еще так:
Код

INPUT keys[2] = { 
    { INPUT_KEYBOARD, { VK_SHIFT, 0, KEYEVENTF_KEYUP, 0, extraInfo } },
    { INPUT_KEYBOARD, { VkKeyScan('O'), 0, KEYEVENTF_KEYUP, 0, extraInfo } }
};

Где подвох smile?

Автор: GremlinProg 6.11.2008, 23:59
Цитата(under_sun @  7.11.2008,  00:23 Найти цитируемый пост)
Где подвох

все там же
Код

INPUT keys[] = { 
    { INPUT_KEYBOARD, { VK_SHIFT, 0, 0, 0, 0 } },
    { INPUT_KEYBOARD, { VkKeyScan('O'), 0, 0, 0, 0 } }
    { INPUT_KEYBOARD, { VK_SHIFT, 0, KEYEVENTF_KEYUP, 0, 0 } },
    { INPUT_KEYBOARD, { VkKeyScan('O'), 0, KEYEVENTF_KEYUP, 0, 0 } }
};

Автор: under_sun 7.11.2008, 00:30
Проверил, все равно Shift залипает. Кроме того надо одну 'O' печатать.

Автор: GremlinProg 7.11.2008, 00:55
Код

SendInput( 4, keys, sizeof( INPUT ) );


Добавлено через 3 минуты и 18 секунд
попробуй keybd_event

Добавлено через 11 минут и 32 секунды
ну или 'O' вместо VkKeyScan('O')
Цитата

The VkKeyScan function translates a character to the corresponding virtual-key code and shift state for the current keyboard.

Автор: under_sun 11.11.2008, 19:52
GremlinProg, спасибо. 
С keybd_event заработало. Но я так и не понял причины, почему с SendInput не работает.

Автор: dumb 11.11.2008, 20:59
Цитата(under_sun @  11.11.2008,  20:52 Найти цитируемый пост)
Но я так и не понял причины, почему с SendInput не работает. 
потому что желательна хотя бы минимальная задержка между "нажатием" и "отпусканием". поэтому и между keybd_event обычно Sleep'ы ставят небольшие. а ты все в одном пакете.

Автор: GremlinProg 11.11.2008, 22:53
не, дело не в задержке, смотрим определение союза:
Код

typedef struct tagINPUT { 
  DWORD type; 
  union {MOUSEINPUT mi; 
            KEYBOARDINPUT ki;
            HARDWAREINPUT hi;
           };
  }INPUT, *PINPUT;

typedef struct tagMOUSEINPUT {
    LONG dx;
    LONG dy;
    DWORD mouseData;
    DWORD dwFlags;
    DWORD time;
    ULONG_PTR dwExtraInfo;
} MOUSEINPUT, *PMOUSEINPUT;

typedef struct tagKEYBDINPUT {
    WORD wVk;
    WORD wScan;
    DWORD dwFlags;
    DWORD time;
    ULONG_PTR dwExtraInfo;
} KEYBDINPUT, *PKEYBDINPUT;

суть в том, что в союзе первый член типа MOUSEINPUT, у которого первые два поля типа LONG
в союзах агрегатаов инициализация идет сначала, т.е. первый компонент союза, второй, и т.д., следовательно KEYEVENTF_KEYUP пишется не в поле dwFlags, а в поле mouseData, которое находится по большему смещению. отсюда и залипание клавиш.

вот в таком варианте и SendInput работает
Код

INPUT keys[4];
::memset(keys,0,sizeof(keys));

keys[0].type        = INPUT_KEYBOARD;
keys[0].ki.wVk        = VK_SHIFT;
keys[0].ki.dwFlags    = 0;

keys[1].type        = INPUT_KEYBOARD;
keys[1].ki.wVk        = 'O';
keys[1].ki.dwFlags    = 0;

keys[2].type        = INPUT_KEYBOARD;
keys[2].ki.wVk        = 'O';
keys[2].ki.dwFlags    = KEYEVENTF_KEYUP;

keys[3].type        = INPUT_KEYBOARD;
keys[3].ki.wVk        = VK_SHIFT;
keys[3].ki.dwFlags    = KEYEVENTF_KEYUP;

::SendInput(4,keys,sizeof(keys[0]));

ничего не залипает

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)