Sign in to follow this  
Followers 0
LAttilaD

Please help me to translate

15 posts in this topic

Please help me to translate a function from Autohotkey to Autoit 3. I found the original function in an Autohotkey forum and used it for a long time for my keyboard remapper. It is called as uni(code), where code is one or more Unicode character code(s) in hex, for example, uni("0171"). The purpose is to send the text to the keyboard (in the example, a Hungarian accented letter).

I would like to use this code in Autoit, but my knowledge isn't enough. Would somebody be so kind to help me to translate it?

Thank you in advance!

uni( p_text ); 4 DllCalls/char + 1, reduced from 20/char + 1
{
   event_count := ( StrLen(p_text)//4 )*2
   VarSetCapacity( events, 28*event_count, 0 )
   base = 0
   Loop % event_count//2
   {
      StringMid code, p_text, 4*A_Index-3, 4
      code = 0x4%code%

      DllCall("RtlFillMemory", "uint", &events + base, "uint",1, "uint", 1)
      DllCall("ntoskrnl.exe\RtlFillMemoryUlong", "uint",&events+base+6, "uint",4, "uint",code)
      base += 28

      DllCall("RtlFillMemory", "uint", &events + base, "uint",1, "uint", 1)
      DllCall("ntoskrnl.exe\RtlFillMemoryUlong", "uint",&events+base+6, "uint",4, "uint",code|(2<<16))
      base += 28
   }
   result := DllCall( "SendInput", "uint", event_count, "uint", &events, "int", 28 )
   if ( ErrorLevel or result < event_count )
      MsgBox SendInput failed`nErrorLevel = %ErrorLevel%`n%result% events of %event_count%
}

Láng Attila D., LAttilaD.org

Share this post


Link to post
Share on other sites



Meanwhile, I've created a translation. I did my best, but it won't work, it always returns with @error = 2. Can anybody help me what's wrong?

func uni($code)
    $eventcount=2
    $events=$empty
    $base=0
    $code=dec($code)
    DllCall("", "", "RtlFillMemory", "uint", ptr($events+$base), "uint", 1, "uint", 1)
    DllCall("ntoskrnl.exe", "", "RtlFillMemoryUlong", "uint", ptr($events+$base+6), "uint", 4, "uint", $code)
    $base+=28
    DllCall("", "", "RtlFillMemory", "uint", ptr($events+$base), "uint", 1, "uint", 1)
    DllCall("ntoskrnl.exe", "", "RtlFillMemoryUlong", "uint", ptr($events+$base+6), "uint", 4, "uint", bitor($code, bitshift(2, -4)))
    $base+=28
    $result=DllCall("", "", "SendInput", "uint", $eventcount, "uint", ptr($events), "int", 28)
    if @Error or $result < $eventcount then
        MsgBox("", "", @error&@crlf&$result)
        endif
endfunc

Note that $empty is a global containing

for $a=1 to 2*28
$empty&=chr(0)
next

Many thanks for any help!


Láng Attila D., LAttilaD.org

Share this post


Link to post
Share on other sites

Thanks for the help, Zedna. I've added the modification. However, the function still returns with an error.


Láng Attila D., LAttilaD.org

Share this post


Link to post
Share on other sites

Thanks for the help, Zedna. I've added the modification. However, the function still returns with an error.

Your translation is still wrong.

- DllCall("", "", "RtlFillMemory", "uint", ptr($events+$base), "uint", 1, "uint", 1) --> first parameter is mandatory as far as I know

- SendInput --> replace it by Send()

Share this post


Link to post
Share on other sites

Your translation is still wrong.

Just an attempt. I'm a total newbie in dll calling.

- DllCall("", "", "RtlFillMemory", "uint", ptr($events+$base), "uint", 1, "uint", 1) --> first parameter is mandatory as far as I know

Okay, it may be, but what should it be?

- SendInput --> replace it by Send()

If I send the keys with Send, what does the rest of the function do? >_< :)


Láng Attila D., LAttilaD.org

Share this post


Link to post
Share on other sites

#7 ·  Posted (edited)

Okay, it may be, but what should it be?

Maybe "Kernel32.dll"

If I send the keys with Send, what does the rest of the function do? >_< :)

Translation before Send()

SendInput doesn't exists in neither in AutoIt nor in Windows system DLLs as far as I know.

Edited by Zedna

Share this post


Link to post
Share on other sites

Update:

After some googling, I've entered the missing dll names and specified a return type for the last dll call. Now the code looks like below. It doesn't report any error but it doesn't send any key! Heeeelp... :)

#Include <Memory.au3>
hotkeyset("{f1}", "uu")

while 1
sleep(1000)
wend

func uu()
uni("0126")
exit
endfunc

while 1
sleep(1000)
wend

func uni($code)
    $eventcount=2
    $events = _MemGlobalAlloc(28*$eventcount, 2 )
    $base=0
    $code=dec($code)
    DllCall("kernel32.dll", "", "RtlFillMemory", "uint", ptr($events+$base), "uint", 1, "uint", 1)
    DllCall("ntoskrnl.exe", "", "RtlFillMemoryUlong", "uint", ptr($events+$base+6), "uint", 4, "uint", $code)
    $base+=28
    DllCall("kernel32.dll", "", "RtlFillMemory", "uint", ptr($events+$base), "uint", 1, "uint", 1)
    DllCall("ntoskrnl.exe", "", "RtlFillMemoryUlong", "uint", ptr($events+$base+6), "uint", 4, "uint", bitor($code, bitshift(2, -4)))
    $base+=28
    $result=DllCall("user32.dll", "uint", "SendInput", "uint", $eventcount, "uint", ptr($events), "int", 28)
    if @Error or $result < $eventcount then
        MsgBox("", "", @error&@crlf&$result)
        endif
endfunc

Láng Attila D., LAttilaD.org

Share this post


Link to post
Share on other sites

Maybe "Kernel32.dll"

Yes, it is; both of us were posting at the same time.

Translation before Send()

SendInput doesn't exists in neither in AutoIt nor in Windows system DLLs as far as I know.

OK, I've remarked the call for SendInput and added a send(chrw($code)). Now I get response: a letter H appears in MS Word. Unfortunately, U+0126 is a H with a stroke, so the diacritic has been removed.


Láng Attila D., LAttilaD.org

Share this post


Link to post
Share on other sites

#10 ·  Posted (edited)

Update:

After some googling, I've entered the missing dll names and specified a return type for the last dll call. Now the code looks like below. It doesn't report any error – but it doesn't send any key! Heeeelp... :)

1) Function ptr() doesn't exists

2) try to call _GetLastErrorMessage() after each DllCall() to see "silent errors"

example:

DllCall("kernel32.dll", "", "RtlFillMemory", "uint", ptr($events+$base), "uint", 1, "uint", 1)

If @error Then _GetLastErrorMessage ("RtlFillMemory - error after DllCall 1")

Func _GetLastErrorMessage ($DisplayMsgBox = "")
    Local $ret, $s
    Local $p = DllStructCreate("char[4096]")
    Local Const $FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000

    If @error Then Return ""

    $ret = DllCall("Kernel32.dll", "int", "GetLastError")

    $ret = DllCall("kernel32.dll", "int", "FormatMessage", _
           "int", $FORMAT_MESSAGE_FROM_SYSTEM, _
           "ptr", 0, _
           "int", $ret[0], _
           "int", 0, _
           "ptr", DllStructGetPtr($p), _
           "int", 4096, _
           "ptr", 0)
    $s = DllStructGetData($p, 1)
    $p = 0
    If $DisplayMsgBox <> "" Then MsgBox(0, "_GetLastErrorMessage", $DisplayMsgBox & @CRLF & $s)
    Return $s
EndFunc ;==>_GetLastErrorMessage
Edited by Zedna

Share this post


Link to post
Share on other sites

1) Function ptr() doesn't exists

Ouch. Doesn't it? I found it in the Autoit documentation, and Autoit never said I'm calling an undefined function. :)

2) try to call _GetLastErrorMessage() after each DllCall() to see "silent errors"

Here you are: I've getting errors after all dll calls. (Not including SendInput, which is in a remark now.) Is @error reset to zero between each call? Or am I calling the functions as wrongly as it seems? I reckon I am.


Láng Attila D., LAttilaD.org

Share this post


Link to post
Share on other sites

#12 ·  Posted (edited)

Ouch. Doesn't it? I found it in the Autoit documentation, and Autoit never said I'm calling an undefined function. :)

Sorry my mistake, Ptr() exists but I think you can't use it this way - but I'm not sure about it.

Edited by Zedna

Share this post


Link to post
Share on other sites

Sorry my mistake, Ptr() exists but I think you can't use it this way - but I'm not sure about it.

Meanwhile, I've removed ptr calls and added *'s after the preceding type declarators, as the documentation suggests it. Unfortunately, nothing changes. There are four error reports, and a diacriticless letter H appears.


Láng Attila D., LAttilaD.org

Share this post


Link to post
Share on other sites

Some Time Ago, i posted a SendInput for Unicode on Autoit.de :) Here it is:

#include <WinAPI.au3>
$process = Run("notepad.exe")

;~ $NotepadHWND = "Untitled - " ; EN
$NotepadHWND = "Unbenannt - " ; DE

WinActivate($NotepadHWND)
WinWaitActive($NotepadHWND)
_SendUnicode(ChrW(0x398) & ChrW(0x3B8))

;~ InputBox("It should be:","It should be this char: Copy it to Notpad and see, that it is accepted",$text)

; Prog@ndy :)
Func _SendUnicode($text)
    Local Const $tagINPUT_Keyboard = "DWORD type; ushort wVk; ushort wScan; DWORD dwFlags; DWORD time; ULONG_PTR dwExtraInfo;dword;ULONG_PTR;"
    Local Const $INPUT_KEYBOARD = 1
    Local Const $KEYEVENTF_UNICODE = 0x4
    Local Const $KEYEVENTF_KEYUP = 0x2
    Local $tinp = DllStructCreate($tagINPUT_Keyboard & $tagINPUT_Keyboard)
    Local $sendDLL = DllOpen("user32.dll")
    $text = StringSplit($text, "")
    Local $ret
    For $i = 1 To $text[0]
        DllStructSetData($tinp, 1, $INPUT_KEYBOARD)
        DllStructSetData($tinp, 7, $INPUT_KEYBOARD)
        DllStructSetData($tinp, 2, 0)
        DllStructSetData($tinp, 8, 0)
        DllStructSetData($tinp, 3, AscW($text[$i]))
        DllStructSetData($tinp, 9, AscW($text[$i]))
        DllStructSetData($tinp, 4, $KEYEVENTF_UNICODE)
        DllStructSetData($tinp, 10, BitOR($KEYEVENTF_KEYUP, $KEYEVENTF_UNICODE))
        DllStructSetData($tinp, 5, 0)
        DllStructSetData($tinp, 11, 0)
        DllStructSetData($tinp, 6, 0)
        DllStructSetData($tinp, 12, 0)
        $ret = DllCall($sendDLL, "uint", "SendInput", "uint", 2, "ptr", DllStructGetPtr($tinp), "int", DllStructGetSize($tinp)/2)
    Next
    DllClose($sendDLL)
EndFunc   ;==>_SendUnicode

*GERMAN* [note: you are not allowed to remove author / modified info from my UDFs]My UDFs:[_SetImageBinaryToCtrl] [_TaskDialog] [AutoItObject] [Animated GIF (GDI+)] [ClipPut for Image] [FreeImage] [GDI32 UDFs] [GDIPlus Progressbar] [Hotkey-Selector] [Multiline Inputbox] [MySQL without ODBC] [RichEdit UDFs] [SpeechAPI Example] [WinHTTP]UDFs included in AutoIt: FTP_Ex (as FTPEx), _WinAPI_SetLayeredWindowAttributes

Share this post


Link to post
Share on other sites

#15 ·  Posted (edited)

Oh… ProgAndy, it looks like you solved my problem.

The real problem was that I wanted to remap keys with something like

hotkeyset("g", "proc")

func proc()
uni("0430")
endfunc

where uni is a function to send a unicode character. I tried two ways. Send("{asc …}") is incompatible with my numpad mouse script and, additionally, doesn't work in certain editors. Clipput() and send("^v") works properly, but if I keep the key pressed, it sometimes produces unwanted results (random keystrokes appear, dialog boxes open and so on). Then, I tried to deactivate the hotkey before processing the send and activate it again after. This is good, but results in things like aaaaaaaaaaagaaaaaaaaaagaaaaaaaaaaaag… where a is the character wanted and g is the one originally given by the hotkey. The best result I could get was to assign the hotkey to a dead function (func dead() endfunc) before sending the key and reassign after. But the keys are obviously slower than undefined ones.

I tested your function for several keys in a short time, and I didn't see any problem. I wonder how could I miss this function in the forum – I was searching for ages before asking for help.

Now, I believe I can write my key mapper. May I give you a credit?

Edited by LAttilaD

Láng Attila D., LAttilaD.org

Share this post


Link to post
Share on other sites

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
Sign in to follow this  
Followers 0