python

Исправляем Alt-Tab в LabView

  • суббота, 20 июня 2015 г. в 02:10:58
http://habrahabr.ru/post/260723/

Когда пишешь программу в среде LabView, в определенный момент её становится слишком много для того, чтобы уместиться в один экран. «Правила хорошего тона» LabView говорят о том, что в таких случаях надо разбивать один vi файл на несколько subvi файлов. Со временем таких subvi становится очень много. Однако об удобной навигации ребята из NI как-то не позаботились.

Мало того, что LabView сдвигает все свои окна в начало Alt-Tab списка (больше так не делает никто: en.wikipedia.org/wiki/Alt-Tab), так еще, несмотря на активно используемую возможность переопределять иконки для vi файлов, в списке Alt-Tab вместо них – стройные ряды из логотипов LabView:

image

Некоторых такое поведение подталкивает к покупке второго монитора. Для них в значительной степени проблема этим и решается. Еще частично помогает интерфейс Windows Aero с его миниатюрами в меню Alt-Tab. Но вроде бы лежащее на поверхности решение – (а) сделать переключение такое же, как во всех остальных приложениях, и (б) выводить в списке иконки vi – стандартными средствами недостижимо.

Судя по тому, что началось это едва ли не с самой первой версии, а соответствующая «идея по улучшению» пылится на «форуме по обмену идеями» с 2010 года forums.ni.com/t5/LabVIEW-Idea-Exchange/Make-Alt-Tab-behaviour-consistent-with-other-applications/idi-p/1162219, просить об этом National Instruments бесполезно. Однако кое-что сделать всё-таки можно.

Часть 1. Выйти из Labview за одно нажатие


Во-первых, я написал вот такой скрипт на python, при помощи которого можно переключаться между, например, браузером и текущим окном LV за одно нажатие, скажем, Alt-`:

import ctypes
 
EnumWindows = ctypes.windll.user32.EnumWindows
EnumWindowsProc = ctypes.WINFUNCTYPE(ctypes.c_bool, ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int))
GetWindowText = ctypes.windll.user32.GetWindowTextW
GetWindowTextLength = ctypes.windll.user32.GetWindowTextLengthW
IsWindowVisible = ctypes.windll.user32.IsWindowVisible
GetClassName = ctypes.windll.user32.GetClassNameW
SwitchToThisWindow = ctypes.windll.user32.SwitchToThisWindow
 
we_are_in_labview = None

def get_title(hwnd):
    length = GetWindowTextLength(hwnd)
    buff = ctypes.create_unicode_buffer(length + 1)
    GetWindowText(hwnd, buff, length + 1)
    return buff.value

def get_cls(hwnd):
    buff = ctypes.create_unicode_buffer(100)
    GetClassName(hwnd, buff, 99)
    return buff.value

def foreach_window(hwnd, lParam):
    global we_are_in_labview

    title, cls = get_title(hwnd), get_cls(hwnd)
    
    if IsWindowVisible(hwnd):
        title, cls = get_title(hwnd), get_cls(hwnd)
        
        if (title, cls) in (('Start', 'Button'), ('', 'Shell_TrayWnd')) or \
           cls == 'TeamViewer_TitleBarButtonClass':
            return True
        
        if we_are_in_labview is None:
            we_are_in_labview = cls.startswith('LV')
        else:
            if we_are_in_labview and cls.startswith('LV'):
                return True

            SwitchToThisWindow(hwnd, True)
            return False
    return True

EnumWindows(EnumWindowsProc(foreach_window), 0)

Вообще, я параллельно писал на c и на python, здесь привожу версию на python потому что так код чуть более читаемый и его можно запустить без visual studio (требуется лишь установленный python любой версии: 2.x или 3.x).
Повесить запуск скрипта на сочетание клавиш можно и на python’е, но при помощи autohotkey сделать это проще:

#IfWinNotActive ahk_class PuTTY
!`::
Run, C:\alttab\switch.py,,Hide

(здесь биндинг отключается в отдельно взятой программе putty)

Часть 2. Переключиться в vi кликом на его иконку


Во-вторых, я доработал соответствующий quickqrop плагин Show Open VIs, чтобы придать ему божеский вид и добавил навигацию с клавиатуры.

image
image


По сравнению с существующими инструментами навигации Show Open VIs:
– лучше Project Explorer тем, что показывает только открытые файлы, а не все файлы в проекте, плюс не занимает лишнее место на панели задач и в Alt-Tab списке (рис.слева);
– лучше встроенного в LV менеджер окон (Ctrl-Alt-W) наличием иконок (рис.справа);
– лучше системного Alt-Tab тем, что это именно иконки vi а не многократный логотип NI.

По нажатию на правую кнопку мыши можно выбрать, куда необходимо переключиться: на Front Panel или на Block Diagram.

В оригинале этот плагин выглядел очень сырым и неаккуратным. Всё друг на друга налезало, а когда уменьшаешь размер окна до размеров, сравнимых с обычным окном alt-tab, вообще переставал работать.

Код плагина я выложил на гитхабе. Проверял в LV 2011 и 2014, x32 и x64. Для установки надо скопировать несколько файлов в каталог LabView в Program Files, перезапуск Labview не требуется. Зависит от «OpenG File Library». Подробности в readme.

Управление с клавиатуры сделал такое: Ctrl-Space Ctrl-4 для запуска (чтобы уж точно не было конфликтов с другими плагинами), [Ctrl-] Tab или стрелка вправо следующий пункт, [Ctrl-] Shift-Tab или стрелка влево – предыдущий, Enter или Space – переключение, Esc – выход.

Чтобы не нажимать этот лишний Ctrl-Space (вход в меню quickdrop), можно использовать вот такой скрипт на autohotkey, чтобы запуск происходил, например, по Ctrl-`:

#IfWinActive ahk_class LVDChild
^`b::
Send ^{Space}
WinWait Quick Drop
Send ^4

Временной зазор между появлением окна quickdrop и его закрытием после получения сочетания клавиш составил у меня около 0.12 секунды. В принципе, это неплохо, но глаз успевает увидеть «лишнее» окно. Тем, кто, как я, quickdrop кроме как для запуска плагинов не использует, может оказаться полезной вот такая недокументированная опция в labview.ini:

QuickDropTransparency=100

Она делает окно QuickDrop невидимым (параметр означает, что на 100%) с сохранением всего функционала.

Как совместить эти два улучшения (отображение иконок vi и привычное поведение alt-tab) я не придумал – все окна LabView находятся в одной группе окон и программно перемещаются внутри z-order последовательности точно так же, как и через GUI: только как одно целое, то есть информация о том, из какого рода было переключение – изнутри LabView или снаружи LabView – теряется. Можно запоминать историю при нажатии alt-tab, но такой способ не универсален, так как не отлавливает переключения при помощью мыши.

В итоге


Установив описанные скрипт и плагин, получаем такие возможности: нажимая Alt-` очень удобно переключаться между, например, браузером и каким-то конкретным окном в LabView, а по нажатию Ctrl-` можно видеть иконки открытых vi файлов и переключаться между ними либо при помощи мыши либо с клавиатуры.