Хотелось бы отдать "Ctrl" + "Scroll Lock" (к примеру) под запуск одного EXE-файла. Если на рабочем столе есть иконка к этой проге, то никаких проблем (параметр свойств иконки "Быстрый вызов"). А если на столе нет иконки?!
Вроде где-то было на эту тему, но не помню где ...
Заранее всем спасибо.
PS: Проге нельзя делать иконку на десктопе даже за пределами экранной области!
Как сидеть "резидентно" в памяти - ещё могу представить; тупой вариант - форма, которую Load, но никак не Show, а в ней - While..Wend с кучей DoEvents внутри него. Хотя наверняка это можно (и нужно) сделать как-то корректнее (если знаешь как - подскажи, плз).
А вот как "отлавливать клаву" - ваще не знаю: вертится в башке кусок из какого-то форумного топика, типа "вешай хук" и т.д., но точно не помню. Наверняка через API...
Ок. Тяни отсюда архив форума (он по-моему есть в полезных программах), там ищи тему "Кому нужен клаиватурный шпион" автора User Unknown. Это тот самый API и есть. Без всяких Whilе'ов и прочих напряжных для системы вещей.....
Архив стянул. Причём - "полный" вариант. Дал в нём поиск по самым разным ключам - User Unknown, клавиатур*, шпион*, хук, hook и т.д. и т.п. - ничего не нашёл. М.б., проблема в том, что даже "полный" архив начинается только с января 2002 г.?! Ты не помнишь, примерно когда был этот топик?
Расширенный поиск Яндексом, с фокусировкой по VB-шным сайтам Рунета, тоже ничего не дал. Разве что опять: "пиши DLL и вешай хук WH_KEYBOARD" или что-то типа этого...
Declare Function RegisterHotKey Lib "user32" Alias "RegisterHotKey" (ByVal hwnd As Long, ByVal id As Long, ByVal fsModifiers As Long, ByVal vk As Long) As Long
· hWnd Identifies the window that will receive WM_HOTKEY messages generated by the hot key. If this parameter is NULL, WM_HOTKEY messages are posted to the message queue of the calling thread and must be processed in the message loop.
· id Specifies the identifier of the hot key. No other hot key in the calling thread should have the same identifier. An application must specify a value in the range 0x0000 through 0xBFFF. A shared dynamic-link library (DLL) must specify a value in the range 0xC000 through 0xFFFF (the range returned by the GlobalAddAtom function). To avoid conflicts with hot-key identifiers defined by other shared DLLs, a DLL should use the GlobalAddAtom function to obtain the hot-key identifier.
· fsModifiers Specifies keys that must be pressed in combination with the key specified by the nVirtKey parameter in order to generate the WM_HOTKEY message. The fsModifiers parameter can be a combination of the following values: MOD_ALT Either ALT key must be held down. MOD_CONTROL Either CTRL key must be held down. MOD_SHIFT Either SHIFT key must be held down.
· vk Specifies the virtual-key code of the hot key.
If the function succeeds, the return value is nonzero.
If the function fails, the return value is zero. To get extended error information, call GetLastError.
Насколько я смог понять, поэкспериментировав немного, функция RegisterHotKey мне не подходит, т.к. она завязана на hWnd конкретного окна, в которое посылаются нажатия "горячих клавиш". Мне же нужно, чтобы вне зависимости от того, какое окно в настоящий момент имеет фокус (и принимает нажатия), происходил бы анализ нажатий.
Я попробовал поиграться с функцией PeekMessage, но у неё та же беда (завязана на конкретное окно). Если при её вызове вместо hWnd поставить NULL (а в MSDN написано, что так можно делать, если хотим анализировать нажатия, адресованные ВСЕМ), то компилятор VB ругается: мол, недопустимое использование пустого указателя! Да даже если этот NULL не ставить, а оставить для простоты (на время отладки) Me.hWnd, то в нижеследующем примере получается забавная штука:
[code]
Private Const WM_KEYUP = &H101
Private Const PM_NOREMOVE = &H0
Private bCancel as Boolean
Private Sub Form_Load()
Dim Message As Msg
Me.Show
bCancel = False
Do While Not (bCancel)
If PeekMessage(Message, Me.hWnd, WM_KEYUP, WM_KEYUP, PM_NOREMOVE) Then
st = st + Chr(Message.wParam)
End If
DoEvents
Loop
End Sub
Private Sub Form_Unload(Cancel As Integer)
bCancel = True
Debug.Print st
End Sub
[/code]
- в переменной st накапливаются НЕ ВСЕ нажимаемые символы (особенно, если нажимать
быстро)!
Я, наверное, чего-то не догоняю принципиально. Хотя вроде смотрел всё в MSDN-е ...
Private Const MOD_ALT = &H1 Private Const MOD_CONTROL = &H2 Private Const MOD_SHIFT = &H4 Private Const PM_REMOVE = &H1 Private Const WM_HOTKEY = &H312 Private Type POINTAPI x As Long y As Long End Type Private Type Msg hWnd As Long Message As Long wParam As Long lParam As Long time As Long pt As POINTAPI End Type Private Declare Function RegisterHotKey Lib "user32" (ByVal hWnd As Long, ByVal id As Long, ByVal fsModifiers As Long, ByVal vk As Long) As Long Private Declare Function UnregisterHotKey Lib "user32" (ByVal hWnd As Long, ByVal id As Long) As Long Private Declare Function PeekMessage Lib "user32" Alias "PeekMessageA" (lpMsg As Msg, ByVal hWnd As Long, ByVal wMsgFilterMin As Long, ByVal wMsgFilterMax As Long, ByVal wRemoveMsg As Long) As Long Private Declare Function WaitMessage Lib "user32" () As Long Private bCancel As Boolean Private Sub ProcessMessages() Dim Message As Msg 'loop until bCancel is set to True Do While Not bCancel 'wait for a message WaitMessage 'check if it's a HOTKEY-message If PeekMessage(Message, Me.hWnd, WM_HOTKEY, WM_HOTKEY, PM_REMOVE) Then 'minimize the form WindowState = vbMinimized End If 'let the operating system process other events DoEvents Loop End Sub Private Sub Form_Load() 'KPD-Team 2000 'URL: http://www.allapi.net/ 'E-Mail: KPDTeam@Allapi.net Dim ret As Long bCancel = False 'register the Ctrl-F hotkey ret = RegisterHotKey(Me.hWnd, &HBFFF&, MOD_CONTROL, vbKeyF) 'show some information Me.AutoRedraw = True Me.Print "Press CTRL-F to minimize this form" 'show the form and Show 'process the Hotkey messages ProcessMessages End Sub Private Sub Form_Unload(Cancel As Integer) bCancel = True 'unregister hotkey Call
Между прочим, энтот пример я и использовал при своих экспериментах. И именно на нём я и наступил на грабли, что у RegisterHotKey() обязательно должен быть какой-нить hWnd, а NULL (обещанный MSDN-ом) - не срабатывает ... Так что этот пример - не в тему, уж не обессудь.
Постой - постой ... минуточку ... А что если я внутри цикла (или по таймеру) буду через АПИ опрашивать, какое окно сейчас активно, и именно егойный hWnd скармливать RegisterHotKey ?!
Что скажете?! Правда, я не знаю, как это сделать, но если уж в VB есть AppActivate, то и АПИ должна быть похожая.
Вообще говоря, мой вопрос сможет решить, наверное, только человек, съевший собаку на PeekMessage() - нутром чую, что через неё должно решаться!
PS: А как это у вас так ловко получается вставить в топик VB-код с сохранением всего форматирования из VB IDE? Поделитесь, плиз!
Странно... Я думал что ты именно активные окна и скармливал, а оно все равно не получалось Конечно активное!
Public Declare Function GetActiveWindow Lib "user32" Alias "GetActiveWindow" () As Long Ета фукция получает хендл активного окно которое имеет фокус ввода, ИМХО именно ето тебе и нужно .
И параметров никаких не надо, просто возвращает хендл.
Только вот в етом случае будет у тебя проблема если откритич окон нет, тогда есть идея использовать хендл рабочего стола как окна верхнего уровня, не зная сработает ли , но попробовать можно.
Public Declare Function GetDesktopWindow Lib "user32" () As Long
Comanche : > Между прочим, энтот пример я и использовал при своих экспериментах. И именно на нём я и наступил на грабли, что у RegisterHotKey() обязательно должен быть какой-нить hWnd.
Hwnd нужен того окна, которому надо сообщить о нажатии на комбинацию кнопок. А как ты собрался получить событие, если передаешь NULL? Твоему окну придет сообщение WM_HOTKEY - т.е. делай подкласс и отлавливай мессаги СВОЕГО окна, а не лезь к чужим.
ларчик открывался гораздо проще, чем я думал - в другом форуме посоветовали использовать ... как вы думаете, что? - GetAsyncKeyState() !!! вот уж действительно - "незаслуженно забытую". Она не ловит сложных комбинаций, как я мог заметить (где более одной клавиши-modifier), но для моей задачи вполне сойдёт. Воткнул её в событие Timer таймера и теперь наслаждаюсь.
Но вопрос про то, как КОРРЕКТНО сделать резидентную программу, - оставляю открытым. Или, может, его лучше выделить в отдельный топик, как думаете?