Главная » WPF » Клавиатура, мышь и стилос

0

Во времена доброго старого User32 для обработки специальных клавиш (например, комбинации Ctrl+S, означающей  сохранение) надо было либо при менять таблицу акселераторов1, либо самостоятельно обрабатывать  сообщения WM_KEYDOWN и WM_KEYUP. В Visual Basic было принято  обрабатывать события KeyDown/KeyUp, поскольку  не существовало  никакого способа пост роить  собственную  таблицу  акселераторов.  У  подхода,  требующего  сделать

1  С помощью таблиц акселераторов в User32 производилась трансляция нажатий клавиш в со%

общения WM_COMMAND.

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

Есть случаи, когда нужно общаться с устройством  напрямую,  например,  реа гировать на движения  стилоса в программе рисования, но обычно достаточно привязки к командам.   Механизм  привязки событий  ввода к командам по умол чанию и так достаточно мощный, но он к тому же расширяем,  то есть позволяет реализовать собственные  правила выполнения команды.

Структурировав приложение так, чтобы концепция привязки ввода была вы делена,  мы сможем  предоставить  пользователю возможность настраивать при вязки по своему усмотрению. В главе 7 мы затрагивали вопрос о привязке ввода, а сейчас рассмотрим  его подробнее.

Класс InputBinding

В классе InputBinding есть два интересных  свойства: Gesture и Command. Свойство  Gesture позволяет  отобразить  любой жест при вводе на заданную  ко манду. И класс InputGesture (тип данных свойства Gesture), и интерфейс ICommand (тип данных свойства Command) расширяемы,  что дает возможность отобразить любой жест на любую команду. По умолчанию WPF поддерживает жесты двух видов: от клавиатуры и от мыши, в результате чего мы можем постро ить стандартный набор акселераторов и поведения,  необходимые  для создания типичных  приложений.

В инструментах  разработки  встречается и более сложный  вид жеста: клавиа турные  аккорды. Аккорд состоит из нескольких  клавиш,  нажимаемых  последо вательно (например, в редакторе Emacs аккорд Ctrl+X, S означает «сохранить»). Чтобы  продемонстрировать расширяемость системы  привязки, добавим  в WPF привязку к клавиатурным аккордам.

Жест, который мы собираемся  поддержать, – это на самом деле набор клавиа турных жесов. Имеющийся в WPF тип KeyGesture не поддерживает клавиш без одновременно нажатых  модификаторов (Ctrl,  Shift и т.д.), но в аккордах  вторая клавиша  зачастую  нажимается сама по себе. Первым  делом  определим  новый класс  KeyChordItemGesture, который  соответствует  одной  «ноте»  в аккорде.  В классе InputGesture есть важный метод – Match, – который говорит, соответству ет ли данный жест какому нибудь событию ввода:

public class KeyChordItemGesture : InputGesture { Key _key;

ModifierKeys _modifiers;

public Key Key {

get { return _key; }

set { _key = value; }

}

public ModifierKeys Modifiers { get { return _modifiers; } set { _modifiers = value; }

}

public override bool Matches(

object targetElement, InputEventArgs inputEventArgs) {

KeyEventArgs e = inputEventArgs as KeyEventArgs;

if (e != null)

{

return e.Key == Key && Keyboard.Modifiers == Modifiers;

}

return false;

}

}

Теперь  можно определить  тип KeyChordGesture, содержащий  набор жестов, которые должны  сравниваться в порядке  следования. В классе имеется  очередь жестов; если произошло  удачное сравнение,  то жест из этой очереди удаляется. Если пользователь нажал не ту клавишу, очередь опустошается:

[ContentProperty(«Gestures»)]

public class KeyChordGesture : InputGesture { InputGestureCollection _gestures = new InputGestureCollection(); Queue<InputGesture> _chords = new Queue<InputGesture>();

public KeyChordGesture() {

}

public InputGestureCollection Gestures { get { return _gestures; } }

public override bool Matches(

object targetElement, InputEventArgs inputEventArgs) {

if (_chords.Count == 0) {

foreach (InputGesture k in _gestures) {

_chords.Enqueue(k);

}

}

if (_chords.Peek().Matches(targetElement, inputEventArgs)) {

_chords.Dequeue();

return _chords.Count == 0;

}

else if (inputEventArgs is KeyEventArgs) {

KeyEventArgs unmatched = (KeyEventArgs)inputEventArgs;

if (unmatched.Key != Key.None

&& unmatched.Key != Key.LeftCtrl

&& unmatched.Key != Key.RightCtrl

&& unmatched.Key != Key.LeftShift

&& unmatched.Key != Key.RightShift

&& unmatched.Key != Key.LeftAlt

&& unmatched.Key != Key.RightAlt)

{

_chords.Clear();

}

}

return false;

}

}

И последний шаг – определение привязки к вводу. У нас нет собственной объ ектной модели, которая включалась  бы в привязку,  но в базовом классе InputBinding отсутствует  открытый  конструктор,  поэтому  нужно  лишь  опреде лить тип так, чтобы его можно использовать в разметке:

public class KeyChordBinding : InputBinding {

public KeyChordBinding() {

}

}

Теперь эту привязку можно использовать для любого элемента  управления в наборе InputBindings:

<Window.InputBindings>

<l:KeyChordBinding

xmlns:l=’clr namespace:InputExample’

Command=’…some command…’>

<l:KeyChordBinding.Gesture>

<l:KeyChordGesture>

<l:KeyChordItemGesture Key=’X’ Modifiers=’Control’ />

<l:KeyChordItemGesture Key=’S’ Modifiers=’Control’ />

</l:KeyChordGesture>

</l:KeyChordBinding.Gesture>

</l:KeyChordBinding>

</Window.InputBindings>

С помощью  определения собственных  типов  привязки мы избегаем  «зашива ния» в код зависимостей между логикой (обработчиками команд) и вводом от поль зователя.  Это очень ценно, если приложение должно быть конфигурируемым, и к тому же дает гарантию, что мы сможем работать с любым способом ввода данных.

Философия WPF состоит в том, чтобы перейти к более декларативному прог раммированию устройств ввода, поэтому такие механизмы, как привязка к вводу, находятся  гораздо ближе к поверхности,  тогда как прямое взаимодействие с уст ройствами  отодвинуто  подальше. Если все же возникает  необходимость  в работе с устройствами напрямую, то в WPF имеется развитая  объектная  модель.

Источник: К. Андерсон  Основы  Windows Presentation Foundation. Пер. с англ. А. Слинкина — М.: ДМК Пресс, 2008 — 432 с.: ил.

По теме:

  • Комментарии