Обработка ключевых событий

Когда пользователь нажимает клавишу на клавиатуре или нажимает несколько клавиш одновременно, система OS X генерирует ключевые события. Когда больше чем одна клавиша нажата, один или больше тех ключей изменяет значение нажатой «основной» клавиши. Обычно используемыми модифицирующими клавишами является Команда, Управление, Опция (Высокий звук) и клавиши Shift. В определенных контекстах и комбинациях, нажатия клавиш представляют команды операционной системе или frontmost приложению и не символам, которые будут вставлены в текст.

В этой главе рассматриваются, как Вы обрабатываете ключевые события, особенно ключевые вниз события.

Обзор ключевых событий

Существенные факты о ключевых событиях, как представлено в Ключевых событиях и Пути Ключевых событий, являются следующим:

Переопределение keyDown: Метод

Большая часть респондента возражает (такие как пользовательские представления), обрабатывают ключевые события путем переопределения keyDown: метод, объявленный NSResponder. Объект может обработать событие всегда, это считает целесообразным. Текстовый объект обычно интерпретирует сообщение как запрос для вставки текста, в то время как рисованного объект мог бы только интересоваться несколькими ключами, теми, которые Удаляют и клавиши со стрелками как команды, чтобы удалить и переместить выбранные пункты. Как с событиями от нажатия мыши, объект респондента часто хочет запросить переданный - в NSEvent объект узнать больше о событии и получить данные это должно обработать его. Некоторые более полезные NSEvent методы для ключевых событий являются следующим:

В реализации a keyDown: метод, респондент может извлечь символьные данные, содержавшие связанным NSEvent возразите и вставьте его в отображаемый текст; или это может интерпретировать символьные данные как сочетание клавиш или сочетание клавиш, или связывающееся с действием клавиатуры или запрашивающее некоторое специализированное поведение. Однако Набор Приложения обеспечивает некоторые удобные ярлыки для того, чтобы сделать это, описанное ниже.

Обработка действий клавиатуры и вставки текста

Респондент возражает, что соглашение с текстом, таким как текст представления, должно быть подготовлено обработать ключевые события, которые могут или быть символами для вставки или действия клавиатуры. Как отмечено по Пути Ключевых событий, действия клавиатуры являются специальным видом сообщения действия, зависящего от механизма привязок клавиш, связывающего определенные нажатия клавиш (например, Управление-e) к определенным командам, связанным с текстом (например, переместите точку вставки до конца текущей строки). Эти команды реализованы в методах, определенных NSResponder дать функциональные интерпретации на представление тех физических нажатий клавиш.

В обработке ключевого события в keyDown:, объект представления, ожидающий вставлять текст сначала, определяет ли символ или символы NSEvent объект представляет действие клавиатуры. Если они делают, это отправляет связанное сообщение действия; если они не делают, это вставляет символы как текст. В частности представление может сделать одну из двух вещей в его реализации:

  • Это может извлечь символы объекта-события с помощью characters метод NSEvent и интерпретируйте их, чтобы видеть, связаны ли они с известным действием клавиатуры. Если они, это вызывает метод соответствующих мер сам по себе или суперпредставление. Этому подходу обескураживают.

  • Это может передать событие системе управления ввода текста Какао путем вызова NSResponder метод interpretKeyEvents:. Входная система управления проверяет нажатую клавишу по записям во всех соответствующих словарях привязки клавиш и, если существует соответствие, отправляет a doCommandBySelector: обменивайтесь сообщениями назад к представлению. Иначе, это отправляет insertText: обменивайтесь сообщениями назад к представлению, и представление реализует этот метод, чтобы извлечь и вывести на экран текст.

Перечисление 5-1 показывает, как второй подход мог бы посмотреть в коде.

Перечисление 5-1  Используя входную систему управления для интерпретации ключевого события

- (void)keyDown:(NSEvent *)theEvent {
    [self interpretKeyEvents:[NSArray arrayWithObject:theEvent]];
}
 
// The following action methods are declared in NSResponder.h
- (void)insertTab:(id)sender {
    if ([[self window] firstResponder] == self) {
        [[self window] selectNextKeyView:self];
    }
}
 
- (void)insertBacktab:(id)sender {
    if ([[self window] firstResponder] == self) {
        [[self window] selectPreviousKeyView:self];
    }
}
 
- (void)insertText:(id)string {
    [super insertText:string];  // have superclass insert it
}

Обратите внимание на то, что этот пример включает переопределение insertText: это просто вызывает реализацию суперкласса. Это сделано для разъяснения роли менеджера по вводу, но не действительно необходимо. Значение по умолчанию (NSResponder) реализация doCommandBySelector: определяет, реагирует ли представление на селектор действия клавиатуры и, если представление действительно отвечает, это вызывает метод действия; если представление не отвечает, doCommandBySelector: отправляется следующему респонденту (и т.д. цепочка респондента). Поэтому представление должно только реализовать методы действия, соответствующие действиям, которые оно хочет обработать. Другая импликация поведения входного менеджера - то, что, если словарь привязок клавиш соответствует физическое нажатие клавиши действию клавиатуры, объект респондента просто должен переопределить связанный метод действия обработать то нажатие клавиши. Например, для обработки привязки по умолчанию Клавиши выхода респондент переопределил бы cancelOperation: метод NSResponder.

Рассматриваемый вопрос суперпредставления, обрабатывающего сообщение действия клавиатуры, инициируемое подпредставлением, является путем NSScrollView возразите командам страницы вниз дескрипторов. Этот объект представления прокрутки является составным объектом, состоящим из представления документа, представления клипа ( NSClipView объект) и скроллер ( NSScroller объект). Поскольку это - содержание или координирование объекта, NSScrollView объект является суперпредставлением всех других объектов в этой группировке. Теперь скажите, что Ваше пользовательское представление является представлением документа представления прокрутки. Если Вы реализуете keyDown: отправить interpretKeyEvents: менеджеру по вводу, но не реализуют scrollPageDown: метод действия, представление документа будет все еще прокручено в представлении прокрутки, когда пользователь нажмет клавишу Page Down (или независимо от того, что привязка клавиш имеет силу для той функции). Это происходит, потому что каждый следующий респондент в цепочке респондента запрашивается, чтобы видеть, отвечает ли она на scrollPageDown:. NSScrollView класс обеспечивает реализацию по умолчанию, таким образом, вызывается эта реализация.

Приложения другой, что те, которые имеют дело с текстом, могут использовать входную систему управления для их преимущества. Например, пользовательское представление в приложении получения могло бы использовать клавиши со стрелками, чтобы "пошагово переместить” графические объекты точные расстояния. В стандартном словаре привязок клавиш клавиши со стрелками связываются с moveUp:, moveDown:, moveLeft:, и moveRight: методы NSResponder. Так кодируйте подобный показанному в Перечислении 5-2, работал бы для пошагового перемещения графических объектов вокруг.

Перечисление 5-2  , Обрабатывающее символы клавиши со стрелкой с помощью входной системы управления

- (void)keyDown:(NSEvent *)theEvent {
    // Arrow keys are associated with the numeric keypad
    if ([theEvent modifierFlags] & NSNumericPadKeyMask) {
        [self interpretKeyEvents:[NSArray arrayWithObject:theEvent]];
    } else {
        [super keyDown:theEvent];
    }
}
 
-(IBAction)moveUp:(id)sender
{
    [self offsetLocationByX:0 andY: 10.0];
    [[self window] invalidateCursorRectsForView:self];
}
 
-(IBAction)moveDown:(id)sender
{
    [self offsetLocationByX:0 andY:-10.0];
    [[self window] invalidateCursorRectsForView:self];
}
 
-(IBAction)moveLeft:(id)sender
{
    [self offsetLocationByX:-10.0 andY:0.0];
    [[self window] invalidateCursorRectsForView:self];
}
 
-(IBAction)moveRight:(id)sender
{
    [self offsetLocationByX:10.0 andY:0.0];
    [[self window] invalidateCursorRectsForView:self];
}

В большинстве экземпляров, interpretKeyEvents: подход предпочтителен для интерпретирования - самостоятельно приближаются. Эта рекомендация является особенно истиной для тех пользовательских представлений в приложениях, таких как текстовые процессоры и графические редакторы, делающие львиную долю работы. Основной фактор, одобряющий использование системы управления ввода текста, - то, что с ним Вы не должны соединять функцию проводами к физическому ключу. Что, если пользователь использует портативный компьютер, испытывающий недостаток в функциональной клавише, соединенной проводами приложением? Лучше, более гибкий подход должен указать альтернативные привязки клавиш в словаре. Другое преимущество системы управления ввода текста состоит в том, что она позволяет ключевым событиям интерпретироваться как текст, не непосредственно доступный на клавиатуре, такой как Кандзи и некоторые символы с диакритикой.

Особенно интерпретация нажатий клавиш

Несмотря на то, что использование системы управления ввода текста выгодно, можно интерпретировать физические ключи сами в keyDown: и обработайте их специализированным способом. NSEvent класс объявляет десятки констант, идентифицирующих определенные ключи или ключевым символом или ключевой функцией; Константы в справочной документации для того класса описывают эти константы. Перечисление 5-3 показывает выборку.

  Константы ключа Listing 5-3 Some определяются NSResponder

enum {
    NSUpArrowFunctionKey            = 0xF700,
    NSDownArrowFunctionKey          = 0xF701,
    NSLeftArrowFunctionKey          = 0xF702,
    NSRightArrowFunctionKey         = 0xF703,
    NSF1FunctionKey                 = 0xF704,
    NSF2FunctionKey                 = 0xF705,
    NSF3FunctionKey                 = 0xF706,
    // other constants here
    NSUndoFunctionKey               = 0xF743,
    NSRedoFunctionKey               = 0xF744,
    NSFindFunctionKey               = 0xF745,
    NSHelpFunctionKey               = 0xF746,
    NSModeSwitchFunctionKey         = 0xF747
};

Кроме того, текстовая система определяет константы, представляющие обычно используемые символы Unicode, такие как вкладка, удалите, и возврат каретки. Для списка этих констант посмотрите Константы в Ссылке класса NSText.

В Вашей реализации keyDown: можно сравнить одну из этих констант к символьным данным объекта ключевого события определить, была ли определенная клавиша нажата и затем действие соответственно. Поскольку можно вспомнить, characters или charactersIgnoringModifiers методы возвращаются NSString объект для значения ключа вместо символа, потому что нажатие клавиши могло бы генерировать многократные символы. (Фактически, эти методы могли даже возвратить пустую строку, если мертвая клавиша — нажата клавиша без символа, отображенного на ней —.), Если Ваша реализация keyDown: обрабатывает односимвольное значение ключа, такое как клавиша со стрелкой, можно исследовать длину возвращаемой строки и, если это - отдельный символ, доступ тот символ с помощью NSString метод characterAtIndex: с индексом 0. Тогда тест, что символ против одного из NSResponder константы.

Перечисление 5-4 показывает, как Вы могли бы выполнить тот же графический объект, «пошагово перемещающий», как сделано в Перечислении 5-2, но на сей раз сам объект респондента определяет, была ли нажата клавиша со стрелкой.

Перечисление 5-4  , Обрабатывающее символы клавиши со стрелкой путем интерпретации физического ключа

- (void)keyDown:(NSEvent *)theEvent {
 
    if ([theEvent modifierFlags] & NSNumericPadKeyMask) { // arrow keys have this mask
        NSString *theArrow = [theEvent charactersIgnoringModifiers];
        unichar keyChar = 0;
        if ( [theArrow length] == 0 )
            return;            // reject dead keys
        if ( [theArrow length] == 1 ) {
            keyChar = [theArrow characterAtIndex:0];
            if ( keyChar == NSLeftArrowFunctionKey ) {
                [self offsetLocationByX:-10.0 andY:0.0];
                [[self window] invalidateCursorRectsForView:self];
                return;
            }
            if ( keyChar == NSRightArrowFunctionKey ) {
                [self offsetLocationByX:10.0 andY:0.0];
                [[self window] invalidateCursorRectsForView:self];
                return;
            }
            if ( keyChar == NSUpArrowFunctionKey ) {
                [self offsetLocationByX:0 andY: 10.0];
                [[self window] invalidateCursorRectsForView:self];
                return;
            }
            if ( keyChar == NSDownArrowFunctionKey ) {
                [self offsetLocationByX:0 andY:-10.0];
                [[self window] invalidateCursorRectsForView:self];
                return;
            }
            [super keyDown:theEvent];
        }
    }
    [super keyDown:theEvent];
}

Можно также преобразовать NSResponder постоянный к строке возражают и затем сравнивают тот объект со значением, возвращенным characters или charactersIgnoringModifiers, как в этом примере:

        unichar la = NSLeftArrowFunctionKey;
        NSString *laStr = [[[NSString alloc] initWithCharacters:&la length:1] autorelease];
        if ([theArrow isEqual:laStr]) {
            [self offsetLocationByX:-10.0 andY:0.0];
            [[self window] invalidateCursorRectsForView:self];
            return;
        }

Однако этот подход является более интенсивно использующим память.

Обработка ключевых эквивалентов

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

Приложение направляет ключевое эквивалентное событие путем отправки ему сначала вниз иерархии представления окна. Глобальная переменная NSApplication возразите диспетчеризирует события, которые это распознает как потенциальные ключевые эквиваленты (на основе присутствия флагов модификатора) в sendEvent: метод. Это отправляет a performKeyEquivalent: обменивайтесь сообщениями к ключу NSWindow объект. Этот объект передает ключевые эквиваленты вниз его иерархия представления путем вызова NSView реализация по умолчанию performKeyEquivalent:, который передает сообщение к каждому из его подпредставлений (включая контекстный и всплывающие меню), пока каждый не отвечает YES; если ни один не делает, это возвращается NO. Если никакой объект в иерархии представления не обрабатывает ключевой эквивалент, NSApp тогда отправляет performKeyEquivalent: к меню в строке меню. NSWindow подклассы отговорены переопределить performKeyEquivalent:.

Некоторые классы Какао, такой как NSButton, NSMenu, NSMatrix, и NSSavePanel, обеспечьте реализации по умолчанию performKeyEquivalent:. Например, можно установить клавишу Return как ключевой эквивалент NSButton возразите и, когда эта клавиша нажата, действия кнопки, как будто по ней щелкнули. Однако подклассы других классов Набора Приложения (включая пользовательские представления) должны обеспечить свои собственные реализации performKeyEquivalent:. Реализация должна извлечь символы для ключевого эквивалента от переданного - в NSEvent объект с помощью charactersIgnoringModifiers метод и затем исследует их, чтобы определить, являются ли они ключевым эквивалентом, он распознает. Это обрабатывает ключевой эквивалент очень, как это обработало бы ключевое событие в keyDown: (см. Переопределение keyDown: Метод). После обработки ключевого эквивалента должна возвратиться реализация YES. Если это не обрабатывает ключевой эквивалент, это должно или вызвать реализацию суперкласса performKeyEquivalent: или (если Вы знаете, суперкласс не обрабатывает ключевой эквивалент), возврат NO указать, что ключевой эквивалент должен быть передан далее вниз иерархия представления или к меню в строке меню.

Управление интерфейсом клавиатуры

Архитектура отгрузки события Какао обрабатывает определенные ключевые события как команды, чтобы переместить фокус управления в различный объект пользовательского интерфейса в окне, моделировать щелчок мышью по объекту, отклонить модальные окна и сделать выборы в объектах, позволяющих выборы. Эту возможность вызывают управлением интерфейсом клавиатуры. Большинство объектов пользовательского интерфейса, вовлеченных в управление интерфейсом клавиатуры, NSControl объекты, но объекты, которые не являются средствами управления, могут участвовать также. Когда объект имеет фокус управления, Набор Приложения рисует голубое ключевое фокусирующее кольцо вокруг границы объекта. Если полный доступ клавиатуры включен, ключи, перечисленные в Таблице 5-1, имеют установленный эффект.

Табличные 5-1  Ключи, используемые в клавиатуре, соединяют интерфейсом с управлением

Ключ

Эффект

Вкладка

Переместитесь в следующее ключевое представление.

Shift-Tab

Переместитесь в предыдущее ключевое представление.

Пространство

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

Клавиши со стрелками

Переместитесь в составном представлении, такой как NSForm объекты.

Вкладка управления (Вкладка сдвига управления)

Перейдите к следующему (предыдущему) ключевому представлению от представлений, где символы табуляции имеют другое значение (например, NSTextView объекты).

Опция или сдвиг

Расширьте выбор, не влияя на другие выбранные пункты.

Некоторые объекты, найденные на палитрах Interface Builder, не участвуют в управлении интерфейсом клавиатуры, такой как NSImageView, WebView, и PDFView объекты.

В дополнение к ключевому циклу представления окно может иметь ячейку кнопки по умолчанию, использующую Возврат (или Войдите), ключ как его ключевой эквивалент. Программно, можно отправить setDefaultButtonCell: к NSWindow возразите для установки этой ячейки кнопки; можно также установить его в Интерфейсном Разработчике путем устанавливания ключа ячейки кнопки, эквивалентного‘\r’в области Attributes окна Get Info. Ячейка кнопки по умолчанию рисует себя как фокальный элемент для управления интерфейсом клавиатуры, если другая ячейка кнопки не фокусируется на. В этом случае это временно рисует себя как нормальный и отключает его ключевой эквивалент. Клавиша выхода является другим ключом по умолчанию для управления интерфейсом клавиатуры в окне; это сразу прерывает модальный цикл.

Объекты пользовательского интерфейса, соединяющиеся вместе в окне, составляют ключевой цикл представления окна. Ключевой цикл представления является последовательностью NSView объекты соединились друг с другом через их nextKeyView свойство ( previousKeyView свойство при входе в обратное направление). Последнее представление в этой последовательности «циклы» назад к первому представлению. По умолчанию, NSWindow присваивает начального первого респондента и создает ключевой цикл представления с объектами, которые он находит. Если Вы хотите большее управление ключевым циклом представления, необходимо установить его использующий Интерфейсного Разработчика. Посмотрите страницы справки для Интерфейсного Разработчика для подробных данных процедуры.

Для его экземпляров для участия в циклах ключевого представления должно возвратиться пользовательское представление YES от acceptsFirstResponder. Путем выполнения так, это влияет на значение, возвращенное canBecomeKeyView метод. acceptsFirstResponder метод управляет, принимает ли респондент первое состояние респондента, когда его окно спрашивает его к (т.е. когда makeFirstResponder: вызывается с респондентом как параметр). canBecomeKeyView метод управляет, позволяет ли Набор Приложения снабжать вкладками к представлению. Это вызывает acceptsFirstResponder, но это также проверяет на другую информацию прежде, чем определить значение для возврата, такой как, скрыто ли представление и идет ли полный доступ клавиатуры. canBecomeKeyView метод редко переопределяется в то время как acceptsFirstResponder часто переопределяется.

NSView и NSWindow классы определяют много методов для того, чтобы настроить и пересечь ключевой цикл представления программно. Таблица 5-2 перечисляет некоторые более полезные.

Таблица 5-2  Некоторые методы цикла ключевого представления

nextKeyView (NSView)

previousKeyView (NSView)

Возвращает следующие и предыдущие объекты представления в ключевом цикле представления.

setNextKeyView: (NSView)

Устанавливает следующее ключевое представление в цикле.

selectNextKeyView: (NSWindow)

selectPreviousKeyView: (NSWindow)

Ищет иерархию представления кандидата затем (предыдущее) ключевое представление и, если это находит один, делает его первым респондентом.

canBecomeKeyView (NSView)

Возвраты, может ли получатель стать ключевым представлением.

nextValidKeyView (NSView)

previousValidKeyView (NSView)

Возвращает самый близкий объект представления в ключевом цикле представления, следующем за получателем и принимающем первое состояние респондента.

Код в Перечислении 5-5 иллюстрирует, как можно было бы использовать некоторые из этих методов для управления циклом ключевого представления.

Перечисление 5-5  , Управляющее циклом ключевого представления

- (void)textDidEndEditing:(NSNotification *)notification {
    NSTextView *text = [notification object];
    unsigned whyEnd = [[[notification userInfo] objectForKey:@"NSTextMovement"] unsignedIntValue];
    NSTextView *newKeyView = text;
 
    // Unscroll the previous text.
    [text scrollRangeToVisible:NSMakeRange(0, 0)];
 
    if (whyEnd == NSTabTextMovement) {
        newKeyView = (NSTextView *)[text nextKeyView];
    } else if (whyEnd == NSBacktabTextMovement) {
        newKeyView = (NSTextView *)[text previousKeyView];
    }
 
    // Set the new key view and select its whole contents.
    [[text window] makeFirstResponder:newKeyView];
    [newKeyView setSelectedRange:NSMakeRange(0, [[newKeyView textStorage] length])];
}