Свой список автозамены

Russian main discussion
Post Reply
  • Author
  • Message
Offline
Posts: 17
Joined: Tue Feb 03, 2026 1:20 pm

Свой список автозамены

Post by testuser2 »

Погружаясь в скриптовую автоматизацию AkelPad, я пришел к мысли, что не плохо было бы как-то удобизировать работу с C-структурами, и в итоге написал "фабричную" функцию, создающую обекты-врапперы структур, в которых методы соответствуют полям структур и реализуют запись/чтение этих полей.. Также я написал уже функцию, которая, на основе сишных определений структур в тексте, создает соответствующие "фабрики" объектов - врапперов этих структур. Реализацию и пример использования можно найти [ur=https://github.com/LAcoder2/AkelPadScriptsl]здесь[/url] (файлы MemHelp.js, StructTest,js, RegisterHotkeyExample.js, ExampleEvents.js). Вишенкой на торте хотелось бы дополнить реализацией кастомного списка автозамены, который должен появиться когда вводишь точку в редакторе после имени объекта - враппера структуры.. Обработку событий ввода я уже реализовал в файле ExampleEvents.js. Окно списка автозамены хотелось бы взять стандартное из плагина Coder, которое можно вызвать командой
AkelPad.Call("Coder::AutoComplete::WithList")
Вопрос - реално ли в JS реализовать хук этого окна и заполнение его своими значениями, при этом использя внутренние структуры Сoder-а, чтобы не нарушать его работу? Или лучше делать собственную реализацию этого списка на JScript?

Offline
Posts: 17
Joined: Tue Feb 03, 2026 1:20 pm

Re: Свой список автозамены

Post by testuser2 »

После двух дней мучений с нейросетью получилось выкатить только вот эту "деревяшку". Оно появляется там где нужно, но ни чего не делает.
Изначально я давал нейросетке рабочий пример но с другим окном где логика создания и обработки окна инкапсулирована в единой функции, и велел делать также, но "железный истукан" не стал соблюдать мой шаблон. Боль и плач.

Code: Select all

// AutoCompletePopup.js
AkelPad.Include("MemHelp.js")
AkelPad.Include("log.js")

var oSys = AkelPad.SystemFunction()
var hMainWnd = AkelPad.GetMainWnd()
var hInstDLL = AkelPad.GetInstanceDll()
var sClass
var MessageLoopOwnFlag
var gPopup = {hWnd:0, hLB:0, hEdit:0, aItems:[]}

if (!AkelPad.IsInclude())
    ShowAutoCompletePopup(["Яблоко", "Груша", "Апельсин"], 0)

function ShowAutoCompletePopup(aItems, hEdit){
    gPopup.aItems = aItems
    gPopup.hEdit = hEdit || AkelPad.GetEditWnd()
    if (!gPopup.hEdit) return

    sClass = "AkelPad::AutoCompletePopup::" + hInstDLL
    if (hDlg = oSys.Call("User32::FindWindowExW", 0, 0, sClass, 0)){
        oSys.Call("User32::SetForegroundWindow", hDlg)
        return
    }

    var caretPos = GetCaretPos(gPopup.hEdit)
    var nX = caretPos.X
    var nY = caretPos.Y + AkelPad.SendMessage(gPopup.hEdit, 3188, 0, 0)

    AkelPad.WindowRegisterClass(sClass)

    // WS_POPUP | WS_VISIBLE | WS_BORDER | WS_CLIPSIBLINGS (0x90800000)
    // WS_EX_CLIENTEDGE (0x00000200) даёт одинаковую границу по всему контуру, без заголовка
    gPopup.hWnd = oSys.Call("User32::CreateWindowExW",
        0x00000200,
        sClass, "",
        0x90800000,
        nX, nY, 180, 120,
        hMainWnd, 0, hInstDLL, DialogCallback)

    if (!gPopup.hWnd){
        AkelPad.WindowUnregisterClass(sClass)
        return
    }

    oSys.Call("User32::ShowWindow", gPopup.hWnd, 1)
    SetForegroundWindow(gPopup.hWnd)

    if (!AkelPad.ScriptHandle(0, 13)){
        MessageLoopOwnFlag = true
        AkelPad.WindowGetMessage()
        MessageLoopOwnFlag = false
        AkelPad.WindowUnregisterClass(sClass)
    }
}

function DialogCallback(hWnd, uMsg, wParam, lParam){
    switch(uMsg){
        case 1: // WM_CREATE
            gPopup.hLB = oSys.Call("User32::CreateWindowExW",
                0, "LISTBOX", "",
                0x50000000 | 0x00000002 | 0x00000040, // WS_CHILD|WS_VISIBLE|LBS_NOTIFY|LBS_NOINTEGRALHEIGHT
                2, 2, 172, 112,
                hWnd, 1001, hInstDLL, 0)
            var hFont = AkelPad.SendMessage(gPopup.hEdit, 0x0031, 0, 0)
            if (hFont) AkelPad.SendMessage(gPopup.hLB, 0x0030, hFont, true)
            for (var i=0; i<gPopup.aItems.length; i++)
                AkelPad.SendMessage(gPopup.hLB, 0x0180, 0, gPopup.aItems[i])
            AkelPad.SendMessage(gPopup.hLB, 0x018E, 0, 0)
            return 0

        case 273: // WM_COMMAND
            var nID = wParam & 0xFFFF
            var nCode = (wParam >>> 16) & 0xFFFF
            // 2 = LBN_DBLCLK, 1 = LBN_SELCHANGE. Используем двойной клик, чтобы не закрывать при навигации стрелками
            if (nID == 1001 && nCode == 2){
                DoInsertAndClose()
                return 0
            }
            return 0

        case 0x0100: // WM_KEYDOWN
            if (wParam == 13){ // VK_RETURN
                DoInsertAndClose()
                return 0
            }
            if (wParam == 27){ // VK_ESCAPE
                ClosePopup()
                return 0
            }
            return 0

        case 0x0008: // WM_KILLFOCUS
            ClosePopup()
            return 0

        case 16: // WM_CLOSE
            oSys.Call("User32::DestroyWindow", hWnd)
            return 0

        case 2: // WM_DESTROY
            gPopup.hWnd = 0
            gPopup.hLB = 0
            if (MessageLoopOwnFlag) oSys.Call("User32::PostQuitMessage", 0)
            return 0
    }
    return 0
}

function DoInsertAndClose(){
    if (!gPopup.hLB) return
    var nSel = AkelPad.SendMessage(gPopup.hLB, 0x0188, 0, 0) // LB_GETCURSEL
    if (nSel == -1) return
    var nLen = AkelPad.SendMessage(gPopup.hLB, 0x018D, nSel, 0) // LB_GETTEXTLEN
    if (nLen <= 0 || nLen > 32768) return
    var sBuf = makeStrBuff(nLen + 1)
    var lpBuf = AkelPad.MemStrPtr(sBuf)
    AkelPad.SendMessage(gPopup.hLB, 0x0189, nSel, lpBuf) // LB_GETTEXT
    var sText = sBuf.replace(/\0+$/, "")
    oSys.Call("User32::SetFocus", gPopup.hEdit)
    AkelPad.ReplaceSel(sText)
    ClosePopup()
}

function ClosePopup(){
    if (gPopup.hWnd && oSys.Call("User32::IsWindow", gPopup.hWnd))
        oSys.Call("User32::PostMessageW", gPopup.hWnd, 16, 0, 0)
}

// --- Вспомогательные функции (без изменений, как в вашем шаблоне) ---
function GetCaretPos(hEdit){
    var sPointBuf = makeStrBuff(4)
    var lpPoint = sPointBuf.StrPtr()
    return (GetCaretPos = function(hEdit){
        if (!hEdit) hEdit = AkelPad.GetEditWnd()
        AkelPad.SendMessage(hEdit, 0x00D6, lpPoint, AkelPad.GetSelStart())
        oSys.Call("User32::ClientToScreen", hEdit, lpPoint)
        return {
            X: AkelPad.MemRead(lpPoint, 3),
            Y: AkelPad.MemRead(_PtrAdd(lpPoint, 4), 3)
        }
    })(hEdit)
}

function SetForegroundWindow(hWnd){
    if (oSys.Call("User32::IsIconic", hWnd)) oSys.Call("User32::ShowWindow", hWnd, 9)
    oSys.Call("User32::SetForegroundWindow", hWnd)
}

Offline
Posts: 17
Joined: Tue Feb 03, 2026 1:20 pm

Re: Свой список автозамены

Post by testuser2 »

Почти достиг того что мне нужно, но не смог пока побороть Enter, который проходит через блокирующий обработчик и проскакивает в редактор. Т.е., допустим, выбрал я пункт в списке нажимаю Enter (Enter еренаправляется окно попап-списка), этот пункт вставляется вредактор, но происходит так, то пункт вставляется с переносом на новую строку, хотя отловил Enter в сабклассе перенаправил в список, блокировал его дальнейшую обработку в редакторе с помощью WindowNoNextProc, но нет, он все равно проскаивает в редактор, гадина такая!

Code: Select all

AkelPad.Include("MemHelp.js")
AkelPad.Include("log.js")
AkelPad.Include("timer.js")
AkelPad.Include("Coder.js") // для Stop- StartRedraw()

var oSys = AkelPad.SystemFunction()
var hMainWnd = AkelPad.GetMainWnd()
var hInstDLL = AkelPad.GetInstanceDll()

var sClass
var MessageLoopOwnFlag
var shtdTaskFlag

var oPopup = {hWnd:0, hLB:0, hEdit:0, aItems:[]}

// Тестовый запуск
if (!AkelPad.IsInclude())
    ShowAutoCompletePopup(["Яблоко", "Груша", "Апельсин", "Банан", "Вишня", "Дыня", "Ежевика", "Жимолость", "Земляника", "Ирга"])

//var ticCount = oSys.Call("kernel32::GetTickCount")
function ShowAutoCompletePopup(aItems){
    var hWndEdit
    oPopup.aItems = aItems
    oPopup.hEdit = AkelPad.GetEditWnd()
    if (!oPopup.hEdit) return

    sClass = "AkelPad::AutoCompletePopup::" + hInstDLL
    if (hDlg = oSys.Call("User32::FindWindowExW", 0, 0, sClass, 0)){
        //SetForegroundWindow(hDlg)
        return
    }
    AkelPad.WindowRegisterClass(sClass)
    
    return (ShowAutoCompletePopup = function (aItems){
        hWndEdit = AkelPad.GetEditWnd()
        var caretPos = GetCaretPos(oPopup.hEdit)
        var nX = caretPos.X
        var nY = caretPos.Y + AkelPad.SendMessage(oPopup.hEdit, 3188/*AEM_GETCHARSIZE*/, 0, 0)
    
        oPopup.hWnd = oSys.Call("User32::CreateWindowExW",
            0x00000080 | 0x08000000, // WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE (критично: не забирает фокус у редактора)
            sClass, "",
            //WS_POPUP | WS_VISIBLE | WS_THICKFRAME
            0x80000000 | 0x10000000 | 0x00040000,
            nX, nY, 220, 200,
            hMainWnd, 0, hInstDLL, DialogCallback)
    
        if (!oPopup.hWnd){
            AkelPad.WindowUnregisterClass(sClass)
            return
        }
    
        // Показываем без активации (SW_SHOWNOACTIVATE = 4) ~ но все равно активируется, кстати ~
        //StopRedraw()
        oSys.Call("User32::ShowWindow", oPopup.hWnd, 4)
        //StartRedraw()
        oSys.Call("User32::SetFocus", AkelPad.GetEditWnd()) // возвращаем фокус в окно редактора, чтобы не терять вомзможность ввода
        // Поднимаем в Z-порядке, но НЕ активируем
        //oSys.Call("User32::SetWindowPos", oPopup.hWnd, -2, 0, 0, 0, 0, 0x0001 | 0x0002 | 0x0010)
        //oSys.Call("User32::SetFocus", AkelPad.GetEditWnd()) 
        // Выделяем первый элемент по умолчанию (как в Coder)
        //oSys.Call("User32::SetFocus", oPopup.hLB)
        // Отложенная инициализация выделения первого пункта
        //oSys.Call("User32::PostMessageW", oPopup.hWnd, 0x8000/*WM_APP*/, 0, 0)
        
        
        if (!AkelPad.ScriptHandle(0, 13)){
            MessageLoopOwnFlag = true
            AkelPad.WindowGetMessage()
            MessageLoopOwnFlag = false
            AkelPad.WindowUnregisterClass(sClass)
        } else {
            if (!shtdTaskFlag) {
                shutdownTasks.add(function (){
                    AkelPad.WindowUnregisterClass(sClass)
                })
                shtdTaskFlag = true
            }
        }
    })(aItems)
    
    var hWndEditSubClass
    function EditCallback(hWnd, uMsg, wParam, lParam){
        if (uMsg == 0x0202/*WM_LBUTTONUP*/){ // если был клик в произвольной области окна редактора
            AkelPad.WindowNextProc(hWndEditSubClass, hWnd, uMsg, wParam, lParam)
            ClosePopup()                    // то закрываем попап
        } else if (wParam == 13/*VK_RETURN*/ || wParam == 27/*VK_ESCAPE*/ || wParam == 38/*VK_UP*/ || wParam == 40/*VK_DOWN*/){ 
            //PrintLog('hWndEditSubClass = ' + hWndEditSubClass)
            oSys.Call("User32::PostMessageW", oPopup.hLB, uMsg, wParam, lParam)// перенаправляем сообщение в попап-листбокс
            //PrintLog('wParam = ' + wParam)
            AkelPad.WindowNoNextProc(hWndEditSubClass) // Блокируем дальнейшую обработку
            //oSys.Call("User32::PostMessageW", oPopup.hLB, 0x0100/*WM_KEYDOWN*/, 40/*VK_DOWN*/, 0)
            //oSys.Call("User32::SetFocus", hWnd)
            return 1 // обработано
        }
        return 0        
    }
    
    var oDIS, sRect, lpRect, oRect // стек сохраняемых данных функции DialogCallback   
    function DialogCallback(hWnd, uMsg, wParam, lParam){
        var WM_MOUSEACTIVATE = 33
        var MA_NOACTIVATE = 3
        var WM_NCACTIVATE = 0x86 // 134
        
        //return (DialogCallback = function (hWnd, uMsg, wParam, lParam){
        switch(uMsg){
            /*switch (uMsg){
            case 32: break
            case 132: break
            case 160: break 
            case 512: break
            default:
                PrintLog('uMsg = ' + uMsg + ' wParam = ' + wParam) 
                break
            }*/
            case 1: // WM_CREATE
                oPopup.hLB = oSys.Call("User32::CreateWindowExW",
                    0x00000200, // WS_EX_CLIENTEDGE
                    "LISTBOX", "",
                    /*WS_CHILD | WS_VISIBLE | WS_VSCROLL | LBS_NOTIFY | LBS_NOINTEGRALHEIGHT | LBS_DISABLENOSCROLL | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS*/
                    0x40000000 | 0x10000000 | 0x00200000 | 0x00000001 | 0x00000100 | 0x00001000/* | 0x0010 | 0x0040*/, 
                    /*2, 2*/0, 0, 212, 192,
                    hWnd, 1001, hInstDLL, 0)
                var hFont = AkelPad.SendMessage(oPopup.hEdit, 0x0031/*WM_GETFONT*/, 0, 0)
                if (hFont) AkelPad.SendMessage(oPopup.hLB, 0x0030/*WM_SETFONT*/, hFont, true)
                // Заполнение листбокса значениями
                for (var i = 0; i < oPopup.aItems.length; i++)
                    AkelPad.SendMessage(oPopup.hLB, 0x0180/*LB_ADDSTRING*/, 0, oPopup.aItems[i])
                
                // Выделяем первый элемент по умолчанию
//                AkelPad.SendMessage(oPopup.hLB, 0x018E/*LB_SETCURSEL*/, 0, 0)
//                oSys.Call("User32::InvalidateRect", oPopup.hLB, 0, true)
                oSys.Call("User32::PostMessageW", oPopup.hLB, 0x0100/*WM_KEYDOWN*/, 40/*VK_DOWN*/, 0)                    
                // Запускаем субклассирование редактора для того, чтобы перенаправлять VK_DOWN, VK_UP, VK_RETURN, VK_ESCAPE в попап 
                hWndEditSubClass = AkelPad.WindowSubClass(hWndEdit, EditCallback, 0x0100/*WM_KEYDOWN*/, 0x0101/*WM_KEYUP*/, 0x0202/*WM_LBUTTONUP*/) // 
                
                return 0
                
//            case 0x8000: // WM_APP // выделение первого пункта в LB
//                AkelPad.SendMessage(oPopup.hLB, 0x018E, 0, 0) // LB_SETCURSEL(0)
//                oSys.Call("User32::InvalidateRect", oPopup.hLB, 0, true)
//                return 0 
                   
            case 5: // WM_SIZE
                // Растягиваем ListBox при изменении размера попапа
                var cx = lParam & 0xFFFF
                var cy = (lParam >> 16) & 0xFFFF
                if (oPopup.hLB)
                    oSys.Call("User32::MoveWindow", oPopup.hLB, 2, 2, cx - 4, cy - 4, true)
                return 0
                
//            case 0x002B: // WM_DRAWITEM
//                //var lpDIS = lParam; // указатель на DRAWITEMSTRUCT
//                PrintLog('WM_DRAWITEM')
//                if (!oDIS) {
//                    oDIS = DRAWITEMSTRUCTwrp(lParam)
//                    sRect = makeStrBuff(8) //16/2 (sizeOf(RECT))                           
//                    lpRect = StrPtr(sRect)
//                    oRect = RECTwrp(lpRect)
//                    // PrintLog('Инициализация данных DialogCallback')
//                } else {
//                    oDIS.pStructSet(lParam)
//                }    
//                if (oDIS.CtlID() == 1001) {
//                    try {
//                        var hDC = oDIS.hDC()                //AkelPad.MemRead(_PtrAdd(lpDIS, _X64?24:16), 8); // hDC (на x64 8 байт)
//                        
//                        var nCurSel = AkelPad.SendMessage(oPopup.hLB, 0x0188, 0, 0); // LB_GETCURSEL                        
//                        // Выбрать цвет фона и текста
//                        var bkColor, textColor;
//                        if ((oDIS.itemState() & 0x0001) || (oDIS.itemID() == nCurSel)) {                        // ODS_SELECTED
//                            bkColor = oSys.Call("User32::GetSysColor", 13);     // COLOR_HIGHLIGHT
//                            textColor = oSys.Call("User32::GetSysColor", 14);   // COLOR_HIGHLIGHTTEXT
//                        } else {
//                            bkColor = oSys.Call("User32::GetSysColor", 5);      // COLOR_WINDOW
//                            textColor = oSys.Call("User32::GetSysColor", 8);    // COLOR_WINDOWTEXT
//                        } //PrintLog('bkColor textColor: ' + bkColor + ' ' + textColor) // вывод: 16777215 0
//                        
//                        // Заливка фона
//                        var hBrush = oSys.Call("Gdi32::CreateSolidBrush", bkColor)//PrintLog('hBrush = ' + hBrush) // вывод - число (хэндл)
//                        var lprcItem = oDIS.rcItemPtr()
//                        var ret = oSys.Call("User32::FillRect", hDC, lprcItem, hBrush)
//                        //PrintLog('FillRect() => ' + ret) // вывод: 1
//                        oSys.Call("Gdi32::DeleteObject", hBrush);
//                        
//                        // Рисование текста
//                        /*ret = */oSys.Call("Gdi32::SetBkMode", hDC, 1);// TRANSPARENT
//                        //PrintLog('SetBkMode() => ' + ret) // вывод 2 либо 1
//                        oSys.Call("Gdi32::SetTextColor", hDC, textColor)
//                        
//                        with(oDIS.rcItem()){
//                            oRect.leftSet(left())
//                            oRect.topSet(top())
//                            oRect.rightSet(right())
//                            oRect.bottomSet(bottom())
//                        }    
//                        var sText = GetItemText(oPopup.hLB, oDIS.itemID()) // Получение текста элемента
//                        /*ret = */oSys.Call("User32::DrawTextW", hDC, StrPtr(sText), -1, lpRect, 0x0000 | 0x0008 | 0x0010); // DT_SINGLELINE | DT_VCENTER | DT_LEFT
//                        //PrintLog('DrawTextW() => ' + ret) // вывод 17
//                        
//                        return 1; // обработано                        
//                    } catch(e) {
//                        PrintLog('Ошибка в WM_DRAWITEM' + e.message)
//                        return 0
//                    }
//                }
//                break;
    
            case WM_MOUSEACTIVATE: // 
                // Возвращаем MA_NOACTIVATE (3) → клик по попапу не активирует его, фокус остаётся в редакторе
                return MA_NOACTIVATE
            
            case WM_NCACTIVATE: // предотвращает изменение внешнего вида окна (например, заголовка) при попытке активации.
                return 1 //TRUE
//            case 7:
//                oSys.Call("User32::SetFocus", hWndEdit)    
            case 273: // WM_COMMAND                
                var nID = wParam & 0xFFFF
                var nCode = (wParam >> 16) & 0xFFFF
                //PrintLog('WM_COMMAND: ' + nID + ' ' + nCode + ' ' + wParam)
                if (nID == 1001 && nCode == 2){ // LBN_DBLCLK WScript.Echo((1874).toString(16))
                    DoInsertAndClose()
                    return 0
                }
                
                return 0
    
            case 0x0100: // WM_KEYDOWN                
                try {
                    switch (wParam){
                    case 13: // VK_RETURN
                        //oSys.Call("User32::SetFocus", oPopup.hWnd)
                        //setTimeout(DoInsertAndClose, 200) //выполняем DoInsertAndClose с отсрочкой 200 мс
                        DoInsertAndClose()
                        return 0
                    case 27: // VK_ESCAPE
                        ClosePopup()
                        return 0
                    case 38: // Up
                        var nCur = AkelPad.SendMessage(oPopup.hLB, 0x0188, 0, 0);
                        if (nCur > 0) {
                            AkelPad.SendMessage(oPopup.hLB, 0x018E, nCur - 1, 0);
                            // Принудительно перерисовать listbox, чтобы обновить выделение
                            oSys.Call("User32::InvalidateRect", oPopup.hLB, 0, true);
                        }
                        return 0;
                    case 40: // Down
                        var nCur = AkelPad.SendMessage(oPopup.hLB, 0x0188, 0, 0);
                        var nCount = AkelPad.SendMessage(oPopup.hLB, 0x018B, 0, 0);
                        if (nCur < nCount - 1) {
                            AkelPad.SendMessage(oPopup.hLB, 0x018E, nCur + 1, 0);
                            oSys.Call("User32::InvalidateRect", oPopup.hLB, 0, true);
                        }
                        return 0;
                    }
                    // Навигация и скроллинг (передаём в ListBox)
                    if (/*wParam == 38 || wParam == 40 || */wParam == 33 || wParam == 34 || wParam == 9){
                        oSys.Call("User32::SendMessageW", oPopup.hLB, uMsg, wParam, lParam)
                        return 0
                    }
                } catch(e) {
                    PrintLog('Ошибка в WM_KEYDOWN: ' + e.message)
                }
                return 0
    
            case 0x020A: // WM_MOUSEWHEEL
                oSys.Call("User32::SendMessageW", oPopup.hLB, uMsg, wParam, lParam)
                return 0
    
            case 0x0202: // WM_LBUTTONUP
                var hChild = oSys.Call("User32::ChildWindowFromPointEx", hWnd, lParam & 0xFFFF, (lParam >> 16) & 0xFFFF, 2)
                if (hChild != oPopup.hLB && hChild != 0){
                    ClosePopup()
                    return 0
                }
                return 0
    
    //        case 0x0008: // WM_KILLFOCUS
    //            if (lParam != oPopup.hLB) ClosePopup()
    //            return 0
    
            case 16: // WM_CLOSE
                oSys.Call("User32::DestroyWindow", hWnd)
                return 0
    
            case 2: // WM_DESTROY
                oPopup.hWnd = 0
                oPopup.hLB = 0
                if (MessageLoopOwnFlag) oSys.Call("User32::PostQuitMessage", 0)
                return 0
        }
        return 0
        //}(hWnd, uMsg, wParam, lParam)
    }
    function ListBoxCallback(hWnd, uMsg, wParam, lParam){
        switch(uMsg){
        case 0x02B: // WM_DRAWITEM
            
        }
    }
    function GetItemText(hLB, nItemID){
        var nLen = AkelPad.SendMessage(hLB, 0x18A/*LB_GETTEXTLEN*/, nItemID, 0)
        var sText = makeStrBuff(nLen)
        var lpText = AkelPad.MemStrPtr(sText)
        AkelPad.SendMessage(hLB, 0x0189/*LB_GETTEXT*/, nItemID, lpText) // LB_GETTEXT
        return sText
    }
    function DoInsertAndClose(){
        var nSel = AkelPad.SendMessage(oPopup.hLB, 0x0188/*LB_GETCURSEL*/, 0, 0) // LB_GETCURSEL
        if (nSel == -1) return
        var nLen = AkelPad.SendMessage(oPopup.hLB, 0x18A/*LB_GETTEXTLEN*/, nSel, 0)
        if (nLen <= 0 || nLen > 32768) return
        var sText = makeStrBuff(nLen)
        var lpText = AkelPad.MemStrPtr(sText)
        AkelPad.SendMessage(oPopup.hLB, 0x0189/*LB_GETTEXT*/, nSel, lpText) // LB_GETTEXT
        ClosePopup()
        //oSys.Call("User32::SetFocus", oPopup.hEdit) 
        AkelPad.ReplaceSel(sText)
    }
    function ClosePopup(){
        AkelPad.WindowUnsubClass(hWndEdit) // удалит самый последний субкласс, а именно тот, который был создан в DialogCallback
        if (oPopup.hWnd && oSys.Call("User32::IsWindow", oPopup.hWnd))
            oSys.Call("User32::PostMessageW", oPopup.hWnd, 16/*WM_CLOSE*/, 0, 0)
    }
    function ResetContent(){
        AkelPad.SendMessage(oPopup.hLB, 0x184/*LB_RESETCONTENT*/, 0, 0)
    }
}

//---Вспомогательные функции---//
function LoWord(nParam) {
    return (nParam & 0xFFFF)
}
//WScript.Echo(HiWord(263145))
function HiWord(nParam) {
    return (nParam >> 16) & 0xFFFF
}
function GetCaretPos(hEdit){
    var sPointBuf = makeStrBuff(4)
    var lpPoint = sPointBuf.StrPtr()
    return (GetCaretPos = function(hEdit){
        if (!hEdit) hEdit = AkelPad.GetEditWnd()
        AkelPad.SendMessage(hEdit, 0x00D6/*EM_POSFROMCHAR*/, lpPoint, AkelPad.GetSelStart())
        oSys.Call("User32::ClientToScreen", hEdit, lpPoint)
        return {
            X: AkelPad.MemRead(lpPoint, 3),
            Y: AkelPad.MemRead(_PtrAdd(lpPoint, 4), 3)
        }
    })(hEdit)
}
function SetForegroundWindow(hWnd){
    if (oSys.Call("User32::IsIconic", hWnd)) oSys.Call("User32::ShowWindow", hWnd, 9)
    oSys.Call("User32::SetForegroundWindow", hWnd)
}
/*typedef struct tagRECT {
  LONG left;
  LONG top;
  LONG right;
  LONG bottom;
} RECT, *PRECT, *NPRECT, *LPRECT;*/
function RECTwrp(pStruct, oStruct, fullInit){
    var aOffsets = (_X64)?[16,4,8,12]:[16,4,8,12]
    var aDataFields = ['left', 3,
                       'top', 3,
                       'right', 3,
                       'bottom', 3]
    return (RECTwrp = function (pStruct, oStruct, fullInit){
        return makeStructWrapper(pStruct, oStruct, fullInit, aOffsets, aDataFields)
    })(pStruct, oStruct, fullInit)
}
/*typedef struct tagDRAWITEMSTRUCT {
  UINT      CtlType;
  UINT      CtlID;
  UINT      itemID;
  UINT      itemAction;
  UINT      itemState;
  HWND      hwndItem;
  HDC       hDC;
  RECT      rcItem;
  ULONG_PTR itemData;
} DRAWITEMSTRUCT, *PDRAWITEMSTRUCT, *LPDRAWITEMSTRUCT;*/
function DRAWITEMSTRUCTwrp(pStruct, oStruct, fullInit){
    var aOffsets = (_X64)?[64,4,8,12,16,24,32,40,56]:[48,4,8,12,16,20,24,28,44]
    var aDataFields = ['CtlType', 3,
                       'CtlID', 3,
                       'itemID', 3,
                       'itemAction', 3,
                       'itemState', 3,
                       'hwndItem', 2,
                       'hDC', 2,
                       'rcItem', 6, RECTwrp,
                       'itemData', 2]
    return (DRAWITEMSTRUCTwrp = function (pStruct, oStruct, fullInit){
        return makeStructWrapper(pStruct, oStruct, fullInit, aOffsets, aDataFields)
    })(pStruct, oStruct, fullInit)
}

Code: Select all

function EditCallback(hWnd, uMsg, wParam, lParam){
        if (uMsg == 0x0202/*WM_LBUTTONUP*/){ // если был клик в произвольной области окна редактора
            AkelPad.WindowNextProc(hWndEditSubClass, hWnd, uMsg, wParam, lParam)
            ClosePopup()                    // то закрываем попап
        } else if (wParam == 13/*VK_RETURN*/ || wParam == 27/*VK_ESCAPE*/ || wParam == 38/*VK_UP*/ || wParam == 40/*VK_DOWN*/){ 
            //PrintLog('hWndEditSubClass = ' + hWndEditSubClass)
            oSys.Call("User32::PostMessageW", oPopup.hLB, uMsg, wParam, lParam)// перенаправляем сообщение в попап-листбокс
            AkelPad.WindowNoNextProc(hWndEditSubClass) // Блокируем дальнейшую обработку (не помогает)
            
            return 1 // обработано (не помогает)
        } else {
            return 0
        }
        return 0        
    }

Offline
Posts: 17
Joined: Tue Feb 03, 2026 1:20 pm

Re: Свой список автозамены

Post by testuser2 »

Название дурацкое у темы. Вообще изначально я хотел сделать не "свой" список а скопировать оригинальный список из плагина Coder, что в общем-то у меня почти получилось, только загвоздка вышла, с перехватом Enter и Escape
Post Reply