Управление окном с клавиатуры
|
|
BLACK_CRAFTER666 | Дата: Пятница, 19.07.2013, 12:50 | Сообщение # 1 |
Сержант
Группа: Пользователи
Сообщений: 31
Статус: Offline
| Здравствуйте. Нужно сделать настройку клавиш для управления своим окном (типа как в играх). Сделал ListView, в котором ловлю сообщение WM_KEYDOWN и получаю код нажатой клавиши. http://i47.fastpic.ru/big/2013/0719/42/84f92301526f1ec8b79da42c0cc96942.jpg (почему-то тэги запрещены) Далее, код клавиши нужно присвоить некой переменной, чтобы потом отловить в WM_KEYDOWN главного окна. Примерно так:
Код WM_KEYDOWN: if wparam = <переменная к кодом клавиши> then // действие Но проблема в том, как в список клавиш добавить еще и модификатор (ctrl,alt,shift)? Конечно, можно их checkbox'ами оформить и if'ами прописать, но это же такая куча нелепой писанины! Должен же быть более рациональный способ? Например, можно как-то по-хитрому использовать HotKey не для глобальных горячих клавиш, а только для моего окна? Если да, то как? Другими словами, мне нужно следующее: 1) Нажимаю в своем окне клавишу J и срабатывает действие 1. Нажимаю Ctrl+J - срабатывает действие 2. 2) Сделать возможным переназначать эти клавиши и сохранить/загрузить их в/из ini-файл/реестр. Как это проще реализовать на WinAPI + Delphi 7? p.s. С ini-файлами и реестром работать умею. p.p.s. Пока это писал, подумал, что, по-видимому, нужно делать это с использованием HotKey. Ведь он просто хранит в себе комбинацию, а не регистрирует горячую клавишу. Как заставить окно реагировать на комбинацию, сохраненную в HotKey'е? Но, опять же, может ли HotKey хранить клавишу без модификаторов? p.p.p.s. Кажется, опять нагородил
Сообщение отредактировал BLACK_CRAFTER666 - Пятница, 19.07.2013, 12:52 |
|
| |
xaramamburu | Дата: Суббота, 20.07.2013, 19:35 | Сообщение # 2 |
Полковник
Группа: Администраторы
Сообщений: 240
Статус: Offline
| Цитата Нужно сделать настройку клавиш для управления своим окном (типа как в играх). А как в играх?
Цитата (почему-то тэги запрещены) Не знаю. Попробуйте использовать в место кодов клавиш их константы VK_LEFT и VK_RIGHT и т.д. список можно найти в интернете.
Цитата Например, можно как-то по-хитрому использовать HotKey не для глобальных горячих клавиш, а только для моего окна? Если да, то как? Другими словами, мне нужно следующее: 1) Нажимаю в своем окне клавишу J и срабатывает действие 1. Нажимаю Ctrl+J - срабатывает действие 2. А почему не хотите использовать собственные события окна OnKeyPress или OnKeyDown? Вот посмотрите здесь http://delphiworld.narod.ru/base/symphony_on_keyboard.html . А здесь пример с горячими клавишами http://basicsprog.ucoz.ru/forum/4-13-1 правда обычный без модификаторов (ctrl,alt,shift).
Цитата Но, опять же, может ли HotKey хранить клавишу без модификаторов? Не знаю, я с этим особо не работал.))))
|
|
| |
xaramamburu | Дата: Суббота, 20.07.2013, 22:08 | Сообщение # 3 |
Полковник
Группа: Администраторы
Сообщений: 240
Статус: Offline
| Да, можно еще использовать функцию GetKeyState (Определяет, каково состояние виртуальной клавиши: поднята, нажата или переключается.).
Вот небольшой пример, при нажатии клавиш 'A', 'W', 'S', 'D' в Label1 выводится сообщение 'Привет', а если нажата клавиша ctrl + 'A', ctrl + 'W', ctrl + 'S', ctrl + 'D' выводится сообщение 'Пока'. Код unit Unit1;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
type TForm1 = class(TForm) Label1: TLabel; procedure FormActivate(Sender: TObject); private { Private declarations } //описание процедуры обработчика сообщений procedure ProcessFormMessages(var Msg: tMsg; var Handled: Boolean); public { Public declarations } end;
var Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.ProcessFormMessages(var Msg: tMsg; var Handled: Boolean); begin { проверка наличия системного сообщения KeyDown } case Msg.Message of WM_KEYDOWN: if Msg.wParam in [$41, $57, $53, $44] then begin {Проверяем нажатие клавиши ctrl (если не нажата)} if GetKeyState(VK_CONTROL) and $80 = 0 then label1.Caption:='Привет' else label1.Caption:='Пока'; { сообщаем о том, что сообщение обработано } Handled := True; end; end; end; procedure TForm1.FormActivate(Sender: TObject); begin { Делаем ссылку на нового обработчика сообщений } Application.OnMessage := ProcessFormMessages; end;
end. а так: if (GetKeyState(VK_CONTROL) and GetKeyState(VK_SHIFT)) and $80 <> 0 then будет задействованы клавиши CONTROL + SHIFT.
Возможен еще и такой, более простой вариант (комбинация ctrl+ 'V') без задействования обработчика системных сообщений ProcessFormMessages: Код procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if (GetKeyState(VK_CONTROL) < 0) and (GetKeyState(Ord('V')) < 0) then ShowMessage('Привет'); end; Смотрите в интернете аналогичных примеров много.:)
|
|
| |
BLACK_CRAFTER666 | Дата: Воскресенье, 21.07.2013, 10:26 | Сообщение # 4 |
Сержант
Группа: Пользователи
Сообщений: 31
Статус: Offline
| cпасибо. Но это немного не то. Я слишком расплывчато описал суть вопроса. Цитата (xaramamburu) А почему не хотите использовать собственные события окна OnKeyPress или OnKeyDown? Потому, что я пишу на WinAPI без формы. Мне так, почему-то, удобнее, чем с формой) Да и проги работают быстрее и весят меньше) Еще раз опишу суть: Основная проблема не в том, чтобы перехватить нажатие именно комбинации клавиш с модификаторами. Меня на другом форуме уже научили, что при нажатии/отпусканию модификатора можно ставить/снимать флаг (boolean). Да и GetKeyState лишним не будет Проблема в том, как запомнить комбинацию с модификатором в ListView и как считать этот модификатор при нажатии? Если не использовать модификатор, то это делается элементарно. Я уже сделал пример и он работает. Если хотите - выложу код. Там ничего сложного. Однако, о чем идет речь - я не знаю, как таким способом изменять и запоминать модификатор. Что-то похожее сделано в плеере Light Alloy в настройках клавиатуры (ссылка на скриншот в первом посте). Но как это сделано? Вот вопрос. p.s. Что значит and $80 = 0? Что за проверка?
|
|
| |
xaramamburu | Дата: Воскресенье, 21.07.2013, 20:06 | Сообщение # 5 |
Полковник
Группа: Администраторы
Сообщений: 240
Статус: Offline
| Цитата я пишу на WinAPI без формы. И охота вам так издеваться. Я как то пробовал, но у меня терпения не хватило. Ну и я кажется понял ваш вопрос. Вы хотите, чтоб пользователь мог сам назначать комбинацию клавиш так? И вы хотите определить какую комбинацию он нажал, запомнить ее и в дальнейшем сохранить в INI файле или где то еще так? Как я понял саму клавишу вы определять научились. Осталось понять нажат ли какой либо модификатор (ctrl,alt,shift). Думаю здесь можно поступить также как у меня в примере:
WM_KEYDOWN: if Msg.wParam in [перечисляем список разрешенных клавиш] then begin запоминаем код нажатой клавиши в переменную; {Проверяем нажатие клавиши ctrl } if GetKeyState(VK_CONTROL) and $80 <> 0 then запоминаем модификатор VK_CONTROL или его код в переменную; {Проверяем нажатие клавиши shift } if GetKeyState(VK_SHIFT) and $80 <> 0 then запоминаем модификатор VK_SHIFT или его код в переменную; {Проверяем нажатие клавиши alt } if GetKeyState(VK_MENU) and $80 <> 0 then запоминаем модификатор VK_MENU или его код в переменную; { сообщаем о том, что сообщение обработано } Handled := True;
В место переменной наверное можно выгрузить в ListView.
Процедура проверки абсолютна аналогична:
WM_KEYDOWN: if Msg.wParam in [перечисляем список разрешенных клавиш] then begin запоминаем код нажатой клавиши в переменную; {Проверяем нажатие клавиши ctrl } if GetKeyState(VK_CONTROL) and $80 <> 0 then запоминаем модификатор VK_CONTROL или его код в переменную; {Проверяем нажатие клавиши shift } if GetKeyState(VK_SHIFT) and $80 <> 0 then запоминаем модификатор VK_SHIFT или его код в переменную; {Проверяем нажатие клавиши alt } if GetKeyState(VK_MENU) and $80 <> 0 then запоминаем модификатор VK_MENU или его код в переменную;
{ сообщаем о том, что сообщение обработано } Handled := True;
по коду клавиши и модификатора определяем действие из ListView;
case действие of
действие1:
действие2:
действие3: ------------ end;
Я думаю как то так, возможно и не прав.)))
Цитата Меня на другом форуме уже научили, что при нажатии/отпусканию модификатора можно ставить/снимать флаг (boolean). Если не сложно выложите ссылку на форум.
Цитата Если хотите - выложу код. Неплохо было бы посмотреть, а то так сложно о чем то говорить.
Цитата Что значит and $80 = 0? Что за проверка? Скорее не так, а вот так GetKeyState(VK_CONTROL) and $80, а затем это сравнивается с 0. Из справки: Функция GetKeyState
Описание: function GetKeyState(VirtKey: Integer): Integer; Определяет, каково состояние виртуальной клавиши: поднята, нажата или переключается.
Параметры: VirtKey: Виртуальная клавиша.
Возвращаемое значение: Клавиша нажата, если старший бит равен 1, и клавиша переключается, если младший бит равен 1.
$80 - в двоичной системе 10000000 (если я не ошибаюсь), т.е. происходит проверка установлен ли старший бит. Можно проверять и так: if HiWord(GetKeyState(VK_CONTROL)) <> 0 then или if GetKeyState(VK_CONTROL) < 0 then (1 в старшем разряде это признак отрицательного числа (снова если я не ошибаюсь)).
|
|
| |
BLACK_CRAFTER666 | Дата: Понедельник, 22.07.2013, 16:46 | Сообщение # 6 |
Сержант
Группа: Пользователи
Сообщений: 31
Статус: Offline
| Цитата (xaramamburu) И охота вам так издеваться. Мне многие так говорили. Но я люблю изобретать велосипед Цитата (xaramamburu) Вы хотите, чтоб пользователь мог сам назначать комбинацию клавиш так? И вы хотите определить какую комбинацию он нажал, запомнить ее и в дальнейшем сохранить в INI файле или где то еще так? Именно так. Я, кстати, извиняюсь. Я выложил скриншот своего окна, а говорю про него, как про Light Alloy Перепутал Скриншот Light Alloy вот: http://i46.fastpic.ru/big/2013/0722/7f/bea804c21437bd75f68b705adf071b7f.jpg Цитата (xaramamburu) Как я понял саму клавишу вы определять научились Саму клавишу я умею определять уже давно. Ее виртуальный код приходит в wparam, а скан-код - в lparam. Если VCL, то Msg.wparam и Msg.LParam. Цитата (xaramamburu) Если не сложно выложите ссылку на форум. http://www.programmersforum.ru/showthread.php?s=8260c286e9ed1945e7da6f92754f7fe4&p=1255294 Но там ничего толком не решилось. Мне посоветовали способ с использованием функций CreateAcceleratorTable, DestroyAcceleratorTable, TranslateAccelerator, но позже выяснилось, что при использовании акселераторов в одном окне, вешаются остальные окна, если окон у программы несколько. Видно, зря я им не сказал, что у меня в проге несколько окон. Хотя модификаторы можно определять в сообщении WM_KEYDOWN с помощью функции GetKeyState, примерно так, как вы предложили (только, я всё-равно не понял, как это мне поможет). А основную проблему с ListView так и не решили. Только протроллили Так что, продолжать туда отписываться не вижу смысла.
Цитата (xaramamburu) В место переменной наверное можно выгрузить в ListView.
Процедура проверки абсолютна аналогична: Выгрузить-то элементарно. А как связать комбинацию с действием? Неужели только так: case <listview id> of Действие1..9?
Цитата (xaramamburu) Неплохо было бы посмотреть, а то так сложно о чем то говорить. Вот код. Позволяет переназначать/сохранять/загружать клавиши для управления окном. Без модификаторов. Написан на WinAPI.
Код var old_lv_kbd_proc : LongInt = 0; // старая процедура
// структура, хранящая коды кнопок type KeyboardConfiguration = record SeekLeft : Integer; SeekRight : Integer; PlayPause : Integer; Fullscreen : Integer; ControlsPanelVisibility : Integer; MakeScreenshot : Integer; ConfigFile : string; end;
// оконная процедура ListView function lvkbdProc(wnd:HWND; Msg : uint; Wpar:Wparam; Lpar:Lparam):Lresult; stdcall; var n,key : Integer; t : string; Begin Result := 0; case msg of
WM_KEYDOWN: begin n := lv_GetIndex(wnd); // определяем индекс выделенной строки { key := (Lpar shr 24); settext(form4,IntToStr(key));} lv_setItemText(wnd,n,2,IntToStr(Wpar)); lv_setItemText(wnd,n,1,GetKN(lpar)); lv_getitemtext(wnd,N,0,t); // достаём текст из первой колонки ListView. N - индекс выделенной строки // t := LowerCase(t); // почему-то не работает. if t='Плэй / пауза' then cfg.KeysConfig.PlayPause := Wpar else if t='Перемотка назад' then cfg.KeysConfig.SeekLeft := Wpar else if t='Перемотка вперед' then cfg.KeysConfig.SeekRight := Wpar else if t='Полный экран' then cfg.KeysConfig.Fullscreen := Wpar else if t='Скриншот' then cfg.KeysConfig.MakeScreenshot := Wpar else if t='Панель управления' then cfg.KeysConfig.ControlsPanelVisibility := Wpar; end;
else Result:= callWindowProc(Pointer(old_lv_kbd_proc),wnd,msg,wpar,lpar); end; End;
// сохранение настроенных кнопок в любой текстовый файл procedure saveKeys; var t : string; f : TextFile; i,n : Integer; begin n := lv_getcount(LV_KeyboardConfigurator); if n>0 then begin AssignFile(f,cfg.KeysConfig.ConfigFile); Rewrite(f); for i:=0 to n-1 do begin lv_getitemtext(LV_KeyboardConfigurator,i,2,t); Writeln(f,t); end; CloseFile(f); end; end;
// загрузка кнопок из файла procedure LoadKeys; var t: string; f : TextFile; key,i : Integer; begin if not FileExists(cfg.KeysConfig.ConfigFile) then Exit; AssignFile(f,cfg.KeysConfig.ConfigFile); Reset(f); i := 0; while not Eof(f) do begin Readln(f,t); if t<>'' then lv_setItemText(LV_KeyboardConfigurator,i,2,t); key := StrToInt(t); lv_getitemtext(LV_KeyboardConfigurator,i,0,t); if t='Плэй / пауза' then cfg.KeysConfig.PlayPause := key else if t='Перемотка назад' then cfg.KeysConfig.SeekLeft := key else if t='Перемотка вперед' then cfg.KeysConfig.SeekRight := key else if t='Полный экран' then cfg.KeysConfig.Fullscreen := key else if t='Скриншот' then cfg.KeysConfig.MakeScreenshot := key else if t='Панель управления' then cfg.KeysConfig.ControlsPanelVisibility := key; inc(i); end; CloseFile(f); end;
// переназначение оконной процедуры ListView old_lv_kbd_proc := SetWindowLong(LV_KeyboardConfigurator,GWL_WNDPROC, LongInt(@lvkbdProc));
Код нубский, но работает Только, нельзя изменять модификаторы. Но если в коде программы прописать проверку на заранее придуманный модификатор, то действие сработает только при нажатом модификаторе. А как сделать этот модификатор изменяемым, у меня знаний не хватает. А джедаи колоться не хотят
Сообщение отредактировал BLACK_CRAFTER666 - Понедельник, 22.07.2013, 16:46 |
|
| |
xaramamburu | Дата: Вторник, 23.07.2013, 13:51 | Сообщение # 7 |
Полковник
Группа: Администраторы
Сообщений: 240
Статус: Offline
| Сразу скажу, что в вашем коде я ни чего не понял, т.к. с winapi, не особо дружу, да и здесь только часть кода, а хотелось бы запустить и посмотреть как это все работает. Кроме этого из этого кода не понятно как пользователь будет изменять настройки клавиш в ListView, здесь как я понял только считывание из него в структуру, причем структура не предусматривает наличие у кнопки модификатора. Если б я это делал на VCL то наверное поступил бы так: При двойном клике на ListView открывал бы новое окно в котором пользователя просил выбрать комбинацию клавиш для данного действия. Далее отлавливал бы эту комбинацию и сохранял в ListView в одну колонку клавишу, а в другую модификатор. После того как все настройки клавиш закончены, по кнопке сохранить выгружал бы все это в структуру или в соответствующие переменные (да если модификатора у клавиши нет то в переменную записывал допустим 1). Ну а далее при работе просто получаете код клавиши и модификатор (модификатора нет то 1) и сравниваете это с вашей структурой (if структура.клавиша = код клавиши и структура.модификатор = модификатор then действие ). И так по всем комбинациям. ))))
|
|
| |
BLACK_CRAFTER666 | Дата: Вторник, 23.07.2013, 14:44 | Сообщение # 8 |
Сержант
Группа: Пользователи
Сообщений: 31
Статус: Offline
| Цитата (xaramamburu) Сразу скажу, что в вашем коде я ни чего не понял, т.к. с winapi, не особо дружу, А зря) У WinAPI есть некоторые преимущества перед VCL. Я так сразу их все не вспомню, но как пример: winapi не выдаёт экскепшены на ошибки в таком количестве, как VCL. Т.е, вместо того, чтобы просто по-тихому вернуть код ошибки, довольно часто генерируется экскепшен. Тут можно долго спорить, но winapi рулит) Цитата (xaramamburu) да и здесь только часть кода, а хотелось бы запустить и посмотреть как это все работает. Это не вопрос. Могу выложить. Только куда? Google-drive сойдет? Нужны исходники или только exe? Цитата (xaramamburu) по кнопке сохранить выгружал бы все это в структуру или в соответствующие переменные (да если модификатора у клавиши нет то в переменную записывал допустим 1). Ну а далее при работе просто получаете код клавиши и модификатор (модификатора нет то 1) и сравниваете это с вашей структурой (if структура.клавиша = код клавиши и структура.модификатор = модификатор then действие ). И так по всем комбинациям. )))) Т.е, для каждого действия использовать пару переменных - код клавиши и код модификатора? ok. Попробую накатать
Сообщение отредактировал BLACK_CRAFTER666 - Вторник, 23.07.2013, 14:46 |
|
| |
xaramamburu | Дата: Вторник, 23.07.2013, 15:52 | Сообщение # 9 |
Полковник
Группа: Администраторы
Сообщений: 240
Статус: Offline
| Цитата Тут можно долго спорить, но winapi рулит Я и не спорю. Кому как нравится.
Цитата Т.е, для каждого действия использовать пару переменных - код клавиши и код модификатора? Да. И можно расширить вашу структуру. Например: SeekLeft : Integer; ModifSeekLeft : Integer; и т.д. В любом случае нужна пара т.к. модификатор это тоже клавиша и она имеет свой код. И его нужно будет проверять совместно с кодом нажатой клавиши.
Цитата Это не вопрос. Могу выложить. Только куда? Google-drive сойдет? Нужны исходники или только exe? Можете скинуть мне на почту xaramamburu@list.ru , желательно с исходниками и exe. ))))
|
|
| |
BLACK_CRAFTER666 | Дата: Вторник, 23.07.2013, 16:32 | Сообщение # 10 |
Сержант
Группа: Пользователи
Сообщений: 31
Статус: Offline
| Цитата (xaramamburu) Можете скинуть мне на почту Скинул) Я кстати, мог бы написать для вашего сайта пару статей по WinAPI. Чтобы, так сказать, расширить содержимое)
|
|
| |
xaramamburu | Дата: Вторник, 23.07.2013, 16:57 | Сообщение # 11 |
Полковник
Группа: Администраторы
Сообщений: 240
Статус: Offline
| Ок. Только чтоб это было ваше, а не где нибудь содранное с просторов интернета. В крайнем случае чтоб были ссылки на источник, а то потом на форумах народ не доволен, типа воруют инфу а ссылок не делают. Если надо я могу создать категорию или присылайте на почту выложу с указанием авторства.))))
|
|
| |
BLACK_CRAFTER666 | Дата: Вторник, 23.07.2013, 18:29 | Сообщение # 12 |
Сержант
Группа: Пользователи
Сообщений: 31
Статус: Offline
| Цитата (xaramamburu) Только чтоб это было ваше, а не где нибудь содранное с просторов интернета. копировать тексты с других сайтов я не собираюсь. Это будут туториалы на темы типа "как создать окно", "как создать Label", "как создать edit/listBox/ListView" и т.д. И, естественно, я приведу примеры, как работать с каждым из этих контролов и некоторые "фишки" работы с окнами (если это можно так назвать). Многое из этого вы могли видеть в исходниках плеера)) Весь интерфейс и api_*.pas-файлы с макросами я писал сам. Комментарии и весь текст будут полностью мои. Если хотите обсудить, можно продолжить в личке. Речь не идет об оплате моих статей. Я просто хочу рассказать о WinAPI в доступной форме всё, что я знаю, для тех, кому это может быть интересно. Так как, в интернете о WinAPI написано не особо доходчиво и я сам долгое время не мог допереть до очень простых вещей, таких как перекраска окна.
|
|
| |
Lovizaim | Дата: Суббота, 26.11.2016, 16:25 | Сообщение # 13 |
Рядовой
Группа: Пользователи
Сообщений: 1
Статус: Offline
| Как часто вы сталкиваетесь с проблемой того, что нужно срочно взять у кого-то денег, но в нынешние времена эта задача порой становится невыполнимой. Мы рады сообщить вам, что теперь все ваши проблемы разрешаются довольно легко благодаря “Ловизайм”. https://lovizaim.ru
Преимущества микрокредита “Ловизайм”. Самое главное преимущество - скорость. Заявка на микрокредит рассматривается буквально за несколько минут, тогда как в банках на это уходит до нескольких дней. Ну и к тому же вы не связываете себя обязательствами на долгое время.
Способы получения денег по успешным заявкам.
Получить наличные можно в любом финансовом офисе денежной системы “Контакт”. С помощью “Яндекс деньги”. Через любую удобную вам платежную карту. Используя безналичный перевод на банковский счет. Отельное удобство - получить деньги сразу на ваш электронный кошелек “QIWI” или “Webmoney”. С помощью денежных переводов “Золотая корона”.
Какой бы способ из перечисленных вы не выбрали - деньги вы получите максимально быстро.
“Ловизайм” всегда переживает и заботится о своих клиентах, а потому, если у вас возникли трудности с выплатой вашего займа вовремя, не стоит беспокоиться, просто обратитесь в службу поддержки нашей компании на сайте, и наши сотрудники помогут вам разобраться в трудностях и подскажут условия для продления времени погашения микрокредита.
Оформите заявку на получение займа прямо сейчас! https://lovizaim.ru/anketa.shtml
|
|
| |
|