Необходимо разобраться с циклом сообщений которые передаются окну!

Тема в разделе "WASM.BEGINNERS", создана пользователем amvoz, 12 сен 2011.

  1. amvoz

    amvoz Member

    Публикаций:
    0
    Регистрация:
    12 ноя 2008
    Сообщения:
    653
    Друзья! Пример взят отсюда, с туториалов Iczelion'а
    http://www.wasm.ru/article.php?article=1001003

    Ну так-то всё пости понятно, я пишу на С, ковыряюсь иногда с OllyDbg, но в одном вообще какой-то ступор на меня нашёл, никогда с окнами не работал, с консолью всё больше, итак, там пример, рисуется окно и такой вот цикл сообщений пишется:

    Код (Text):
    1. .WHILE TRUE   ; Enter message loop
    2.   invoke GetMessage, ADDR msg,NULL,0,0
    3. .BREAK .IF (!eax)
    4.   invoke TranslateMessage, ADDR msg
    5.   invoke DispatchMessage, ADDR msg
    6. .ENDW
    Так, раз за разом вызывается GetMessage, пока не вернёт 0, а за ней TranslateMessage, а теперь смотрите, в мои рассуждения TranslateMessage не вписыватеся никак.

    Итак: послали сообщение окну, где-то в недрах винды оно сформировалось в нужную структурку (типа: мышиное ли сообщение или клавиатурное ну и так далее), так потом эта структурка в очередь (суть некоторая область памяти) виндой же записалась, а, поскольку, GetMessage вызывается в цикле, то GetMessage это сообщение благополучно считала, нужным образом заполнило структурку msg, после чего вызвалась функция DispatchMessage, которая, в свою очередь сделала так: "DispatchMessage пеpесылает сообщение пpоцедуpе соответствующего окна." (так написано), ну , а процедура окна обработала сообщение.

    Но на фига тут TranslateMessage я хоть убей не пойму! Читаю:
    "TranslateMessage - это вспомогательная функция, котоpая обpабатывает ввод с клавиатуpы и генеpиpует новое сообщение (WM_CHAR), помещающееся в очеpедь сообщений. "

    И что это мне даёт? Я должен на клавиши нажимать что ли? Спасибо, кто откликнется
     
  2. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Ну если тебе не нужно автопреобразование WM_KEYDOWN в WM_CHAR, то можешь и не транслировать. Но, например, ввод символов в эдит-контролы осуществляется именно по WM_CHAR
     
  3. pivikov

    pivikov New Member

    Публикаций:
    0
    Регистрация:
    19 сен 2010
    Сообщения:
    19
    Как не специалист, не специалисту: эта муть очень важна если у тебя приложение обрабатывает HotKey :)
    Во, точняк.
     
  4. amvoz

    amvoz Member

    Публикаций:
    0
    Регистрация:
    12 ноя 2008
    Сообщения:
    653
    Хм. Так это что получается-то? "TranslateMessage - это вспомогательная функция, котоpая обpабатывает ввод с клавиатуpы и генеpиpует новое сообщение (WM_CHAR), помещающееся в очеpедь сообщений."

    То есть TranslateMessage каким-то хитрым способом преобразовало сообщение и вновь поставило его в очередь?
     
  5. pivikov

    pivikov New Member

    Публикаций:
    0
    Регистрация:
    19 сен 2010
    Сообщения:
    19
    Чего не понятного то?
    Передается указатель на структуру, далее ф-я "каким-то хитрым способом преобразовало" нужное и все, вызываем DispatchMessage.
     
  6. amvoz

    amvoz Member

    Публикаций:
    0
    Регистрация:
    12 ноя 2008
    Сообщения:
    653
    Вы что-то опускаете. Уверен, что неумышленно. Я в двух источниках уже прочёл, что одно и то же сообщение попадает в очередь дважды. Первый раз до вызова TranslateMessage, второй раз после TranslateMessage. Как так может получиться?
     
  7. pivikov

    pivikov New Member

    Публикаций:
    0
    Регистрация:
    19 сен 2010
    Сообщения:
    19
    Нуу эээ, добавляет да, гугл все найдет, правда ведь?
     
  8. amvoz

    amvoz Member

    Публикаций:
    0
    Регистрация:
    12 ноя 2008
    Сообщения:
    653
    Я правильно понял, что "одно и то же сообщение попадает в очередь дважды. Первый раз до вызова TranslateMessage, второй раз после TranslateMessage."? Просто скажите да или нет и всё. Просто это неправдоподобно. Хе, сообщение честно отстояло очередь, а потом ещё раз в ней стоять. Тут что-то не то.
     
  9. Ezrah

    Ezrah Member

    Публикаций:
    0
    Регистрация:
    22 мар 2011
    Сообщения:
    411
    amvoz
    Псевдокод для TranslateMessage (сильно упрощено и частный случай, но для понимания подойдёт):
    Код (Text):
    1. TranslateMessage(const MSG *lpMSG) {
    2.   if (lpMSG->message == WM_KEYDOWN) {
    3.     PostMessage(WM_CHAR);
    4.   }
    5. }
    Теперь очевидно, что нет.
     
  10. litrovith

    litrovith Member

    Публикаций:
    0
    Регистрация:
    20 июн 2007
    Сообщения:
    509
    amvoz, по идее в ядре ничего по два раза по два раза не повторяется (если не задействуются кривые руки ветвящиеся из известных мест).
     
  11. pivikov

    pivikov New Member

    Публикаций:
    0
    Регистрация:
    19 сен 2010
    Сообщения:
    19
    Нет, не одно и тоже. Сообщения разные.
    О, уже ответили, ну теперь то все понятно надеюсь :)
     
  12. amvoz

    amvoz Member

    Публикаций:
    0
    Регистрация:
    12 ноя 2008
    Сообщения:
    653
    Хорошо, условно назовём их разными. А тогда возникает другой вопрос: а второй-то раз с сообщением что делает?

    Сообщение встало в очередь, потом считалось, потом TranslateMessage его изменило и снова поставило в очередь
    Потом это сообщение (другое уже якобы) опять отстояло очередь и снова пришло на обработку TranslateMessage
    Щас-то TranslateMessage что с ним делает? Оно ведь уже обработано!
     
  13. amvoz

    amvoz Member

    Публикаций:
    0
    Регистрация:
    12 ноя 2008
    Сообщения:
    653
    Не, ну как ответили. Я вообще жду, что кто-то скажет: Айзелион неправ. И В.А. Безруков с его "Win32 API программирование", где чёрным по-белому о работе TranslateMessage "Сообщение WM_CHAR помещается в очередь и наследующей итерации цикла функции GetMessage() извлекает его для последующей обработки"
    ...То есть оно уже было в очереди в теперь второй раз туда пошло с другим именем
     
  14. litrovith

    litrovith Member

    Публикаций:
    0
    Регистрация:
    20 июн 2007
    Сообщения:
    509
    amvoz, вы же не Безруков и не Айзелион. Пилите, Шура, пилите.
     
  15. amvoz

    amvoz Member

    Публикаций:
    0
    Регистрация:
    12 ноя 2008
    Сообщения:
    653
    Правильно, поэтому мне можно сказать всё, что угодно. В смысле в мой адрес.
     
  16. amvoz

    amvoz Member

    Публикаций:
    0
    Регистрация:
    12 ноя 2008
    Сообщения:
    653
    Короче, поковырявшись в отладчике, я нашёл всё это более чем странным. Но других объяснений нет, придётся довольствоваться этим.
    При нажатии на клавишу сообщение становится в очередь второй раз с другим именем. И TranslateMessage вызовется второй раз но на этот раз сработает как бы "вхолостую" и поэтому вернёт ноль

    Во этот лишний круг и вводил меня в замешательство. Не проще было бы сделать, чтобы TranslateMessage просто напросто преобразовывало чё она там преобразовывает и не задействовать второй раз ни GetMessage ни TranslateMessage? Ну дело их. Всем спасибо и до свидания
     
  17. pivikov

    pivikov New Member

    Публикаций:
    0
    Регистрация:
    19 сен 2010
    Сообщения:
    19
    Ничего, мимо пропускает.
    Мы вроде уже разобрались, что ф-я не изменяет сообщение, а добавляет новое.
    Ничего, мимо пропускает.

    TranslateMessage реагирует только на определенные сообщения типа WM_KEYDOWN, UP и т.д. все.
    Ничего она по два раза не обрабатывает.

    Ладно сдаюсь, объяснять не мой конёк. Информации достаточно у тебя уже есть.
     
  18. amvoz

    amvoz Member

    Публикаций:
    0
    Регистрация:
    12 ноя 2008
    Сообщения:
    653
    Вникнем в термины "добавляет-изменяет"
    Итак, первый вызов TranslateMessage, структура msg

    C03D2- хэндл окна
    100- WM_KEYDOWN
    52- виртуалныый код клавиши "R" (я на неё нажал)
    130001 какой-то дополнительный параметр
    14EA985- время
    2E6- координаты курсора
    ___________________________________________

    И сразу же после этого вызов TranslateMessage

    C03D2- хэндл окна
    102- WM_CHAR
    EA- ANSI код клавиши "R" (я на неё нажал)
    130001 какой-то дополнительный параметр
    1530A20- время
    275- координаты курсора


    Так что чё уж тут добавляет, остаётся только догадываться. Скорее, именно изменяет. Хотя это разговор о терминах.
     
  19. Ezrah

    Ezrah Member

    Публикаций:
    0
    Регистрация:
    22 мар 2011
    Сообщения:
    411
    Перечитайте #5 и #9.
    WM_KEYDOWN сообщает виртуальный код нажатой клавиши. Например, нажали Shift + "1", вместе с WM_KEYDOWN придёт VK_1.
    WM_CHAR сообщает символ. Нажали Shift+"1" - WM_CHAR даст "!".
    Этот какой-то дополнительный параметр также описан в MSDN. Там передаются.флаги и некоторая иная информация (как то число повторов). Если было нажато Shift + "1", там будет содержаться флаг, что во время нажатия на клавишу "1", был зажат шифт.
    Возьмём другой пример. Shift + "2". Тут на значение символа влияет так же и язык. На русской раскладке этому сочетанию клавиш соответствует кавычка, на английской - собака. В обоих случаях в WM_KEYDOWN придет VK_2, а в WM_CHAR - либо @ либо ".
    TranslateMessage нужна для того, чтобы преобразовать Shift + "1" в "!" (Shift + "2" в @ или в " в зависимости от раскладки, и т.п.). Если Вы хотите делать это вручную (непонятно зачем), не вызывайте TranslateMessage.
    TranslateMessage ничего не меняет в исходном сообщении (WM_KEYDOWN), она лишь добавляет в очередь новое сообщение WM_CHAR, в котором содержится не виртуальный код клавиши, а печатаемый символ при зажатых клавишах.
    Тоже относится к WM_SYSKEYDOWN, WM_KEYUP и т.д.
    Всё упростил до не могу, если уж и так не понятно, то я тоже сдаюсь, ибо как об стенку горох.
    можно было написать после поста #5.
     
  20. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    amvoz
    Разницу чуЙствуешь? Клавиатура шлет только сообщения нажатия\отжатия клавиш WM_KEYDOWN\WM_KEYUP, причем у каждой клавиши есть уникальный идентификатор - виртуальный код (или скан-код), который не зависит от состояния клавиш Shift, CapsLock, раскладки клавиатуры и текущего языка ввода. Никакого ANSI-кода у клавиши нет. Поэтому TranslateMessage тем и занимается, что учитывает все эти состояния и генерит (постит в очередь) новое сообщение WM_CHAR c ANSI (или UNICODE) кодом символа. В твоем случае EA - это анси-код русской буквы "к" - это значит, что в момент нажатия клавиши "R" у тебя стоял русский язык с русской раскладкой и не были нажаты\зажаты клавиши Shift или CapsLock (а также Ctrl и Alt, т.к. в этом сл. сообщение WM_CHAR вообще бы не сгенерилось).

    Как я уже говорил, ввод символов в эдит-контролы (поля ввода, мемо, рич-эдит) осуществляется только по WM_CHAR, а WM_KEYDOWN\UP они обрабатывают только для перемещения\выделения по стрелкам и Home\End\PageUp\PageDown, удаления по Delete и т.п. Поэтому если не юзать TranslateMessage, то никакие WM_CHAR при нажатии клавиш генериться не будут, и соотв-но никакой текст в эдит-контролы вводиться также не будет. Если тебя это устраивает или ты хочешь сам анализировать состояние клавы\языка и сам генерить WM_CHAR, то можешь не юзать TranslateMessage, как г-рится "флаг в руки" ;)