Улучшение меню с дублирующимися хоткеями

Здесь обсуждается всё, что касается макросов.
User avatar
John Doe
Бюрократ
Posts: 11415
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 17 times
Been thanked: 101 times

Улучшение меню с дублирующимися хоткеями

Post by John Doe » Fri 05 Dec, 2014 14:54

При наличии в меню или списке несколько пунктов с одинаковым хоткеем, фар всегда запускает первый из них.

Предлагаемый скрипт улучшает это поведение:
  • При первом нажатии в списке остаются только элементы с хоткеем, соответствующем нажатой клавише.
  • Последующие нажатия циклически перемещают курсор.
    Для того чтобы выбрать пункт можно использовать Enter, или Ctrl-<хоткей> (см. Дополнительные функции).
  • Нажатие Esc или F10 отменяет фильтр.
Дополнительные функции:
  • Если использовать хоткей с модификатором Ctrl, то хоткей срабатывает независимо от того, есть ли в списке дубликаты.
    При этом если курсор уже стоит на элементе с хоткеем, то будет выполнен именно этот элемент (а не первый по порядку).
  • Если использовать хоткей с модификатором Alt, то фильтрации не происходит, а только лишь перемещается курсор
Для корректной работы требуется FAR 3 build >=4215.
[attachment=0]ConcurrentHotkeys.7z[/attachment]
P.S.
В основе лежит идея отсюда: viewtopic.php?p=126218#p126218
Attachments
ConcurrentHotkeys.7z
(1.8 KiB) Downloaded 186 times

User avatar
John Doe
Бюрократ
Posts: 11415
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 17 times
Been thanked: 101 times

Скрипт фильтра пользовательского меню

Post by John Doe » Fri 05 Dec, 2014 20:37

sToLp wrote: А вот теперь подумалось: а может быть Вы сможете универсальный макрос предложить?
Можем:
  1. local F = far.Flags
  2. Event { group="DialogEvent"; description="Concurrent hotkeys menu handler";
  3.   condition=function(Event,param)
  4.     return param.Msg==F.DN_LISTHOTKEY and Event==F.DE_DLGPROCINIT
  5.   end;
  6.   action=function(Event,param)
  7.     local hDlg,ID,ItemIndex = param.hDlg,param.Param1,param.Param2
  8.     if hDlg:send(F.DM_LISTINFO,ID).ItemsNumber~=Object.ItemCount then return end --macro api item indexes does not count hidden items
  9.     local hk = Object.GetHotkey(ItemIndex)
  10.     if Object.CheckHotkey(hk,ItemIndex+1)~=0 then
  11.       hDlg:send(F.DM_SHOWDIALOG,0)
  12.       local list = far.GetDlgItem(hDlg, ID)[6] --[6]  Selected/ListItems: integer/table
  13.       for i=#list,1,-1 do
  14.         if Object.GetHotkey(i)~=hk then
  15.           local item = list[i]
  16.           hDlg:send(F.DM_LISTUPDATE, ID,{Index=i,Text=item.Text,Flags=bor(item.Flags,F.LIF_HIDDEN)})
  17.         end
  18.       end
  19.       Menu.Filter(4) --подправить высоту списка под количество элементов
  20.       hDlg:send(F.DM_SHOWDIALOG,1)
  21.       return 1
  22.     end
  23.   end;
  24. }
P.S.
Ограничение: не предназначен для работы в отфильтрованных списках.

User avatar
John Doe
Бюрократ
Posts: 11415
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 17 times
Been thanked: 101 times

Скрипт фильтра пользовательского меню

Post by John Doe » Fri 05 Dec, 2014 22:26

И заодно альтернативный вариант, без фильтрации.
Если в меню есть дублирующиеся хоткееи, то при нажатии соответствующих клавиш вместо выполнения будет происходить только позиционирование курсора (циклически).
  1. local F = far.Flags
  2. local InitPos
  3. Event { group="DialogEvent";
  4.   condition=function(Event,param)
  5.     return param.Msg==F.DN_CONTROLINPUT and Event==F.DE_DLGPROCINIT
  6.   end;
  7.   action=function(Event,param)
  8.     InitPos = Object.CurPos
  9.   end;
  10. }
  11. Event { group="DialogEvent";
  12.   condition=function(Event,param)
  13.     return param.Msg==F.DN_LISTHOTKEY and Event==F.DE_DLGPROCINIT
  14.   end;
  15.   action=function(Event,param)
  16.     local hDlg,ID = param.hDlg,param.Param1
  17.     if hDlg:send(F.DM_LISTINFO,ID).ItemsNumber~=Object.ItemCount then return end --macro api item indexes does not count hidden items
  18.     local hk = Object.GetHotkey() --ItemIndex
  19.     if Object.CheckHotkey(hk,Object.CurPos+1)==0 then return end
  20.     local Pos = Object.CheckHotkey(hk,InitPos+1)
  21.     if Pos~=0 then
  22.       hDlg:send(F.DM_LISTSETCURPOS,ID,{SelectPos=Pos})
  23.     end
  24.     return true
  25.   end;
  26. }

User avatar
sToLp
Posts: 764
Joined: Thu 23 Jul, 2009 10:16
Has thanked: 57 times
Been thanked: 5 times

Скрипт фильтра пользовательского меню

Post by sToLp » Fri 05 Dec, 2014 22:49

John Doe

Просто супер!

Вариант ConcurrentHotkeys2.lua больше подходит для компактных меню, полностью помещающихся на экране. А первый вариант — для объёмных, типа как в Macro Browser alt.

А нельзя ли сделать оба применимыми, например позиционирование с Alt, как подсказал HaRT?

User avatar
John Doe
Бюрократ
Posts: 11415
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 17 times
Been thanked: 101 times

Скрипт фильтра пользовательского меню

Post by John Doe » Fri 05 Dec, 2014 23:01

Совместил два варианта, теперь по умолчанию фильтруется, а с Alt только позиционируется.
  1. local F = far.Flags
  2. Event { group="DialogEvent"; description="Concurrent hotkeys menu handler";
  3.   condition=function(Event,param)
  4.     return param.Msg==F.DN_LISTHOTKEY and Event==F.DE_DLGPROCINIT
  5.     and band(Mouse.LastCtrlState,0x1+0x2)==0
  6.   end;
  7.   action=function(Event,param)
  8.     local hDlg,ID,ItemIndex = param.hDlg,param.Param1,param.Param2
  9.     if hDlg:send(F.DM_LISTINFO,ID).ItemsNumber~=Object.ItemCount then return end --macro api item indexes does not count hidden items
  10.     local hk = Object.GetHotkey() --ItemIndex
  11.     if Object.CheckHotkey(hk,ItemIndex+1)~=0 then
  12.       hDlg:send(F.DM_SHOWDIALOG,0)
  13.       local list = far.GetDlgItem(hDlg, ID)[6] --[6]  Selected/ListItems: integer/table
  14.       for i=#list,1,-1 do
  15.         if Object.GetHotkey(i)~=hk then
  16.           local item = list[i]
  17.           hDlg:send(F.DM_LISTUPDATE, ID,{Index=i,Text=item.Text,Flags=bor(item.Flags,F.LIF_HIDDEN)})
  18.         end
  19.       end
  20.       Menu.Filter(4) --подправить высоту списка под количество элементов
  21.       hDlg:send(F.DM_SHOWDIALOG,1)
  22.       return 1
  23.     end
  24.   end;
  25. }
  26.  
  27. local InitPos
  28. Event { group="DialogEvent";
  29.   condition=function(Event,param)
  30.     return param.Msg==F.DN_CONTROLINPUT and Event==F.DE_DLGPROCINIT
  31.   end;
  32.   action=function(Event,param)
  33.     InitPos = Object.CurPos
  34.   end;
  35. }
  36. Event { group="DialogEvent";
  37.   condition=function(Event,param)
  38.     return param.Msg==F.DN_LISTHOTKEY and Event==F.DE_DLGPROCINIT
  39.   end;
  40.   action=function(Event,param)
  41.     local hDlg,ID,ItemIndex = param.hDlg,param.Param1,param.Param2
  42.     local x,y = {},{}
  43.     local ii = 0
  44.     for i,item in ipairs(far.GetDlgItem(hDlg, ID)[6]) do --[6]  Selected/ListItems: integer/table
  45.        if band(item.Flags,F.LIF_HIDDEN)==0 then
  46.          ii = ii+1; x[i],y[ii] = ii,i
  47.        end
  48.     end
  49.     local hk = Object.GetHotkey(x[ItemIndex])
  50.     if Object.CheckHotkey(hk,ItemIndex+1)==0 then return end
  51.     local Pos = Object.CheckHotkey(hk,y[InitPos]+1)
  52.     if Pos~=0 then
  53.       hDlg:send(F.DM_LISTSETCURPOS,ID,{SelectPos=y[Pos]})
  54.     end
  55.     return true
  56.   end;
  57. }

User avatar
sToLp
Posts: 764
Joined: Thu 23 Jul, 2009 10:16
Has thanked: 57 times
Been thanked: 5 times

Улучшение меню с дублирующимися хоткеями

Post by sToLp » Fri 05 Dec, 2014 23:36

John Doe

Ну у Вас и производительность! Мощно!

В пользовательском меню и в меню конфликтов макросов третий вариант работает вроде как надо по обеим направлениям: и по фильтру, и по позиционированию.

Исправлено: ввиду малого числа совпадений хоткеев (и практически всех парных) в этих меню глючность позиционирования не проявлялась. Но стоило только добавить третье совпадение, как она тут же обнаружилась.


А в Macro Browser alt. позиционирование глючит: то переход производится только между двумя ближайшими одинаковыми хоткеями, а то и вовсе один и тот же хоткей попеременно то вверху видимой части экрана показывается, то внизу.

Добавлено: это отчётливо подтверждается и в меню "Ассоциации для файлов".
Last edited by sToLp on Sat 06 Dec, 2014 08:18, edited 1 time in total.

User avatar
John Doe
Бюрократ
Posts: 11415
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 17 times
Been thanked: 101 times

Улучшение меню с дублирующимися хоткеями

Post by John Doe » Sat 06 Dec, 2014 00:25

sToLp wrote: позиционирование глючит
Это какая-то неведомая херня.
Похоже баги в фаре, причём в 2х местах:
viewtopic.php?f=54&t=7039&p=126293#p126293
viewtopic.php?f=15&t=4623&p=126294#p126294

User avatar
sToLp
Posts: 764
Joined: Thu 23 Jul, 2009 10:16
Has thanked: 57 times
Been thanked: 5 times

Улучшение меню с дублирующимися хоткеями

Post by sToLp » Sat 06 Dec, 2014 08:18

Уточнил своё предыдущее сообщение.

siberia-man
Posts: 70
Joined: Sat 28 Jun, 2014 23:07
Been thanked: 1 time

Улучшение меню с дублирующимися хоткеями

Post by siberia-man » Sat 06 Dec, 2014 08:46

Code: Select all

1,3d0                                                          
<                                                              
< -- http://forum.farmanager.com/viewtopic.php?f=15&t=9197     
<                                                              
46d42                                                          
<     local y = {}                                             
Одна неинициализированная переменная бросает ошибку.

Забыл добавить: происходит только в случае, одного найденного элемента. Проверял на списке выбора синтаксиса far colorer

siberia-man
Posts: 70
Joined: Sat 28 Jun, 2014 23:07
Been thanked: 1 time

Улучшение меню с дублирующимися хоткеями

Post by siberia-man » Sat 06 Dec, 2014 08:49

Хотелка: По Alt+letter позиционировать курсор, даже если в списке один элемент.

В lua/luafar не очень хорошо разбираюсь. Поэтому пока решил так:

Code: Select all

--    if Object.CheckHotkey(hk,x[ItemIndex]+1)==0 then return end
Что тоже имеет свой плюс. Видим, что выбираем.

User avatar
sToLp
Posts: 764
Joined: Thu 23 Jul, 2009 10:16
Has thanked: 57 times
Been thanked: 5 times

Улучшение меню с дублирующимися хоткеями

Post by sToLp » Sat 06 Dec, 2014 09:53

siberia-man wrote:Хотелка: По Alt+letter позиционировать курсор, даже если в списке один элемент.
... Видим, что выбираем.
Поддерживаю.

И вот это бы ещё добавить: "по символу с Ctrl — сразу применение пункта списка".

User avatar
John Doe
Бюрократ
Posts: 11415
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 17 times
Been thanked: 101 times

Улучшение меню с дублирующимися хоткеями

Post by John Doe » Sat 06 Dec, 2014 11:23

siberia-man wrote: Хотелка: По Alt+letter позиционировать курсор, даже если в списке один элемент.
Ок.
sToLp wrote: И вот это бы ещё добавить: "по символу с Ctrl — сразу применение пункта списка".
"Применение" и без Ctrl работает.
Но не в MBA. Посмотрю как-нибудь.

User avatar
sToLp
Posts: 764
Joined: Thu 23 Jul, 2009 10:16
Has thanked: 57 times
Been thanked: 5 times

Улучшение меню с дублирующимися хоткеями

Post by sToLp » Sat 06 Dec, 2014 11:54

John Doe wrote:"Применение" и без Ctrl работает.
Но не в MBA. Посмотрю как-нибудь.
Да, "применение" по Enter`у в большинстве меню работает.
Но тут 3 существенных момента.
Пользователь нацелен на хоткей, держит его под пальцем. Только что нажимал Alt-хоткей. И ему сподручнее в этот момент нажать Ctrl-хоткей, нежели переключится на Enter. Это во-первых.
Во-вторых, у той, как я полагаю, довольно большой группы пользователей, которая практикует плагин AltHistory, есть уже привычка работать с Ctrl-хоткей.
В третьих, расширить арсенал команд, работающих в МВА, дополнительной возможностью, совпадающей с популярной тенденцией, было бы весьма полезно.
Спасибо Вам за готовность заняться этим!

И ещё одно пожелание. А нельзя ли ещё сделать так, чтобы после сброса пользователем отфильтрованного меню (по Esc или F10) происходил возврат к родительскому меню? Причём для МВА это особенно желательно.

User avatar
John Doe
Бюрократ
Posts: 11415
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 17 times
Been thanked: 101 times

Улучшение меню с дублирующимися хоткеями

Post by John Doe » Sat 06 Dec, 2014 13:51

sToLp wrote: Пользователь нацелен на хоткей, держит его под пальцем. Только что нажимал Alt-хоткей. И ему сподручнее в этот момент нажать Ctrl-хоткей, нежели переключится на Enter.
А при чём тут Enter? Достаточно нажать тот же хоткей без Alt.
sToLp wrote: А нельзя ли ещё сделать так, чтобы после сброса пользователем отфильтрованного меню (по Esc или F10) происходил возврат к родительскому меню?
Можно по Esc/F10 полностью снимать все фильтры.
Но конкретно для MBA нужно делать иначе, и обсуждать в другой теме (вижу вы и там написали уже).

siberia-man
Posts: 70
Joined: Sat 28 Jun, 2014 23:07
Been thanked: 1 time

Улучшение меню с дублирующимися хоткеями

Post by siberia-man » Sat 06 Dec, 2014 14:11

John Doe wrote: Можно по Esc/F10 полностью снимать все фильтры.
По ESC (как действие по умолчанию) было бы здорово снимать все фильтры и возвращаться к первоначальному виду списка.

User avatar
John Doe
Бюрократ
Posts: 11415
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 17 times
Been thanked: 101 times

Улучшение меню с дублирующимися хоткеями

Post by John Doe » Sat 06 Dec, 2014 16:08

Code: Select all

local F = far.Flags
local hDlg,ID
Macro { description="Reset filters";
  area="Dialog Menu MainMenu UserMenu Disks"; key="Esc F10";
  uid="3DE219F0-7B83-453B-A1FA-E780640F7093";
  condition=function()
    hDlg = far.AdvControl"ACTL_GETWINDOWINFO".Id
    ID = Area.Dialog and Dlg.CurPos or 1
    if Area.Dialog and Dlg.ItemType~=F.DI_LISTBOX then return end
    return hDlg:send(F.DM_LISTINFO,ID).ItemsNumber~=Object.ItemCount
  end;
  action=function()
    if Menu.Filter(0)==1 then Menu.Filter(0,0); return end
    hDlg:send(F.DM_ENABLEREDRAW,0)
    for i,item in ipairs(far.GetDlgItem(hDlg,ID)[6]) do--[6]  Selected/ListItems: integer/table 
      if band(item.Flags,F.LIF_HIDDEN)~=0 then
        hDlg:send(F.DM_LISTUPDATE,ID,{Index=i,Text=item.Text,Flags=band(item.Flags,bnot(F.LIF_HIDDEN))})
      end
    end
    Menu.Filter(4) --подправить высоту списка под количество элементов
    hDlg:send(F.DM_ENABLEREDRAW,1)
  end;
}

Post Reply

Return to “Обсуждение макросов”