Jump to content

Recommended Posts

  • 1 year later...
Posted (edited)

Hi!

Thank you for this UDF, I love It!

It seems you can not setup the same key on both keyboards at the same time, Is it intended?
If so, don't read anymore, thanks anyway.

EDIT:  I realized that it internally uses HotkeySet, so the same hotkey couldn't been registered two timese for different keyboards. I'm sorry.

 

If I setup {f1} hotkey for keyboard 1  and {f2} for keyboard 2, everything works perfectly, so:
- both keyboards works and they are detected
- There are no error registerings hotkeys.
- I get Console Messages for both hotkeys press


If I setup {f1} for both keyboards:
- It works for keyboard 1, I get Console Messages whenever I press {f1} on keyboard 1
- It doesn't work for keyboard 2, I don't get Console Message on this hotkey and keyboard 2

This code reproduce the problem:

#include <MKHKS-UDF.au3>
#include <Misc.au3>

_MKHKS_Initialize()

_MKHKS_Register_HotKey("{f1}", _keyb1, 1 )  
If @error Then ConsoleWrite("error " &  @error &  @CRLF)
_MKHKS_Register_HotKey("{f1}", _keyb2, 2 )  
If @error Then ConsoleWrite("error " &  @error &  @CRLF)

While 1
    sleep(50)
    _MKHKS_WaitForEvent()
    If _IsPressed("1B") Then  ; Esc
        Exit
    EndIf
Wend


Func _keyb1()
  ConsoleWrite("pressed F1 on keyb index 1"&  @CRLF)
EndFunc

Func _keyb2()
  ConsoleWrite("pressed F1 on keyb index 2 Dactyl manuform"&  @CRLF)
EndFunc


 

It seems  __MKHKS_FindKey function doesn't take in mind at what keyboard is registered that searched hotkey,
 so it finds the first one that was for Keyboard 1, and then, since The hDevice is not the same, it uses ControlSend.

 Func __MKHKS_WM_INPUT:

Local $iHotKey = __MKHKS_FindKey($sMKHKS_HotKey)
  If ___MKHKS_FindKeyBoard($tRIH.hDevice) = $aMKHKS_HotKeySet[$iHotKey][2] Then
    If $aMKHKS_HotKeySet[$iHotKey][3] Then
      $iMKHKS_HotKeyPressed = $iHotKey + 1
    Else
      $aMKHKS_HotKeySet[$iHotKey][1]()
    EndIf
  Else
    ControlSend("", "", "", $sMKHKS_HotKey)
  EndIf

I Think __MKHKS_FindKey needs a second parameter (keyboard hDevice) so it only search the hotkey on the desired Keyboard hDevice. Am I right?

 

Edited by Lepes
Posted

@Lepes Glad you like my UDF.

As of today I would consider it a bug, since it registers both keyboards for the same key (F1 in your example).  Now I believe it would be quite easy to implement your suggestion.  Only drawback is that you would need to specify a keyboard in _MKHKS_UnRegister_HotKey (I could allow no specification and all keyboards would be unregistered).

Just curious what the others think about your idea.

Meanwhile, I'll think of the best solution (either a bug or an enhancement).

Thanks anyway for the report. 

Posted

Thank you very much!! I really appreciate your time and effort.

"Everyone said" that this was imposible, because Windows USB keyboard Management is transparent and you can not identify what keypress belong to a specific hardware.

I have been trying to achieve this for almost a year now, since I 3DPrinted and built a handwired Dactyl manuform 4x6. I am not sure if you realize what you have done here: To achieve this I need to craft a new keyboard (buy switches, keycaps, diodes, weld everything) configure QMK firmware to assign differents functions to each keys and use a dedicated Arduino Pro-Micro for this secondary macro keyboard.

Once I did everything, I got two problems:
- You can not create new virtual key codes. You are sticked to remap existings ones, the only availables are from F13 to F24
- Since the firmware is inside your macro keyboard, it knows nothing about Windows OS. I don't want to change keyboard/mouse layers manually everytime I change from Mozilla Firefox to Blender, to FreeCommander and so on. I want AutoIt detects the active window and remaps everything on the fly.

This UDF allows to connect any cheap keyboard and use it as a control panel, it is not just a keyboard anymore (although you can), It is a custom macro keyboard, you can program any key to do whatever you want.

The best part is that your main keyboard is not affected. I mean, if you map F5 for an Autoit function, you can not press F5 anymore to update mozilla webpage. You need to pause your AutoIt script to use F5 native function. Now you have two different F5 keys, Problem solved!!

It is exactly the same if you have a programmable mouse buttons and the mouse software doesn't fit your needs. I map Mouse Buttons to fixed functions keys (F1..F12) and then AutoIt remaps on the fly based on the active window, but it also remap my main keyboard, something I didn't like.

;File Generated with OdsToArray.au3 from 'Mapeado.ods' file
#Region ; $aTable
Global Const $WIN =  0 , $HOT =  1 , $SEN = 2 ,  $FUN =  3 ,  $HEL =  4  ; COLS constants
;Wintitle                      , HotKeySet           , ControlSend         , Function            , Help                          

Global $aTable[][] = [ _ 
["Mozilla"                     , "{f1}"              , "^+{TAB}"           , ""                  , "prior tab"                   ], _ 
["Mozilla"                     , "{f2}"              , "^{TAB}"            , ""                  , "next tab"                    ], _ 
["Mozilla"                     , "{f3}"              , "^w"                , ""                  , "close tab"                   ], _ 
["Mozilla"                     , "{f4}"              , "^c"                , ""                  , "copy text"                   ], _ 
["Mozilla"                     , "{f5}"              , "^x"                , ""                  , "cut text"                    ], _ 
["Mozilla"                     , "{f6}"              , "^v"                , ""                  , "paste text"                  ], _ 
["Mozilla"                     , "+{f4}"             , ""                  , "copyWebLink"       , "copy Web link"               ], _ 
["Mozilla"                     , "!{f4}"             , ""                  , "addWebLink"        , "Add new Web link"            ], _ 
["Mozilla"                     , "{f7}"              , ""                  , "TranslateWord"     , "translate from English"      ], _ 
["Mozilla"                     , "{f10}"             , ""                  , "GoogleText"        , ""                            ], _ 
["Blender"                     , "{f1}"              , "+s"                , ""                  , "Cursor a selección"          ], _ 
["Blender"                     , "{f2}"              , "{NUMPADDIV}"       , ""                  , "vista Local/Global"          ], _ 
["Blender"                     , "{f3}"              , "h"                 , ""                  , "Ocultar"                     ], _ 
["Blender"                     , "{f4}"              , "{NUMPAD1}"         , ""                  , "vista frontal"               ], _ 
["Blender"                     , "^{f4}"             , "^{NUMPAD1}"        , ""                  , "vista trasera"               ], _ 
["Blender"                     , "{f5}"              , "{NUMPAD3}"         , ""                  , "vista derecha"               ], _ 
["Blender"                     , "^{f5}"             , "{NUMPAD3}"         , ""                  , "vista izquierda"             ], _ 
["Blender"                     , "{f6}"              , "{NUMPAD7}"         , ""                  , "vista superior"              ], _ 
["Blender"                     , "^{f6}"             , "^{NUMPAD7}"        , ""                  , "vista inferior"              ], _ 
["Blender"                     , "{f10}"             , "{NUMPADDOT}"       , ""                  , "Focalizar selección"         ], _ 
["Blender"                     , "{left}"            , "1"                 , ""                  , "Vertices"                    ], _ 
["Blender"                     , "{Down}"            , "2"                 , ""                  , "Aristas"                     ], _ 
["Blender"                     , "{Right}"           , "3"                 , ""                  , "Caras"                       ], _

This UDF is a really good gift, Thank you and Merry Christmas!!

Posted

I'm having a problem here, while it shows that it catches the arrows, but it doesn't fire the function, unless I press another key

#include "MKHKS-UDF.au3" ;https://www.autoitscript.com/forum/topic/205141-multiple-keyboards-hotkeyset-udf

Example()

;----------------------------------------------------------------------------------------
Func Example()
    _MKHKS_Initialize(False) ;With True Show list of keyboards

    _MKHKS_Register_HotKey("{LEFT}", goLEFT, 0) ;set hotkey to 1st keyboarb
    _MKHKS_Register_HotKey("{RIGHT}", goRIGHT, 0) ;set hotkey to 1st keyboarb

    While True
        _MKHKS_WaitForEvent()
        Sleep(50)
    WEnd

EndFunc   ;==>Example

;----------------------------------------------------------------------------------------
Func goLEFT()
    ConsoleWrite("goLEFT" & @CRLF)
EndFunc
;----------------------------------------------------------------------------------------
Func goRIGHT()
    ConsoleWrite("goRIGHT" & @CRLF)
EndFunc

 

I know that I know nothing

Posted

@ioa747  Thanks for reporting.  I got same problem as you.  As of now, it seems there is a special treatment by Windows for those 2 keys.  I will need to investigate further although I still do not understand why Windows would do such a thing.

  • 10 months later...
Posted

Thank you for this amazing UDF, Nine!

A small bug that caught me today - _MKHKS_UnRegister_HotKey fails if a hotkey was registered with more than one keyboard. This is because your for loop is missing "Step -1" so that the loop is specified to go from 1 to 0, for example, which causes it to never run.

The original line is:

Func _MKHKS_UnRegister_HotKey
.....
For $i = UBound($aIdx) - 1 To 0
    If $iKeyBoard < 0 Or $aMKHKS_HotKeySet[$aIdx[$i]][2] = $iKeyBoard Then

It should read:

 For $i = UBound($aIdx) - 1 To 0 Step -1
    If $iKeyBoard < 0 Or $aMKHKS_HotKeySet[$aIdx[$i]][2] = $iKeyBoard Then

On a related note, it would be nice to have a function to handle a new "keyboard" being attached. The problem is the merely re-assigning $aMKHKS_Keyboard, aside from messing with an "internal variable" is not sufficient, since it then breaks any currently assigned hotkeys. Preserving hotkeys across a change of the keyboard list would be a bit tricky -- you currently don't store enough information in $aMKHKS_HotKeySet to do it. But at the very least, all existing hotkeys should be unregistered.  My proposed function would be something like 

Func RescanKeyboards($exclude)
  Local $aCurrentKbds = __MKHKS_EnumRawKeyboards($exclude)

  If _ArrayToString($aMKHKS_Keyboard) <> _ArrayToString($aCurrentKbds) Then
    
    "ToDo: Unregister all hotkeys"
    
    $aMKHKS_Keyboard = $aCurrentKbds
    Return True  ;kdbs changed, user needs to reinitialize all hotkeys
  Endif

  Return False
EndFunc

My use case:

  I'm handling "keystrokes" from a remote control (Logitech R400 Wireless Presenter Remote Control), but also assigns hotkeys to the local keyboard. The script runs at Windows startup but the usb stick for the remote is not immediately plugged in. So if the code doesn't find the remote (based on its ID), it scans until it is found, then updates the keyboard definitions. Also, to make the program a bit less dependent on exact ID strings, anything that is not the remote controller is treated as the local keyboard -- usually there is more than one of these, just because of how the manufacturers specify their keyboards (keypad vs. main kbd, for example), hence the need to unregister keys from multiple keyboards.

Thanks again for all your hard work on this!

Posted (edited)

@easyL  Thanks for reporting the bug in _MKHKS_UnRegister_HotKey.  I will make a new version soon.

Instead of creating a new function to rescan and unregister all hotkeys, I suggest you use this script that will restart on the addition of a new keyboard :

#include "C:\Apps\AutoIt\Keyboard Mouse\MKHKS-UDF.au3"

HotKeySet("{ESC}", Terminate)
HotKeySet("{HOME}", Restart) ; manual restart

If $CmdLine[0] Then Sleep(500)  ; give time for restart, so all hotkeys from previous start are unset
Local $iNumKB = AssignHotKeys()

While Sleep(100)
  _MKHKS_WaitForEvent()
  If $iNumKB <> UBound(__MKHKS_EnumRawKeyboards("194a8f")) Then Restart() ; automatic restart
WEnd

Func Restart()
  Exit ShellExecute(@ScriptFullPath, "Restart")
EndFunc   ;==>Restart

Func Terminate()
  Exit
EndFunc   ;==>Terminate

Func AssignHotKeys()
  Local $iNum = _MKHKS_Initialize(False, "194a8f")
  Switch $iNum
    Case 2 ; register hotkeys on secondary KB when available
      _MKHKS_Register_HotKey("{F1}", DoF1, 1, False)
      ContinueCase
    Case 1 ; register hotkeys on local KB
      _MKHKS_Register_HotKey("{F2}", DoF2, 0, True)
  EndSwitch
  Return $iNum
EndFunc   ;==>AssignHotKeys

Func DoF1()
  MsgBox($MB_OK, "", "F1")
EndFunc   ;==>DoF1

Func DoF2()
  MsgBox($MB_OK, "", "F2")
EndFunc   ;==>DoF2

Let me know if that should work for you.  I prefer this approach because it will close all current execution of hotkeys and restart a clean instance.

Edited by Nine
suggested solution

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...