Touch no Mac: guia de migração, technote de jogos e HIG

O que a Apple publicou para o Touch no Mac depois dos talks? Na noite de 28 de outubro, o artigo do AppKit “Adopting gesture recognizers in your app,” que retornava 404 ao meio-dia, estava no ar com uma tabela de quatro linhas que dá a cada tipo de código de tratamento de mouse um próximo passo; um segundo artigo, “Handling AppKit gestures,” documenta as exclusive views, um timeout de dois segundos para recognizers travados e dois defaults de depuração; uma technote nova, a TN3216, trata de jogos e da ordem dos eventos de mouse emulados; e três páginas das Human Interface Guidelines trazem entradas de change log datadas de 28 de outubro sobre toque no Mac.1234 O bloco “Documentation resources” da página de entrada agora aponta para o artigo e para o exemplo de file promises, o bloco “Design resources” aponta para as três páginas das HIG, e o bloco do beta do Xcode 27.3 ainda diz “Coming soon.”5

TL;DR: O post para desenvolvedores, publicado à 1:47 da tarde no horário do Pacífico em 28 de outubro, partiu de três Tech Talks e de uma technote de junho; o artigo do AppKit de que ele precisava retornava 404 ao meio-dia. Às 9:51 da noite, esse artigo estava no ar com mais dois documentos ao lado. O artigo de migração divide o seu código em quatro linhas: controles padrão e recognizers não precisam de nada; overrides de mouseDown(with:) e tracking loops recebem emulação de um dedo e devem virar recognizers; uma subclasse de controle que sobrescreve um método de mouse volta para um tracking loop; um recognizer próprio que nunca termina segura a sua exclusive view.1 A regra por trás da terceira linha é que o AppKit decide pelo fato de o método estar sobrescrito, “not on what the override does” (não pelo que o override faz), então chamar super não ajuda.1 Um NSPanGestureRecognizer só de toque com buttonMask 0 ao lado de um loop que você mantém agora está documentado, com a consequência exata de deixar a máscara como está: um arrasto do mouse inicia o recognizer e o seu mouseDown(with:) nunca roda.1 As exclusive views vêm ativadas por padrão quando a chave do Info.plist está ausente, e o template macOS App do Xcode grava a chave como NO só para um projeto cujo ciclo de vida de app é o app delegate do AppKit, não para o ciclo de vida padrão do SwiftUI; li isso nos templates do Xcode 27.1 e do beta do 27.2 neste Mac.27 Um recognizer travado é cancelado dois segundos depois que a interação termina, e durante a depuração um user default provoca um crash quando falta um override e outro troca o cancelamento silencioso por um crash.2 A technote de jogos lista os eventos de mouse exatos que um toque e um arrasto produzem, diz aos engines para não somar deltas e explica que cada superfície de toque aparece como um GCMouse emulado adicional até que NSIsTouchNative seja definido.3 As HIG chamam o toque de “a secondary input mode” (um modo de entrada secundário), dizem para deixar “tap targets bigger, not the controls themselves” (os alvos de toque maiores, não os próprios controles) e acrescentam seis regras para controles que só apareciam no hover.4 Ainda ausentes: o beta do Xcode 27.3 e os três controles dos gestos do sistema, que retornam 404 às 9:51 da noite no horário do Pacífico.56

O que chegou, e quando

Cada item abaixo traz o horário em que o verifiquei, porque os próprios carimbos do servidor não batem com o que as páginas mostraram durante o dia; o post ao vivo tem o registro do dia, com uma linha tardia para esta leva.

  • O artigo do AppKit. “Adopting gesture recognizers in your app” retornava 404 no endpoint de documentação da Apple ao meio-dia no horário do Pacífico; às 9:51 da noite estava no ar, servido com um carimbo de modificação de 2:30 da tarde no horário do Pacífico, listado na seção Essentials do AppKit, depois de “Adopting Liquid Glass,” e em “Gesture handling” na página Gestures do framework, e a primeira captura dele no Wayback Machine é das 6:08 da tarde no horário do Pacífico (comprovantes nas fontes).1 A página do Tech Talk “Bring Touch to your Mac app” ainda não aponta para ele.5
  • Um segundo artigo. “Handling AppKit gestures” fica ao lado dele na página Gestures. Ele não tem histórico de revisões, a technote de junho não aponta para ele, o Wayback Machine não tem captura dele, e o carimbo do servidor é 10:35 da noite no horário do Pacífico de 27 de outubro; ele não estava entre as páginas que verifiquei ao meio-dia, então não sei dizer quando foi ao ar.2
  • Uma technote nova. “TN3216: Supporting touch input for games on macOS” tem um histórico de revisões de uma linha, “2026-10-28 First published,” e um carimbo do servidor de 2:09 da tarde no horário do Pacífico.3
  • Três páginas das HIG. “Designing for macOS,” “Gestures” e “Pointing devices” agora terminam com linhas de change log datadas de 28 de outubro de 2026. As cópias que baixei ao meio-dia não tinham nada do texto novo; as cópias baixadas às 9:51 da noite têm. O header de modificação do servidor na nova página “Gestures” marca 5:11 UTC de 27 de outubro, antes da cópia do meio-dia que não tinha o texto; registro os dois fatos e nenhum minuto de publicação.4
  • A página de entrada. Às 11:49 da manhã, os três blocos em “Tools and documentation” diziam “Coming soon,” com os links guardados em comentários HTML. Às 9:51 da noite, o bloco “Documentation resources” (“Learn how to build and optimize your app for touch input.”) aponta para o artigo e para o exemplo de file promises, e o bloco “Design resources” (“Create experiences that take advantage of touch user interface patterns.”) aponta para as três páginas das HIG e para o Apple Design Resources, cuja lista de molduras de produto inclui “MacBook Pro PROLED XDR Display.” O bloco “Xcode 27.3 beta” ainda diz “Coming soon,” e o comentário HTML TK skill continua na página.5
  • O exemplo. A página de “Supporting drag and drop through file promises” agora diz sobre os seus recognizers que “The recognizers work the same way with a pointer or with direct touches on a Mac with a touch display.” (os recognizers funcionam do mesmo jeito com um ponteiro ou com toques diretos em um Mac com tela de toque)6
  • Nada mais se mexeu. O item mais novo do feed de notícias para desenvolvedores ainda é “Say hello to Touch on Mac,” às 10:00:55 da manhã PDT; os itens mais novos do feed de releases são as versões pontuais de 26 de outubro, sem beta do Xcode 27.3 nem do macOS 27.3; a lista de Tech Talks tem os mesmos três talks; a página do ActivityKit traz um carimbo de 8 de outubro e ainda não lista o macOS como plataforma.56

O post da tarde disse que as regras escritas eram os talks e a technote de junho. Este post trata do que as regras escritas acrescentam, e corrige o post da tarde onde a verificação da noite encontrou informações diferentes; a lista está no fim.

A tabela que faz a triagem do seu código

A seção “Prepare your app for a Mac with a touch display” do artigo é uma tabela com três colunas, tratamento de entrada, comportamento com toque e próximo passo, e quatro linhas. A coluna de comportamento da Apple vai citada; as outras duas colunas vão condensadas, exceto o próximo passo da terceira linha, que está nas palavras da Apple:1

Seu código “Behavior with touch” da Apple Próximo passo
Controles padrão do AppKit e gesture recognizers “Works with touch, with no changes needed.” Testar.
Overrides de mouseDown(with:) e tracking loops “AppKit emulates a single-finger tap or drag, but supports multi-finger gestures and individual touches only through gesture recognizers.” Substituí-los por recognizers.
Subclasses de NSButton, NSSlider e outras views do AppKit que sobrescrevem métodos de tratamento de mouse “AppKit falls back to a tracking loop.” “Replace the overrides with target-action pairs for tracking events.”
Subclasses próprias de NSGestureRecognizer “A recognizer that never reaches a terminal state keeps its exclusive view, which can make your app appear unresponsive.” Tratar o cancelamento e chegar a um estado terminal.

O teste que vem depois da tabela tem quatro linhas, e vale rodá-lo como está escrito: “Controls respond to a tap, and buttons highlight and activate as expected,” “Dragging a view, selecting text, and scrolling work with one finger,” “Pinch and rotate work where your app supports them,” e “Small targets, such as resize grips and grab handles, are easy to hit with a finger.” (os controles respondem a um toque e os botões se destacam e ativam como esperado; arrastar uma view, selecionar texto e rolar funcionam com um dedo; pinça e rotação funcionam onde o app os suporta; alvos pequenos, como alças de redimensionamento e de arraste, são fáceis de acertar com o dedo)1 A lista de busca amplia a auditoria de overrides de mouseDown(with:) do talk para cinco símbolos: “search your project for nextEvent(matching:until:inMode:dequeue:) and trackEvents(matching:timeout:mode:handler:), because tracking loops typically call these methods. Also search for mouseDown(with:) and mouseDragged(with:) overrides, and for uses of currentEvent in control action methods.”1 A última verificação é aquela de que trata a quarta linha: “confirm that your app stays responsive after a touch interaction ends, and that every gesture recognizer action method handles the NSGestureRecognizer.State.cancelled state.” (confirme que o app continua respondendo depois que uma interação de toque termina, e que todo método de ação de gesture recognizer trata o estado cancelled)1

Duas frases da Overview resolvem uma questão que o talk deixava para a inferência. A emulação é de um dedo: “AppKit emulates mouse events from a single finger tapping or dragging,” e “Relying on this emulation, however, means you miss out on multi-finger gestures, like pinch and rotate, that gesture recognizers handle.” (depender dessa emulação, porém, significa perder os gestos de vários dedos, como pinça e rotação, que os gesture recognizers tratam)1 E a bancada de testes é a que o talk citou, agora em uma dica: “Use Sidecar to test touch input without a Mac that has a touch display,” porque “AppKit then routes touch on its screen the same way it does on a Mac with a touch display.”1

A regra do override

A terceira linha da tabela tem por trás uma regra que nem o talk nem a technote de junho enunciaram com essa clareza. Se você cria uma subclasse de NSButton e sobrescreve mouseDown(with:) para acrescentar uma animação de destaque, “AppKit treats your override as a replacement for its own click handling, rather than as a side effect” (o AppKit trata o seu override como substituto do próprio tratamento de clique, e não como um efeito colateral), e o botão volta para um tracking loop.1 Depois: “AppKit decides based on whether your subclass overrides the method, not on what the override does,” então o fallback vale mesmo quando o override chama super.mouseDown(with:), e “Overriding mouseDragged(with:) or mouseUp(with:) has the same effect.”1

A substituição é o padrão de control events do talk, e a listagem do artigo difere da do talk em um detalhe que vale copiar. A listagem do talk em 2:24 registrava uma ação para [.trackingExited, .trackingEndedInside] e outra separada para .trackingCancelled; o conjunto de ocultação do artigo é [.trackingExited, .trackingEndedInside, .trackingEndedOutside, .trackingCancelled], que acrescenta um pressionamento que termina fora do botão.19 trackingEndedOutside não é novo: a documentação da Apple o lista como disponível desde o macOS 11.0, e o SDK do macOS 27.0 o declara como NSControlEventTrackingEndedOutside = 1 << 7 no NSControl.h (análise do autor).67 O artigo também observa que os métodos de ação precisam ser expostos ao Objective-C com @objc, e que, se você só precisa da ativação, primaryActionTriggered dispara “regardless of whether someone used a mouse, trackpad, or touch to produce it.” (não importa se a pessoa usou mouse, trackpad ou toque)1

As views contêineres têm a mesma armadilha: “If you start a drag from mouseDragged(with:) in an NSTableView, NSCollectionView, NSOutlineView, or NSBrowser, AppKit falls back to a tracking loop for the interaction,” e a saída são os métodos de arrastar do data source e do delegate, tableView(_:pasteboardWriterForRow:) no caso de uma tabela.1

Para os dois overrides de mouseDown(with:) mais comuns, o artigo dá pares de antes e depois. “Most mouseDown(with:) overrides do one of two things: mark an item as selected when someone clicks it, or show a menu when someone Control-clicks.” (a maioria dos overrides marca um item como selecionado no clique ou mostra um menu no Control-clique)1 Para a seleção, observe isSelected no item da collection view ou na row view da tabela, com a ressalva de que o observador “also runs when your code changes the selection programmatically”; para o menu, sobrescreva menu(for:) e deixe o AppKit apresentá-lo, ou defina menu ou defaultMenu quando o menu não depende do clique.1

Um recognizer só de toque ao lado de um loop que você mantém

O talk recomendava um pan recognizer só de toque ao lado de um tracking loop existente como o caminho para uma versão pontual. O artigo documenta a mesma receita em “Add touch support to your custom tracking loop,” com as funções compartilhadas de início, continuação, fim e cancelamento, e depois diz o que cada propriedade faz com uma precisão para a qual o talk não tinha espaço:1

let touchRecognizer = NSPanGestureRecognizer(target: self, action: #selector(handleTouchPan))
touchRecognizer.buttonMask = 0
touchRecognizer.allowedTouchTypes = .direct
addGestureRecognizer(touchRecognizer)

“setting buttonMask to 0 means the gesture recognizer only recognizes touches, not mouse or trackpad input, so your tracking loop keeps handling the mouse and trackpad exactly as before.” (definir buttonMask como 0 faz o recognizer reconhecer só toques, não entrada de mouse ou trackpad, e o tracking loop continua tratando mouse e trackpad exatamente como antes)1 Deixe a máscara no valor padrão e o recognizer “also responds to the primary mouse button. A mouse drag then begins the gesture recognizer, and AppKit doesn’t call your mouseDown(with:) override, so the tracking loop doesn’t run. A click that doesn’t move still reaches your tracking loop.” (também responde ao botão principal do mouse; um arrasto do mouse inicia o recognizer, o AppKit não chama o seu override de mouseDown(with:) e o tracking loop não roda; um clique sem movimento ainda chega ao loop)1 Ou seja, a máscara não é um detalhe; sem ela, o loop para de receber arrastos em silêncio. A linha de allowedTouchTypes é cinto e suspensório: “Direct touches are already the default for allowedTouchTypes, and setting it to .direct states that intent explicitly.”1 A avaliação da própria Apple sobre a abordagem: “This is often the fastest, lowest-risk way to add touch support to code with a tracking loop you’d rather not rewrite all at once.” (muitas vezes é o jeito mais rápido e de menor risco de acrescentar suporte a toque a um código com um tracking loop que você prefere não reescrever de uma vez)1

Se você substituir o loop, o exemplo de pan do artigo devolve a legenda à origem inicial em .cancelled, e um loop que iniciava uma sessão de arrasto passa o recognizer para beginDraggingSession(items:gesture:source:) em vez do evento.1

Filtrando com os dois métodos de delegate

A seção mais nova em relação aos talks é “Filter gesture recognizer candidates.” Os recognizers são reunidos por hit-testing, não pela responder chain: “Gesture recognizers don’t use the responder chain.”1 Quando o AppKit os reúne, “not every recognizer it finds is actually applicable to the interaction” (nem todo recognizer encontrado se aplica de fato à interação), e o app remove os que não se aplicam por meio de dois métodos de delegate: gestureRecognizer(_:shouldAttemptToRecognizeWith:) “to inspect the initiating NSEvent for pointer-based input,” e gestureRecognizer(_:shouldReceive:) “to inspect each new NSTouch for touch input.”1 O objetivo dos dois: “Either method gives you the initial input, something the recognizer doesn’t otherwise expose, and lets you stop the recognizer from handling that event stream or touch.” (qualquer um dos métodos entrega a entrada inicial, que o recognizer não expõe de outra forma, e permite impedir que ele trate aquele fluxo de eventos ou toque)1 E a divisão é estrita: “Direct touches don’t call this method. To filter them, implement gestureRecognizer(_:shouldReceive:) instead, as shown above.”1 Filtrar só pelo método de eventos deixa os toques diretos sem filtro por esse delegate.

Os dois exemplos são padrões que espero ver copiados. Uma alça de redimensionamento: anexe o recognizer de redimensionamento à view inteira e, nos dois métodos de delegate, retorne se a posição está dentro do frame da alça, retornando true “only to give the gesture recognizer a chance to attempt recognition, not to guarantee it succeeds.” (só para dar ao recognizer a chance de tentar o reconhecimento, não para garantir que ele tenha sucesso)1 Uma linha do tempo de clipes: um único recognizer na linha do tempo e, no método de eventos, um hit-test do clipe, que fica guardado para o método de ação, retornando false quando não há clipe.1 O aviso que acompanha, para alvos pequenos: “If a custom control expects a touch to land inside its visible area, update it to handle touches that land outside that area.”1

A prioridade entre os que sobram é um requisito de falha, e o artigo repete o aviso do segundo artigo, “Use this sparingly, because the waiting recognizer responds more slowly” (use com moderação, porque o recognizer que espera responde mais devagar), e dá o exemplo de que “making a single click wait for a double click to fail makes clicks feel sluggish.”1

currentEvent, hover e deslizes

“Handle touch input” reafirma, em forma de documentação, a frase do talk que organiza tudo: o AppKit “doesn’t deliver direct touches (NSTouch) through the responder chain or through event monitors,” e “Gesture recognizers are the only way to respond to multi-finger gestures or to receive individual touches from a Mac with a touch display or a Sidecar-connected iPad.” (os gesture recognizers são a única forma de responder a gestos de vários dedos ou de receber toques individuais de um Mac com tela de toque ou de um iPad conectado pelo Sidecar)1 A página de visão geral de entrada do AppKit diz o mesmo pelo lado do responder: “The responder chain receives touch events only from indirect touches on a trackpad, if a view asks for them. It doesn’t receive touch events from direct touches on a Mac with a touch display.”6

O conselho sobre verificações de capacidade é evitá-las: “In most cases, instead of checking whether a device supports touch, write your event-handling code to work the same way regardless of input source, and decide on alternate presentations based on the interaction type.” (na maioria dos casos, em vez de verificar se o dispositivo suporta toque, escreva o tratamento de eventos para funcionar igual com qualquer fonte de entrada e decida apresentações alternativas pelo tipo de interação)1 O único exemplo dado para touchCapabilities é “capturing a signature on a touch display.” (capturar uma assinatura em uma tela de toque)1

currentEvent ganha uma seção própria. Como as interações com controles passam por recognizers, “currentEvent no longer reliably returns the event that initiated an action” (currentEvent já não retorna de forma confiável o evento que iniciou uma ação), e o par de antes e depois troca os modifier flags do evento pelo NSEvent.modifierFlags de classe, com a ressalva de que “These report the state at the time you query them, not at the time of the original event. A touch doesn’t register in pressedMouseButtons.”1 O que não muda: “Keyboard events and scroll-wheel events behave the same on every input source: AppKit delivers them through the responder chain. Hover tracking, which relies on mouseMoved(with:) and NSTrackingArea, applies to pointer input only, because a touch display has no hover.” (eventos de teclado e de roda de rolagem se comportam igual em qualquer fonte de entrada: o AppKit os entrega pela responder chain. O rastreamento de hover, que depende de mouseMoved(with:) e NSTrackingArea, vale só para entrada de ponteiro, porque uma tela de toque não tem hover)1

Os deslizes não são traduzidos: “AppKit doesn’t translate touch swipes for you.”1 Se você usa trackSwipeEvent(options:dampenAmountThresholdMin:max:usingHandler:), implemente o seu próprio e, para a navegação de voltar e avançar, verifique NSEvent.isTouchSwipeNavigationEnabled antes, “because the person can turn off swipe navigation in System Settings.” (porque a pessoa pode desativar a navegação por deslize nos Ajustes do Sistema)1 Essa propriedade é nova: a documentação da Apple a lista como disponível desde o macOS 27.0, e o NSEvent.h no SDK do macOS 27.0 a declara na linha 496 como API_AVAILABLE(macos(27)) (análise do autor).67

Recognizers próprios: o contrato, o timeout e dois defaults

As diretrizes do artigo para uma subclasse própria de NSGestureRecognizer são um contrato em sete itens: trate o cancelamento em mouseCancelled(with:) e touchesCancelled(with:); nos métodos de evento, apenas atualize o estado privado de tracking e defina state; responda no método de ação, não no callback do evento; guarde o NSEvent ou o NSTouch de origem para o método de ação; “Override reset() to clear your cached state, so it doesn’t leak from one gesture into the next” (sobrescreva reset() para limpar o estado guardado, para que ele não vaze de um gesto para o seguinte); “Always end an active gesture recognizer by transitioning to NSGestureRecognizer.State.ended, NSGestureRecognizer.State.failed, or NSGestureRecognizer.State.cancelled. Otherwise, other recognizers can’t activate” (sempre encerre um recognizer ativo passando para ended, failed ou cancelled, ou os outros recognizers não conseguem ativar); e sobrescreva location(in:), porque “If you skip this override and build your app with the macOS 27 SDK and later, AppKit returns NSZeroPoint and logs a console error.” (se você pular esse override e compilar com o SDK do macOS 27 ou posterior, o AppKit retorna NSZeroPoint e registra um erro no console)1 O exemplo DragTrackingRecognizer que vem em seguida é um esqueleto: os corpos dos overrides de mouse down, dragged e up são comentários que mandam chamar um único método privado track(_:event:state:), o do override de cancelamento manda definir .cancelled, e o método de ação lê de volta a posição e o evento guardados.1

O segundo artigo é onde as consequências de quebrar o contrato ganham números. “A gesture recognizer is stuck if it hasn’t reached a terminal state within 2 seconds after the person stops interacting with your app, such as when they release the mouse button or lift their fingers.” (um gesture recognizer está travado se não chegou a um estado terminal até 2 segundos depois que a pessoa para de interagir com o app, por exemplo ao soltar o botão do mouse ou levantar os dedos)2 Com exclusive views, “A stuck gesture recognizer keeps holding its exclusive view” (um recognizer travado continua segurando a sua exclusive view), o que bloqueia a coleta fora da sua hierarquia, e o remédio do sistema é automático: “To keep a single stuck gesture recognizer from blocking your app indefinitely, the system automatically transitions it to the NSGestureRecognizer.State.cancelled state, allowing gesture gathering to resume normally.” (para que um único recognizer travado não bloqueie o app indefinidamente, o sistema o passa automaticamente para o estado cancelled, e a coleta de gestos volta ao normal)2 Esse é o mecanismo por trás da quarta linha da tabela, e significa que um recognizer quebrado em um app publicado bloqueia a coleta de gestos fora da sua hierarquia exclusiva, com o resto do app parecendo travado, até o cancelamento automático dois segundos depois que a pessoa para de interagir, e o target da ação continua responsável por tratar o cancelamento.

Dois user defaults fazem esses problemas virarem um crash com stack trace enquanto você desenvolve, um para um override ausente e outro no lugar do cancelamento silencioso. “Set the NSGestureRecognizerCrashOnMissingOverrides key in UserDefaults to YES,” ou passe -NSGestureRecognizerCrashOnMissingOverrides YES como argumento de inicialização, para ter um crash quando faltar um método de evento que você deveria ter sobrescrito; e defina NSCrashOnStuckGestureTimeout “to a small number of seconds, such as 2,” ou passe -NSCrashOnStuckGestureTimeout 2, para ter um crash em vez do cancelamento de um recognizer travado.2 O primeiro não pega tudo: ele “doesn’t detect a gesture recognizer that correctly transitions to NSGestureRecognizer.State.cancelled and sends its action, if the action’s target doesn’t handle the canceled state.” (não detecta um recognizer que passa corretamente para cancelled e envia a sua ação, se o target da ação não trata o estado cancelado)2 O aviso seguinte é do tipo que merece entrar em um checklist: “Comment out or remove NSGestureRecognizerCrashOnMissingOverrides and NSCrashOnStuckGestureTimeout before shipping your app,” e “Changes to these user defaults or launch arguments take effect only after you rebuild or relaunch your app.” (comente ou remova os dois antes de publicar o app; mudanças nesses defaults ou argumentos só valem depois de recompilar ou reabrir o app)2 Nenhum dos dois defaults aparece nos talks nem na technote de junho.

O mesmo artigo explica a diferença entre os dois estados terminais que não são sucesso: .failed é para um recognizer que nunca casou, e “If a gesture recognizer sets this after it already delivered an action, the system automatically converts it to NSGestureRecognizer.State.cancelled instead.” (se um recognizer define esse estado depois de já ter entregado uma ação, o sistema o converte automaticamente em cancelled)2 Ele também nomeia uma causa de cancelamento pelo sistema além do exemplo do Exposé no talk: “when the same touches begin a system-level gesture like smartMagnify(with:), the system takes over those touches for its own use.” (quando os mesmos toques iniciam um gesto do sistema como smartMagnify(with:), o sistema assume esses toques para uso próprio)2

Três fatos menores da mesma página. Os recognizers podem atrasar eventos do responder: “If you set delaysPrimaryMouseButtonEvents to true, the system stores the relevant events until the gesture recognizer fails, then delivers them to the appropriate responders. If the gesture recognizer reaches the NSGestureRecognizer.State.ended state, the system never delivers the events.” (com delaysPrimaryMouseButtonEvents em true, o sistema guarda os eventos relevantes até o recognizer falhar e então os entrega aos responders apropriados; se o recognizer chega a ended, os eventos nunca são entregues)2 E os métodos de toque do próprio responder são só de trackpad: “These methods don’t have an equivalent delay mechanism, and they apply only to indirect touches from a trackpad.”2 Um view controller não pode ter um recognizer: “You can’t attach a gesture recognizer to a view controller directly,” então acrescente-o à view do controller, com o controller como target e delegate.2

Exclusive views: ativadas por padrão, desativadas nos templates AppKit do Xcode

O post da tarde explicou a exclusividade a partir do talk e da technote de junho. Os dois artigos acrescentam o padrão, o mecanismo e um fato sobre o Xcode.

O mecanismo, novo no macOS 27: “In macOS 27 and later, the initial hit-tested view for a mouse click or touch event becomes an exclusive view for gathering gesture recognizers,” e “This behavior simulates the presence of a single mouse pointer, even when a person touches a Mac with a touch display with several fingers at once.” (no macOS 27 e posteriores, a primeira view atingida pelo hit-test em um clique ou toque vira uma exclusive view para a coleta de gesture recognizers, o que simula a presença de um único ponteiro de mouse mesmo quando a pessoa toca a tela com vários dedos ao mesmo tempo)2 O padrão: “Exclusive views are on by default,” e “If your app’s information property list doesn’t include the NSViewGestureRecognizerIsExclusive key, the system treats it as YES.” (se o Info.plist do app não inclui a chave, o sistema a trata como YES)2 A página da própria chave concorda, “The default value is YES,” e descreve a saída de forma restrita: “Set this key to NO to allow gesture recognizers in multiple views to activate simultaneously. Do this only if your app intentionally needs concurrent gesture recognition across different views.” (defina a chave como NO para permitir que recognizers em várias views ativem ao mesmo tempo, e só faça isso se o app precisa intencionalmente de reconhecimento simultâneo em views diferentes)6 O exemplo do sistema de saída por view é o Color Panel: “AppKit uses this same technique in the standard Color Panel,” onde vários sliders se movem ao mesmo tempo.2

O fato sobre o Xcode, dito nos dois artigos: “Xcode adds the NSViewGestureRecognizerIsExclusive key with a value of NO to new macOS app projects, so those apps don’t use exclusive views unless you change the value to YES.” (o Xcode acrescenta a chave com o valor NO a novos projetos de app de macOS, e esses apps não usam exclusive views a menos que você mude o valor para YES)1 Li os templates de projeto neste Mac para ver quais projetos isso cobre (análise do autor). No Xcode 27.1 (27A9275) e no beta do Xcode 27.2 (27B5019j), o template macOS App herda de uma unidade “Cocoa App Base” cuja opção de ciclo de vida de app tem dois valores, SwiftUI e Cocoa, com SwiftUI como padrão; a chave INFOPLIST_KEY_NSViewGestureRecognizerIsExclusive com o valor NO fica só dentro da unidade Cocoa, então o Xcode a grava, como um build setting que vai parar no Info.plist gerado, quando o projeto usa o ciclo de vida do app delegate do AppKit e não quando usa o ciclo de vida do SwiftUI.7 A opção de ciclo de vida não tem nome de exibição nos templates; a opção que tem é Interface: (SwiftUI, Storyboard ou XIB, com SwiftUI como padrão), e as unidades Storyboard e XIB exigem o ciclo de vida do AppKit, então um projeto Storyboard ou XIB recebe a chave, e um projeto com interface SwiftUI só a recebe quando o seu ciclo de vida é o app delegate do AppKit.7 O template Document App descende da mesma base, então, nas mesmas condições, ele herda esse build setting e também grava a chave como uma entrada do Info.plist com o valor false; o template macOS Game força o ciclo de vida Cocoa, então um jogo de macOS novo começa sem exclusividade.7 Não há neste Mac nenhum Xcode anterior ao 27.1, então não sei dizer quando os templates ganharam a chave. A leitura prática: um projeto AppKit criado a partir desses templates começa sem exclusividade; um projeto SwiftUI, e qualquer app existente cujo Info.plist não tem a chave, é exclusivo. A nota de migração do segundo artigo decorre disso: se o seu app definiu a chave como NO, “also set the view’s exclusiveGestureBehavior to NSView.ExclusiveGestureBehavior.exclusive” quando você substituir um tracking loop, porque “This prevents simultaneous gesture recognition with unrelated views, which the loop previously prevented implicitly.” (isso impede o reconhecimento simultâneo com views não relacionadas, que o loop antes impedia implicitamente)2

O primeiro artigo desembaraça as três configurações que mexem com exclusividade e rolagem, com a frase “These settings don’t override each other.” (essas configurações não se sobrepõem umas às outras)1 exclusiveGestureBehavior e a chave do plist decidem quais recognizers o AppKit reúne, e “The view’s setting applies to that view and its subviews, and takes precedence over the app-wide key.” (a configuração da view vale para ela e as suas subviews e tem precedência sobre a chave do app inteiro)1 isCancellableByScrollGesture é por recognizer e independente: “It lets a scroll gesture cancel that gesture recognizer even if it has already begun.”1 scrollGestureForRelationships serve para recognizers que competem com os da própria scroll view.1 O cenário a que o artigo manda prestar atenção é um botão dentro de uma scroll view: defina isCancellableByScrollGesture como true no recognizer dele para que um arrasto que começa no botão role em vez de clicar.1

Os engines de texto ganham mais uma ferramenta. NSTextSelectionManager “creates its gesture recognizers itself, so you don’t have a reference to them” (cria os próprios gesture recognizers, então você não tem referência a eles), então um recognizer próprio que precisa esperar por eles retorna true de gestureRecognizer(_:shouldRequireFailureOf:) quando o gesturesForFailureRequirements do manager contém o outro recognizer.1 Essa propriedade está listada como disponível desde o macOS 27.0 e declarada no NSTextSelectionManager.h, na linha 59 do SDK do macOS 27.0 (análise do autor).67

A emulação, em cinco itens

O post da tarde citou as quatro regras de emulação da technote de junho para frameworks de UI que não são o AppKit. A lista do artigo tem cinco, e a nova é o arrasto.18

  • “Tapping emulates a mouse-down followed immediately by a mouse-up.” (um toque emula um mouse-down seguido imediatamente de um mouse-up)
  • “Touching and then immediately panning emulates a trackpad scroll, even if the UI doesn’t otherwise handle Multi-Touch input directly.” (tocar e mover em seguida emula uma rolagem de trackpad, mesmo que a UI não trate diretamente entrada Multi-Touch)
  • “Touching, briefly holding, and then moving emulates mouseDown(with:), followed by mouseDragged(with:) as it moves, and mouseUp(with:) on lift.” (tocar, segurar por um instante e depois mover emula mouseDown(with:), seguido de mouseDragged(with:) durante o movimento e de mouseUp(with:) ao levantar o dedo)
  • “Touching and holding without movement emulates rightMouseDown(with:), and rightMouseUp(with:) on lift.” (tocar e segurar sem mover emula rightMouseDown(with:), e rightMouseUp(with:) ao levantar o dedo)
  • “Pinching or rotating with two fingers emulates the trackpad magnify and rotate gestures.” (pinça ou rotação com dois dedos emulam os gestos de ampliar e girar do trackpad)

O terceiro item é a forma escrita do “drag with a small hold delay” (arrastar com um pequeno atraso de espera) do talk (11:31): um toque que se move de imediato rola, um toque que segura antes arrasta.9 A lista de junho tinha um toque, um pan imediato, um toque longo e uma pinça ou rotação de dois dedos, e nenhum item de arrasto.8 O limite é de dois dedos: “This emulation covers interactions with one or two fingers. If another finger touches down during a pinch or rotation, the emulation ignores it and keeps tracking the original two fingers.” (a emulação cobre interações com um ou dois dedos; se outro dedo toca durante uma pinça ou rotação, ela o ignora e continua acompanhando os dois originais)1 Três ou mais dedos exigem recognizers, e NSIsTouchNative definido como YES desliga a emulação extra quando o framework passa a tratar o toque por conta própria.1

Jogos: a TN3216

A technote é para jogos: “This guidance focuses on configurations common in games, such as an app with a single view backed by a CAMetalLayer.”3 O enquadramento de design dela é mais rígido que o das HIG: “Touch extends the Mac experience rather than replacing other input,” e “Touch works best for brief interactions that complement these devices,” com a instrução de “Design touch interactions for brief moments that the player can complete with one hand, while the other hand stays on the keyboard, mouse, or controller” (o toque amplia a experiência do Mac em vez de substituir as outras entradas, funciona melhor em interações breves, e deve ser pensado para momentos que o jogador conclui com uma mão enquanto a outra fica no teclado, no mouse ou no controle), para interações “such as inventory management, map zoom and scroll, or the settings menu.”3

A história de compatibilidade é a mesma emulação, com uma particularidade para jogos. “AppKit applies game-specific emulation to apps in a games category, and can apply emulation to an individual view, such as one that hosts a third-party UI framework.” (o AppKit aplica uma emulação específica de jogos a apps da categoria de jogos, e pode aplicar emulação a uma view individual, como uma que hospeda um framework de UI de terceiros)3 A categoria é lida do Info.plist: se LSApplicationCategoryType é public.app-category.games ou uma subcategoria de jogos, “the system applies game-specific mouse emulation.”3 O problema que ela resolve é um que o mouse nunca tem: “A mouse moves continuously from one position to the next, but a player can tap or start a drag at two distant locations in succession” (um mouse se move continuamente de uma posição para a seguinte, mas o jogador pode tocar ou começar um arrasto em dois pontos distantes em sequência), então um jogo que soma deltas sai do lugar, e “For games, AppKit sends a mouseMoved event to the new location before each mouseDown(with:), so your game can refresh its cached mouse position.” (para jogos, o AppKit envia um evento mouseMoved para a nova posição antes de cada mouseDown(with:), para que o jogo atualize a posição do mouse que guardou)3

A technote então lista os eventos emulados em ordem. Para um toque: mouseMoved(with:) “from the last mouse position to the tap location,” depois mouseDown(with:), depois mouseUp(with:). Para um arrasto: mouseMoved(with:) até onde o arrasto começa, mouseDown(with:), mouseDragged(with:) “repeatedly while the touch continues,” e mouseUp(with:).3 Depois, uma regra em um quadro “Important”: “Don’t intercept events by overriding sendEvent(:) or pulling them with nextEvent(matching:until:inMode:dequeue:). Doing so can interfere with gesture recognizers that respond to a physical mouse.” (não intercepte eventos sobrescrevendo sendEvent(:) nem os puxe com nextEvent(matching:until:inMode:dequeue:); isso pode interferir com recognizers que respondem a um mouse físico)3

A parte sem equivalente nos talks é o GCMouse. “By default, the system presents each touch surface, whether a Mac with a touch display or a Sidecar-connected iPad, as an additional GCMouse that emulates mouse input from touches” (por padrão, o sistema apresenta cada superfície de toque, seja um Mac com tela de toque ou um iPad conectado pelo Sidecar, como um GCMouse adicional que emula entrada de mouse a partir dos toques): um dedo encostando pressiona o botão esquerdo, o movimento chama o handler de mouse movido com um delta, e levantar o dedo solta o botão.3 Os limites: “The emulated GCMouse ignores additional fingers, and it doesn’t emulate other buttons, scrolling, or pinch input,” e, como os toques caem em pontos desconectados, “Don’t use them to track an absolute pointer position.” (não os use para acompanhar uma posição absoluta do ponteiro)3

NSIsTouchNative faz mais por um jogo do que por um app AppKit. Definido como YES, “AppKit’s emulation will stick to a generic emulation - ignoring the app’s category or whether it uses a third-party UI framework - and disable GCMouse emulation” (a emulação do AppKit se limita a uma emulação genérica, ignorando a categoria do app e o uso de um framework de UI de terceiros, e desliga a emulação de GCMouse), então a superfície de toque deixa de aparecer como um GCMouse e “Your game receives touch through gesture recognizers instead of emulated mouse events.”3 Sobra um resíduo: “AppKit still emulates mouse events for any NSView that handles them, for example by overriding mouseDown:.”3 A página da própria chave diz que a maioria dos apps AppKit não precisa dela e que ela é “primarily intended for apps that embed a non-AppKit rendering or input framework and implement their own touch-handling pipeline” (pensada principalmente para apps que embutem um framework de renderização ou de entrada que não é o AppKit e implementam o próprio pipeline de toque); um engine de jogo é esse caso.6

A seção de implementação é um padrão de delegate em Swift e em Objective-C: um pan recognizer e um tap recognizer com buttonMask 0, para que ignorem um mouse físico, um recognizer de magnificação, shouldRecognizeSimultaneouslyWith retornando true só para o par pan e pinça, e shouldRequireFailureOf fazendo o toque esperar pelos dois.3 Uma nota confirma o padrão que o primeiro artigo descreve: “The gesture recognizers must include direct in allowedTouchTypes. On macOS 27 and later, this is the default.”3 O conselho de roteamento tem forma de engine: “Install the gesture recognizers once in your app and leave them enabled,” converta os callbacks em eventos de entrada do engine, e “Let the active input handler decide if and how to react to different gestures” (instale os recognizers uma vez e deixe-os ativos, e deixe o handler de entrada ativo decidir se e como reagir a cada gesto), com um handler de pan que converte pontos em pixels com o fator de escala do backing e inverte o eixo y para um engine cuja origem fica no canto superior esquerdo.3 Os controles padrão continuam funcionando depois da troca, “as long as you don’t attach your own direct-touch gesture recognizers to them.” (desde que você não anexe a eles os seus próprios recognizers de toque direto)3

O checklist final tem duas metades. Para um jogo na emulação: leia a posição de cada evento, e não sobrescreva sendEvent: nem puxe eventos de nextEventMatchingMask:. Para um jogo que trata o toque: defina NSIsTouchNative, use recognizers de toque direto com buttonMask 0, acrescente toque onde os jogadores o esperam e mantenha-o para uma só mão, “Continue to read GCMouse for the physical mouse. With NSIsTouchNative set, touch no longer appears as an emulated GCMouse” (continue lendo o GCMouse para o mouse físico; com NSIsTouchNative definido, o toque deixa de aparecer como um GCMouse emulado), e use controles padrão sempre que possível.3

As HIG, datadas de 28 de outubro

O post da tarde disse que as quatro páginas das HIG que a página de entrada planejava linkar não tinham orientação sobre toque na tela do Mac. Três delas agora têm, cada uma com uma linha de change log datada de 28 de outubro de 2026; a página de Live Activities não mudou.4

Designing for macOS (“Added guidance for touch input.”) reescreve três linhas da sua descrição da plataforma e acrescenta uma boa prática. Ergonomia: “On a Mac with a touch display, people reach forward to touch the screen, so they tend to use touch for brief, intentional interactions rather than sustained work.” (em um Mac com tela de toque, as pessoas esticam o braço para tocar a tela, então tendem a usar o toque para interações breves e intencionais, não para trabalho contínuo) As entradas agora começam pelos teclados e dispositivos apontadores e incluem “Gestures on a trackpad or a Mac with a touch display” entre as demais. A nova boa prática é o talk de design inteiro em uma frase: “Support standard gestures on trackpads and Mac devices with a touch display. Use larger tap targets and controls that expand on touch to make touch interaction easier, while keeping control size and density the same to stay optimized for keyboard and pointing device input.” (suporte os gestos padrão no trackpad e na tela de toque; use alvos de toque maiores e controles que se expandem ao toque para facilitar a interação por toque, mantendo o tamanho e a densidade dos controles para continuar otimizado para teclado e dispositivo apontador)4

Gestures (“Added guidance for gestures and touch input in macOS.”) amplia a sua seção de macOS, que agora aponta para os dois artigos do AppKit como orientação para desenvolvedores. A primeira frase define a hierarquia: “On a Mac with a touch display, or on an iPad connected with Sidecar, people can also interact directly using touch gestures as a secondary input mode.” (em um Mac com tela de toque, ou em um iPad conectado pelo Sidecar, as pessoas também podem interagir diretamente com gestos de toque, como um modo de entrada secundário)4 Depois, seis regras, cada uma com um título em negrito:

  • “Keep the layout and size of interface elements the same when you support touch.” (mantenha o layout e o tamanho dos elementos da interface ao suportar toque) O motivo: “In macOS, touch is secondary to keyboard and pointing device input,” e as pessoas alternam entre as entradas com frequência. O contraste com o iPhone Duo, em que a tela interna muda as size classes, é justamente o ponto: no Mac muda a entrada, e o layout não muda.
  • “Make tap targets bigger, not the controls themselves,” por meio de “enlarging their tap targets to anticipate that interaction may start slightly outside of their visual bounds” (ampliando os alvos de toque para prever que a interação comece um pouco fora dos limites visuais), e “Where possible, use standard framework controls, which the system configures with an optimal tap target size automatically.”
  • “Consider providing expandable controls,” uma variante temporária no tamanho adequado ao toque que aparece com um toque, fica enquanto o dedo segura e permanece “for a short time after they lift their finger to keep the control accessible to touch” (por um curto tempo depois que a pessoa levanta o dedo, para manter o controle acessível ao toque); “When using standard system controls, steppers, sliders, and dials gain this behavior automatically.”
  • “Don’t use touch as the only way to access controls or features,” e o inverso: “aim to provide touch equivalents for actions otherwise performed exclusively with a pointing device, like using a keyboard modifier to shift-drag or displaying a menu when the pointer moves over an element.” (procure oferecer equivalentes de toque para ações que de outro modo só se fazem com um dispositivo apontador, como usar um modificador do teclado para arrastar com Shift ou mostrar um menu quando o ponteiro passa sobre um elemento)
  • “Where possible, align with gestures people already know,” do seu app de iPhone ou de iPad ou do trackpad, e “Test to ensure they don’t conflict with macOS system gestures.”
  • “Make sure custom gestures work for both touch and trackpad,” usando “modifier keys where needed to help the gesture work for all touch inputs.”4

A página não dá o número de 36 pontos; esse número está nos dois talks (“Touch on macOS uses a touch target of 36 points,” 9:17 no talk de design, e a ampliação do hit rect do talk de AppKit para “a minimum of 36 points on each axis,” 5:53).9 Ela acrescenta uma tabela, “macOS trackpad and touch display gestures,” que associa cada ação às suas formas no trackpad e no toque: selecionar é um clique principal ou um toque; abrir é um clique duplo ou um toque duplo; rolar é com dois dedos no trackpad e com um na tela; ampliar e girar são a mesma pinça e o mesmo giro de dois dedos nos dois; um menu de contexto é um clique secundário ou um toque longo; um arrasto é clicar e arrastar, ou “Touch and hold, then drag.”4 Na tabela multiplataforma, “Touch (or pinch) and hold” agora inclui o macOS, e a linha do toque duplo acrescenta “open an item on a Mac with a touch display.”4

Pointing devices (“Added guidance for revealing hidden controls with touch on Mac, and updated guidance and artwork for iPadOS and macOS.”) é a página com as regras mais concretas, sob um título novo, “Touch support for hidden controls.” A premissa: “Some Mac apps reveal certain controls only when the pointer moves over them. These controls need another way to appear when someone uses touch on a Mac that supports it.” (alguns apps de Mac só revelam certos controles quando o ponteiro passa sobre eles, e esses controles precisam de outra forma de aparecer quando alguém usa o toque em um Mac compatível)4 As regras:

  • “Decide which hidden controls need touch support. Reserve touch support for essential controls.” (decida quais controles ocultos precisam de suporte a toque, e reserve-o para os essenciais) Tooltips não se qualificam, nem nada que o toque já faz de outro jeito: “someone can swipe to scroll a carousel, so there’s no need to reveal the navigation buttons that exist for mice without a scroll wheel.” E: “Avoid keeping hidden controls visible all the time just to accommodate touch.”
  • “Reveal a hidden control when someone taps its general location on a touch display.” (revele um controle oculto quando alguém toca a região onde ele fica) Só os relevantes, e “Hide a control again when the person finishes with it, or after a few seconds if they don’t use it.” (esconda-o de novo quando a pessoa terminar, ou depois de alguns segundos sem uso)
  • “Retain the current selection when revealing a hidden control,” porque o controle pode agir sobre a seleção.
  • “Make essential hidden controls available in a context menu,” que o toque abre com um toque longo.
  • “In a sidebar, reveal hidden controls when someone taps the corresponding section header or row.” (em uma barra lateral, revele os controles ocultos quando alguém toca o cabeçalho de seção ou a linha correspondente) O exemplo é o Finder: “tapping the Favorites header in the Finder sidebar collapses the section and reveals a disclosure button.” Os controles revelados ficam até o toque sair da barra lateral ou um dispositivo apontador ser usado, e um toque na área de um controle oculto o revela sem ativá-lo: “The control acts only when they tap it again.” (o controle só age quando a pessoa toca nele de novo)
  • “In a tabbed window, reveal the selected tab’s close button when someone taps anywhere in the window,” e mantenha-o até a pessoa voltar a um dispositivo apontador.4

Essas seis regras são a forma escrita da orientação sobre hover dos dois talks, com tempos e exceções que os talks não deram: alguns segundos até um controle revelado se esconder, um segundo toque para ativar, e barras laterais e botões de fechar abas como os casos que continuam visíveis. A mesma revisão reescreveu o material de ponteiro do iPadOS da página para o Liquid Glass, mudou no texto o formato padrão do ponteiro de círculo para seta, substituiu a coluna só de AppKit da tabela de cursores por símbolos de AppKit e de SwiftUI, e removeu a seção de magnetismo do ponteiro; nada disso trata da tela do Mac.4

O que ainda não está aqui

Verificado às 9:51 da noite no horário do Pacífico em 28 de outubro, no endpoint de documentação da Apple, na página de entrada, nos feeds de notícias e de releases para desenvolvedores e na lista de Tech Talks.56

  • O beta do Xcode 27.3. O bloco da página de entrada ainda diz “Coming soon,” o feed de releases não lista nada mais novo que as versões pontuais de 26 de outubro (o macOS 27.2 entre elas), e as páginas de release notes do Xcode 27.3 e do macOS 27.3 retornam 404. O Xcode mais novo continua sendo o 27.2 RC, cujo SDK não inspecionei; a ressalva do post da tarde sobre o deployment target continua valendo, e o post sobre o lançamento do Xcode 27 traz o contexto sobre deployment targets.
  • Os três controles dos gestos do sistema que o talk de AppKit demonstrou, NSWindow.disablesDirectTouchSystemGestures, UIViewController.prefersDirectTouchSystemGesturesDisabled e o directTouchSystemGesturesDisabled() do SwiftUI. Os três retornam 404, e nenhum dos artigos novos os menciona. Os artigos descrevem como um gesto do sistema cancela o seu recognizer; não descrevem como desligar o gesto do sistema.
  • Um ActivityKit disponível no macOS. A página do framework traz um carimbo de 8 de outubro e não lista o macOS como plataforma, e AlertConfiguration.announcement(_:), do talk de Live Activities, retorna 404. A seção do post da tarde sobre Live Activities continua valendo como foi escrita, e o post sobre a máquina de estados continua sendo só uma implementação para iOS.
  • A “gesture modernization skill” que o talk de AppKit mencionou em 12:16. Nenhuma página da Apple a nomeia; o comentário TK skill da página de entrada continua lá.59
  • Um link da página do talk para o artigo, e qualquer declaração da Apple sobre um caminho pelo simulador ou pelo Device Hub para o toque no Mac.
  • Uma entrada datada na página de atualizações da documentação do SwiftUI. O carimbo do servidor dela é 2:58 da tarde no horário do Pacífico de 28 de outubro, mas a seção mais nova ainda é a de setembro de 2026, e a entrada sobre gestos é a linha GestureInputKinds de junho de 2026; o que quer que tenha mudado, não foi uma nova seção datada.6

Correções ao post para desenvolvedores

O post da tarde estava correto em relação às verificações do meio-dia; cinco das suas afirmações deixaram de valer na verificação das 9:51 da noite no horário do Pacífico de 28 de outubro. Um bloco de atualização naquele post, publicado junto com este, aponta para cá, e as afirmações foram corrigidas no próprio texto; esta é a lista.

  1. Os três blocos “Coming soon” da página de entrada agora são um. Os recursos de documentação e de design estão no ar; o beta do Xcode 27.3 não.5
  2. “Adopting gesture recognizers in your app” não retorna mais 404. Está no ar, e é o documento de onde a orientação de migração deve ser lida.1
  3. As páginas das HIG não estão mais caladas sobre o toque na tela do Mac. Três das quatro trazem linhas de change log de 28 de outubro; a página de Live Activities não.4
  4. A lista de emulação tem cinco regras, não as quatro da technote de junho; a regra de segurar e depois arrastar é o acréscimo.18
  5. As exclusive views só vêm ativadas por padrão para apps cujo Info.plist não tem a chave. Os templates macOS App e Document App do Xcode, no Xcode 27.1 e no beta do 27.2, gravam a chave como NO para um projeto cujo ciclo de vida de app é o app delegate do AppKit.127

O que o post da tarde disse sobre os SDKs, os três controles não documentados e o ActivityKit não muda com nada do que foi publicado desde então.

Principais conclusões

Para quem desenvolve em AppKit: rode o teste de quatro linhas do artigo no Sidecar e depois busque os cinco símbolos que ele nomeia; um override de mouseDown(with:), mouseDragged(with:) ou mouseUp(with:) em uma subclasse de controle faz esse controle cair para um tracking loop, quer chame super, quer não, e a correção são pares target-action em NSControl.Events com .trackingEndedOutside no conjunto de ocultação.1

Para um loop que você mantém: o recognizer só de toque precisa de buttonMask 0, ou um arrasto do mouse inicia o recognizer e o seu mouseDown(with:) nunca roda; allowedTouchTypes = .direct já é o padrão.1

Para recognizers próprios: chegue a um estado terminal, sobrescreva reset() e location(in:), e depure com -NSGestureRecognizerCrashOnMissingOverrides YES e -NSCrashOnStuckGestureTimeout 2, removidos antes de publicar; em produção, um recognizer travado é cancelado dois segundos depois que a pessoa para de interagir.12

Para a exclusividade: um app sem a chave é exclusivo; um projeto criado a partir do template macOS App do Xcode com o ciclo de vida do app delegate do AppKit (todo projeto Storyboard ou XIB) não é, e um com o ciclo de vida padrão do SwiftUI é. Leia o seu Info.plist antes de migrar um tracking loop.27

Para jogos: leia as posições dos eventos em vez de somar deltas, não sobrescreva sendEvent(_:), e saiba que cada superfície de toque é um GCMouse emulado adicional até NSIsTouchNative ser YES.3

Para designers: o toque é “a secondary input mode” (um modo de entrada secundário); mantenha o layout e o tamanho dos controles; amplie os alvos de toque, não os controles; revele controles ocultos com um toque perto deles, esconda-os quando a pessoa terminar ou depois de alguns segundos sem uso, com as barras laterais e o botão de fechar de uma aba como exceções, e dê aos essenciais um menu de contexto.4

Perguntas frequentes

O artigo de migração do AppKit está no ar?

Sim. “Adopting gesture recognizers in your app” retornava 404 ao meio-dia no horário do Pacífico em 28 de outubro e estava no ar às 9:51 da noite, listado nas seções Essentials e Gestures do AppKit e linkado pelo bloco de documentação da página de entrada.15

As exclusive views estão ativadas no meu app?

Se o seu Info.plist não tem a chave NSViewGestureRecognizerIsExclusive, sim: “If your app’s information property list doesn’t include the NSViewGestureRecognizerIsExclusive key, the system treats it as YES.” (se o Info.plist do app não inclui a chave, o sistema a trata como YES)2 Um projeto criado a partir do template macOS App no Xcode 27.1 ou no beta do 27.2 com o ciclo de vida do app delegate do AppKit (todo projeto Storyboard ou XIB) recebe a chave como um build setting com o valor NO; o mesmo template com o ciclo de vida padrão do SwiftUI não grava a chave (análise do autor a partir dos templates neste Mac).7

O que acontece com um gesture recognizer que nunca termina?

Ele segura a sua exclusive view até o sistema cancelá-lo: um recognizer “is stuck if it hasn’t reached a terminal state within 2 seconds after the person stops interacting with your app” (está travado se não chegou a um estado terminal até 2 segundos depois que a pessoa para de interagir), e o sistema “automatically transitions it to the NSGestureRecognizer.State.cancelled state.”2 Defina o default NSCrashOnStuckGestureTimeout durante a depuração para ter um stack trace no lugar.2

Por que o meu tracking loop para de receber arrastos depois que acrescento um pan recognizer?

Porque o buttonMask do recognizer está no valor padrão e captura o botão principal do mouse: “A mouse drag then begins the gesture recognizer, and AppKit doesn’t call your mouseDown(with:) override, so the tracking loop doesn’t run.” (um arrasto do mouse inicia o recognizer, o AppKit não chama o seu override de mouseDown(with:) e o tracking loop não roda) Defina buttonMask como 0 para ter um recognizer só de toque.1

Como um jogo recebe o toque no Mac?

Como eventos de mouse emulados, em uma ordem documentada, com um mouseMoved(with:) até a nova posição antes de cada mouseDown(with:), e como um GCMouse adicional cujos deltas não são contínuos. Definir NSIsTouchNative como YES passa o jogo para gesture recognizers e remove o GCMouse emulado.3

As HIG dão um tamanho de alvo de toque para o Mac?

Não. A página Gestures diz “Make tap targets bigger, not the controls themselves” (deixe os alvos de toque maiores, não os próprios controles) e remete aos controles do framework para o tamanho; o número de 36 pontos está nos dois talks, não nas HIG.49

De onde vêm os fatos deste post?

Dos dois artigos do AppKit da Apple, da TN3216, das três páginas das HIG e da página de entrada, todos baixados às 9:51 da noite no horário do Pacífico em 28 de outubro de 2026, com a disponibilidade do artigo, as páginas das HIG e a página de entrada comparadas com verificações feitas ao meio-dia e às 11:49 da manhã do mesmo dia; do JSON da documentação da Apple para cada símbolo citado; da technote de junho, para a comparação; das trilhas de legendas dos Tech Talks, para as citações dos talks; e dos headers e templates de projeto do Xcode 27.1 e do beta do Xcode 27.2 no meu Mac, que são análise do autor. A cobertura da imprensa não é fonte.

Fontes


  1. Apple Developer Documentation, Adopting gesture recognizers in your app, AppKit. Consultado em 28 de outubro de 2026 às 9:51 da noite no horário do Pacífico (HTTP 200, Last-Modified: Wed, 28 Oct 2026 21:30:45 GMT); a mesma URL e o seu endpoint JSON retornavam 404 ao meio-dia no horário do Pacífico do mesmo dia. Listado na seção Essentials da página do framework AppKit, em segundo lugar, depois de “Adopting Liquid Glass,” e em “Gesture handling” na página Gestures. A primeira captura do Wayback Machine é de 2026-10-29 01:08:12 UTC (linha CDX 20261029010812, status 200; os comprovantes do header bruto e do CDX estão guardados com as evidências do post). Seções citadas: Overview, “Prepare your app for a Mac with a touch display” (a tabela, o teste de quatro linhas, a lista de busca), “Filter gesture recognizer candidates,” “Handle touch input,” “Update your event-handling code,” “Replace common mouse-down overrides,” “Handle tracking-loop compatibility,” “Replace your custom tracking loops with gesture recognizers,” “Add touch support to your custom tracking loop,” “Write a custom gesture recognizer,” “Account for gesture recognizer behavior changes” e “Support non-AppKit UI frameworks.” A listagem em Swift deste post é uma redução de quatro linhas da listagem “Add touch support to your custom tracking loop” do artigo. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  2. Apple Developer Documentation, Handling AppKit gestures, AppKit. Consultado em 28 de outubro de 2026 às 9:51 da noite no horário do Pacífico (Last-Modified: Wed, 28 Oct 2026 05:35:41 GMT); sem histórico de revisões na página; não linkado pela TN3212; sem captura no índice do Wayback Machine até aquele momento. Seções citadas: Overview, “Track gesture recognizer states,” “Understand gesture recognizer gathering,” “Implement a custom gesture recognizer,” “Prioritize gesture recognizers,” “Delay responder events,” “Configure exclusive views,” “Replace event-tracking loops” e “Diagnose unresponsive gesture recognizers.” ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  3. Apple Developer Documentation, TN3216: Supporting touch input for games on macOS, histórico de revisões “2026-10-28 First published,” consultada em 28 de outubro de 2026 às 9:51 da noite no horário do Pacífico (Last-Modified: Wed, 28 Oct 2026 21:09:50 GMT). Seções citadas: Overview, “Extend the player experience meaningfully,” “Understand automatic touch support in existing games,” “Understand GCMouse emulation,” “Opt out of mouse emulation,” “Implement touch events,” “Route gestures in your game engine,” “Use standard AppKit controls for automatic touch support” e “Review your touch integration.” ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  4. Apple Developer, Human Interface Guidelines, consultadas em 28 de outubro de 2026 às 9:51 da noite no horário do Pacífico e comparadas com cópias baixadas ao meio-dia no horário do Pacífico do mesmo dia: Designing for macOS, change log “October 28, 2026 | Added guidance for touch input.”; Gestures, change log “October 28, 2026 | Added guidance for gestures and touch input in macOS.”, com a seção da plataforma macOS e a tabela “macOS trackpad and touch display gestures”; Pointing devices, change log “October 28, 2026 | Added guidance for revealing hidden controls with touch on Mac, and updated guidance and artwork for iPadOS and macOS.”, com a seção “Touch support for hidden controls”; Live Activities, idêntica byte a byte à cópia do meio-dia, com change log terminando em 13 de outubro de 2026. As cópias do meio-dia das três primeiras não contêm nada do texto citado. O header Last-Modified do servidor no novo JSON de Gestures marca Tue, 27 Oct 2026 05:11:02 GMT, com X-Cache: hit-stale na primeira requisição, às 9:59 da noite. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  5. Apple Developer, Get ready for Touch on Mac, consultada em 28 de outubro de 2026 às 11:49 da manhã no horário do Pacífico (três blocos dizendo “Coming soon,” links em comentários HTML) e às 9:51 da noite no horário do Pacífico: “Xcode 27.3 beta” / “Download the latest SDKs to build, run, and test your app.” / “Coming soon”; “Documentation resources” / “Learn how to build and optimize your app for touch input.” apontando para o artigo e para o exemplo; “Design resources” / “Create experiences that take advantage of touch user interface patterns.” apontando para Gestures, Designing for macOS, Pointing devices e o Apple Design Resources, cuja lista de molduras de produto inclui “MacBook Pro PROLED XDR Display”; o comentário TK skill presente nas duas consultas. Latest News RSS, item mais novo “Say hello to Touch on Mac,” Wed, 28 Oct 2026 10:00:55 PDT; Releases RSS, itens mais novos datados de Mon, 26 Oct 2026 10:00:00 PDT (iOS, iPadOS, macOS 27.2 (26B123), tvOS, visionOS e watchOS 27.2); a lista de Tech Talks com 111456, 111467 e 111468 e nenhum outro talk sobre toque ou Live Activities; a página de Bring Touch to your Mac app, sem link para nenhum dos artigos; tudo consultado às 9:51 da noite no horário do Pacífico. ↩↩↩↩↩↩↩↩↩

  6. JSON da documentação da Apple (developer.apple.com/tutorials/data/documentation/<path>.json), consultado em 28 de outubro de 2026 às 9:51 da noite no horário do Pacífico. Encontrados: trackingEndedOutside (macOS 11.0), NSEvent.isTouchSwipeNavigationEnabled (macOS 27.0), NSTextSelectionManager.gesturesForFailureRequirements (macOS 27.0), gestureRecognizer(_:shouldRequireFailureOf:) em NSGestureRecognizerDelegate (macOS 10.10), NSViewGestureRecognizerIsExclusive (“The default value is YES.”), NSIsTouchNative, Mouse, Keyboard, and Trackpad (as duas frases sobre a responder chain e o toque), Supporting drag and drop through file promises (a frase sobre toques diretos) e SwiftUI updates (Last-Modified: Wed, 28 Oct 2026 21:58:06 GMT, seção mais nova “September 2026”). Não encontrados (HTTP 404): appkit/nswindow/disablesdirecttouchsystemgestures, uikit/uiviewcontroller/prefersdirecttouchsystemgesturesdisabled, swiftui/view/directtouchsystemgesturesdisabled(), activitykit/alertconfiguration/announcement(_:), xcode-release-notes/xcode-27_3-release-notes, macos-release-notes/macos-27_3-release-notes. ActivityKit: Last-Modified: Thu, 08 Oct 2026 15:31:35 GMT, plataformas iOS, iPadOS e Mac Catalyst. ↩↩↩↩↩↩↩↩↩↩↩

  7. Verificação do SDK e dos templates em 28 de outubro de 2026 (análise do autor), no MacOSX27.0.sdk dentro do Xcode 27.1 (27A9275): a linha 180 do NSControl.h diz NSControlEventTrackingEndedOutside = 1 << 7, com a mesma linha no MacOSX27.2.sdk dentro do beta do Xcode 27.2 (27B5019j); a linha 496 do NSEvent.h diz @property (class, readonly, getter=isTouchSwipeNavigationEnabled) BOOL touchSwipeNavigationEnabled API_AVAILABLE(macos(27));; a linha 59 do NSTextSelectionManager.h declara gesturesForFailureRequirements; as linhas 116 e 149 do NSGestureRecognizer.h declaram shouldRequireFailureOfGestureRecognizer:. Templates de projeto, lidos com plistlib, no Xcode 27.1 (27A9275) e no beta do Xcode 27.2 (27B5019j), em Platforms/MacOSX.platform/Developer/Library/Xcode/Templates/Project Templates/macOS/Application/: Cocoa App Base.xctemplate/TemplateInfo.plist traz a chave INFOPLIST_KEY_NSViewGestureRecognizerIsExclusive com o valor string NO em Options[0] (appLifecycle) / Units / Cocoa / Targets[0] / SharedSettings, e em nenhum outro lugar; macOS App Lifecycle.xctemplate, em Project Templates/macOS/Base/, define a opção appLifecycle sem Name, com Type popup, Default SwiftUI e Values SwiftUI, Cocoa; macOS Application UI.xctemplate define userInterface com Name Interface:, Default SwiftUI e Values SwiftUI, Storyboard, XIB, e as suas unidades Storyboard e XIB, assim como uma das suas unidades SwiftUI, trazem RequiredOptions com appLifecycle Cocoa; App.xctemplate descende de Cocoa App Base por meio de Core Data App, macOS SwiftUI App, macOS Application UI e Cocoa App Native Base; Cocoa Document App.xctemplate grava um nó Info.plist:NSViewGestureRecognizerIsExclusive cuja definição é <key>NSViewGestureRecognizerIsExclusive</key><false/>, dentro da sua unidade de ciclo de vida Cocoa; Game.xctemplate define appLifecycle como Override Cocoa; Document App.xctemplate descende tanto de Cocoa Document App quanto de Cocoa App Base (por meio de Core Data Document App, macOS SwiftUI Document-Based App, macOS Application UI e Cocoa App Native Base). Só esses dois arquivos de template contêm a chave, nos dois Xcodes. Os build settings INFOPLIST_KEY_ do Xcode são gravados no Info.plist gerado. ↩↩↩↩↩↩↩↩↩↩

  8. Apple Developer Documentation, TN3212: Adopting gesture recognizers for Sidecar touch support, histórico de revisões “2026-06-08 First published,” seção “Support third-party UI frameworks,” quatro itens: “A tap emulates a mouse-down followed immediately by a mouse-up,” “A touch and immediate pan emulates trackpad scroll events, even if the UI doesn’t respond to them,” “A long press without movement emulates a rightMouseDown(with:) (optionally followed by rightMouseDragged(with:)) with a rightMouseUp(with:) on touch lift” e “A two-finger pinch or rotation simultaneously emulates both the trackpad magnify and rotate gestures.” Consultada em 28 de outubro de 2026. ↩↩↩

  9. Apple Developer, Tech Talks Bring Touch to your Mac app (13:19, Raleigh Ledet) e Design for touch on Mac (16:52, Cas Lemmens), 28 de outubro de 2026. As citações vêm das trilhas de legendas em inglês; o tempo entre parênteses é a primeira marcação do trecho citado: “drag with a small hold delay” (111468, 11:31), “there’s a gesture modernization skill that has an understanding of the features and changes I’ve talked about” (111468, 12:16), “Touch on macOS uses a touch target of 36 points” (111456, 9:17), “a minimum of 36 points on each axis” (111468, 5:53). A listagem de código da página do talk “Use NSControl events to detect tracking” (2:24) registra addTarget(_:action:for:) para [.trackingBegan, .trackingEntered], [.trackingExited, .trackingEndedInside] e .trackingCancelled. ↩↩↩↩↩

Artigos relacionados

Touch no Mac para devs: 36 pontos, recognizers e Sidecar

Touch no Mac para desenvolvedores: toques viram cliques, gesture recognizers são o único caminho do toque direto, alvos …

39 min de leitura

Imagens de itens de menu somem no macOS 27 e no iPadOS 27

macOS 27 e iPadOS 27 escondem as imagens dos itens de menu por padrão, e o que some depende do SDK usado na linkagem. Tr…

12 min de leitura

A Mac App Store não deixa gerenciadores de janelas existirem. Publiquei um mesmo assim.

O App Sandbox proíbe a API de que todo organizador de janelas precisa, e a Apple mandou distribuir fora da loja. O 941 T…

11 min de leitura