HoloLens (1ª gen) Entrada 211: Gesto

Importante

Os tutoriais da Mixed Reality Academy foram desenhados com HoloLens (1ª gen), Unidade 2017 e Auscultadores Imersivos de Realidade Mista em mente. Como tal, sentimos que é importante deixar estes tutoriais no lugar para os desenvolvedores que ainda estão à procura de orientação no desenvolvimento para esses dispositivos. Estes tutoriais não serão atualizados com os mais recentes instrumentos ou interações que estão a ser utilizados para HoloLens 2 e podem não ser compatíveis com versões mais recentes da Unidade. Serão mantidos para continuar a trabalhar nos dispositivos suportados. Uma nova série de tutoriais foi publicada para HoloLens 2.

Os gestos transformam a intenção do utilizador em ação. Com gestos, os utilizadores podem interagir com hologramas. Neste curso, vamos aprender a rastrear as mãos do utilizador, responder à entrada do utilizador e dar feedback ao utilizador com base no estado da mão e na localização.

No MR Basics 101, usamosum simples gesto de toque de ar para interagir com os nossos hologramas. Agora, vamos ultrapassar o gesto de toque de ar e explorar novos conceitos para:

  • Detete quando a mão do utilizador está a ser rastreada e forneça feedback ao utilizador.
  • Use um gesto de navegação para rodar os nossos hologramas.
  • Forneça feedback quando a mão do utilizador está prestes a sair da vista.
  • Use eventos de manipulação para permitir que os utilizadores movam hologramas com as mãos.

Neste curso, vamos revisitar o projeto Unity Model Explorer,que construímos no MR Input 210. O nosso amigo astronauta está de volta para nos ajudar na exploração destes novos conceitos de gestos.

Importante

Os vídeos incorporados em cada um dos capítulos abaixo foram gravados usando uma versão mais antiga de Unidade e o Mixed Reality Toolkit. Embora as instruções passo a passo sejam precisas e atuais, pode ver scripts e visuais nos vídeos correspondentes que estão desatualizados. Os vídeos continuam incluídos para a posteridade e porque os conceitos cobertos ainda se aplicam.

Suporte de dispositivos

Curso HoloLens Auscultadores imersivos
Entrada MR 211: Gesto ✔️ ✔️

Antes de começar

Pré-requisitos

Project ficheiros

  • Descarregue os ficheiros exigidos pelo projeto. Requer Unidade 2017.2 ou mais tarde.
  • Desaprove os ficheiros para o seu ambiente de trabalho ou outro local de fácil acesso.

Nota

Se quiser ver o código fonte antes de descarregar, está disponível no GitHub.

Errata e Notas

  • "Enable Just My Code" precisa de ser desativado(não verificado)em Visual Studio de ferramentas- Opções- > Depuração para atingir pontos de rutura no seu código.

Capítulo 0 - Configuração da Unidade

Instruções

  1. Iniciar a Unidade.
  2. Selecione Abrir.
  3. Navegue para a pasta Gesto que não tenha arquivado anteriormente.
  4. Encontre e selecione a pasta Start-ModelExplorer.
  5. Clique no botão Selecione Pasta.
  6. No painel Project, expanda a pasta Cenas.
  7. Clique duas vezes na cena do ModelExplorer para carregá-lo em Unidade.

Edifício

  1. In Unitity, selecione File Build Definições.
  2. Se Cenas/ModelExplorer não estiverem listados em Scenes In Build,clique em Adicionar Cenas Abertas para adicionar a cena.
  3. Se estiver a desenvolver especificamente para HoloLens, desenhe o dispositivo Target para HoloLens. Caso contrário, deixe-o em qualquer dispositivo.
  4. Certifique-se de que o Tipo de Construção está definido para D3D e o SDK está definido para o mais recente instalado (que deve ser SDK 16299 ou mais recente).
  5. Clique em Construir.
  6. Criar uma nova pasta chamada "App".
  7. Clique na pasta App.
  8. A Pasta e Unidade de Imprensa Selerá começará a construir o projeto para Visual Studio.

Quando a unidade estiver terminada, aparecerá uma janela do Explorador de Ficheiros.

  1. Abra a pasta App.
  2. Abra a solução Visual Studio ModelExplorer.

Se for implantado para HoloLens:

  1. Utilizando a barra de ferramentas superior em Visual Studio, altere o alvo de Debug para Release e de ARM para x86.
  2. Clique na seta de queda ao lado do botão Máquina Local e selecione Máquina Remota.
  3. Introduza o seu endereço IP HoloLens dispositivo e desafie o modo de autenticação para universal (Protocolo não encriptado). Clique em Selecionar. Se não souber o endereço IP do seu dispositivo, procure Definições Network Internet Advanced &> Options.
  4. Na barra de menu superior, clique em Debug - Comece sem depurar ou prima Ctrl + F5. Se esta for a primeira vez que se implanta no seu dispositivo, terá de emparelhá-lo com Visual Studio.
  5. Quando a aplicação tiver sido implantada, desprete a Fitbox com um gesto selecionado.

Se for implantado num auricular imersivo:

  1. Utilizando a barra de ferramentas superior em Visual Studio, altere o alvo de Debug para Release e de ARM para x64.
  2. Certifique-se de que o alvo de implantação está definido para Máquina Local.
  3. Na barra de menu superior, clique em Debug - Comece sem depurar ou prima Ctrl + F5.
  4. Quando a aplicação tiver sido implantada, desprete a Fitbox puxando o gatilho num controlador de movimento.

Nota

Pode notar alguns erros vermelhos no painel Visual Studio Errors. É seguro ignorá-los. Mude para o painel de saída para ver o progresso real da construção. Erros no painel de saída exigirão que faça uma correção (na maioria das vezes são causados por um erro num script).

Capítulo 1 - Feedback detetado à mão

Objetivos

  • Subscreva eventos de rastreio manual.
  • Utilize feedback do cursor para mostrar aos utilizadores quando uma mão está a ser rastreada.

Nota

No HoloLens 2, as mãos detetaram fogos sempre que as mãos são visíveis (não apenas quando um dedo está apontando para cima).

Instruções

  • No painel hierarquia, expanda o objeto InputManager.
  • Procure e selecione o objeto GesturesInput.

O script interactionInputSource.cs executa estes passos:

  1. Subscreve os eventos InteractionSourceDetected e InteractionSourceLost.
  2. Define o estado de despercebida à mão.
  3. Cancelar subscrições dos eventos InteractionSourceDetected e InteractionSourceLost.

Em seguida, atualizaremos o nosso cursor do MR Input 210 para um que mostra feedback dependendo das ações do utilizador.

  1. No painel hierarquia, selecione o objeto Cursor e elimine-o.
  2. No painel Project, procure o CursorWithFeedback e arraste-o para o painel da Hierarquia.
  3. Clique no InputManager no painel da hierarquia e, em seguida, arraste o objeto CursorWithFeedback da Hierarquia para o campo cursor do InputManager's SimpleSinglePointerSelector,na parte inferior do Inspetor.
  4. Clique no CursorWithFeedback na Hierarquia.
  5. No painel do Inspetor, expanda os dados do Estado do Cursor no script Do Cursor de Objetos.

Os Dados do Estado do Cursor funcionam assim:

  • Qualquer estado de Observação significa que nenhuma mão é detetada e o utilizador está simplesmente a olhar em volta.
  • Qualquer estado de interação significa que uma mão ou controlador é detetada.
  • Qualquer estado hover significa que o utilizador está a olhar para um holograma.

Construir e Implementar

  • Em Unidade, utilize o Definições de Construção de Ficheiros para reconstruir a aplicação.
  • Abra a pasta App.
  • Se ainda não estiver aberto, abra o ModelExplorer Visual Studio Solution.
    • (Se já construiu/implementou este projeto em Visual Studio durante a configuração, então pode abrir essa instância de VS e clicar em 'Reload All' quando solicitado).
  • Em Visual Studio, clique em Debug - Start Without debugging ou prima Ctrl + F5.
  • Depois de a aplicação ser colocada no HoloLens, desprete a caixa de ajuste utilizando o gesto de toque de ar.
  • Mova a mão para a vista e aponte o dedo indicador para o céu para começar a rastrear as mãos.
  • Mova a mão para a esquerda, direita, para cima e para baixo.
  • Observe como o cursor muda quando a sua mão é detetada e depois perdida da vista.
  • Se estiver num auricular imersivo, terá de ligar e desligar o controlador. Este feedback torna-se menos interessante num dispositivo imersivo, uma vez que um controlador conectado estará sempre "disponível".

Capítulo 2 - Navegação

Objetivos

  • Use eventos de gestos de navegação para rodar o astronauta.

Instruções

Para utilizar gestos de Navegação na nossa aplicação, vamos editar a GestureAction.cs para rodar objetos quando o gesto de Navegação ocorrer. Além disso, adicionaremos feedback ao cursor para exibir quando a Navegação estiver disponível.

  1. No painel hierarquia,expanda o CursorWithFeedback.
  2. Na pasta Hologramas, encontre o ativo ScrollFeedback.
  3. Arraste e deixe cair o prefácio do ScrollFeedback no CursorWithFeedback GameObject na Hierarquia.
  4. Clique em CursorWithFeedback.
  5. No painel inspetor, clique no botão Adicionar Componente.
  6. No menu, digite na caixa de pesquisa CursorFeedback. Selecione o resultado da pesquisa.
  7. Arraste e deixe cair o objeto ScrollFeedback da hierarquia para a propriedade Do Objeto de Jogo Detetado no Componente De Feedback do Cursor no Inspetor.
  8. No painel hierarquia, selecione o objeto AstroMan.
  9. No painel inspetor, clique no botão Adicionar Componente.
  10. No menu, digite na caixa de pesquisa Gesture Action. Selecione o resultado da pesquisa.

Em seguida, aBriu a Reação de Gesto.cs em Visual Studio. No exercício de codificação 2.c, edite o script para fazer o seguinte:

  1. Rode o objeto AstroMan sempre que um gesto de Navegação for realizado.
  2. Calcular a rotaçãoFactor para controlar a quantidade de rotação aplicada ao objeto.
  3. Rode o objeto em torno do eixo y quando o utilizador mover a mão para a esquerda ou para a direita.

Complete os exercícios de codificação 2.c no script ou substitua o código pela solução completa abaixo:

using HoloToolkit.Unity.InputModule;
using UnityEngine;

/// <summary>
/// GestureAction performs custom actions based on
/// which gesture is being performed.
/// </summary>
public class GestureAction : MonoBehaviour, INavigationHandler, IManipulationHandler, ISpeechHandler
{
    [Tooltip("Rotation max speed controls amount of rotation.")]
    [SerializeField]
    private float RotationSensitivity = 10.0f;

    private bool isNavigationEnabled = true;
    public bool IsNavigationEnabled
    {
        get { return isNavigationEnabled; }
        set { isNavigationEnabled = value; }
    }

    private Vector3 manipulationOriginalPosition = Vector3.zero;

    void INavigationHandler.OnNavigationStarted(NavigationEventData eventData)
    {
        InputManager.Instance.PushModalInputHandler(gameObject);
    }

    void INavigationHandler.OnNavigationUpdated(NavigationEventData eventData)
    {
        if (isNavigationEnabled)
        {
            /* TODO: DEVELOPER CODING EXERCISE 2.c */

            // 2.c: Calculate a float rotationFactor based on eventData's NormalizedOffset.x multiplied by RotationSensitivity.
            // This will help control the amount of rotation.
            float rotationFactor = eventData.NormalizedOffset.x * RotationSensitivity;

            // 2.c: transform.Rotate around the Y axis using rotationFactor.
            transform.Rotate(new Vector3(0, -1 * rotationFactor, 0));
        }
    }

    void INavigationHandler.OnNavigationCompleted(NavigationEventData eventData)
    {
        InputManager.Instance.PopModalInputHandler();
    }

    void INavigationHandler.OnNavigationCanceled(NavigationEventData eventData)
    {
        InputManager.Instance.PopModalInputHandler();
    }

    void IManipulationHandler.OnManipulationStarted(ManipulationEventData eventData)
    {
        if (!isNavigationEnabled)
        {
            InputManager.Instance.PushModalInputHandler(gameObject);

            manipulationOriginalPosition = transform.position;
        }
    }

    void IManipulationHandler.OnManipulationUpdated(ManipulationEventData eventData)
    {
        if (!isNavigationEnabled)
        {
            /* TODO: DEVELOPER CODING EXERCISE 4.a */

            // 4.a: Make this transform's position be the manipulationOriginalPosition + eventData.CumulativeDelta
        }
    }

    void IManipulationHandler.OnManipulationCompleted(ManipulationEventData eventData)
    {
        InputManager.Instance.PopModalInputHandler();
    }

    void IManipulationHandler.OnManipulationCanceled(ManipulationEventData eventData)
    {
        InputManager.Instance.PopModalInputHandler();
    }

    void ISpeechHandler.OnSpeechKeywordRecognized(SpeechEventData eventData)
    {
        if (eventData.RecognizedText.Equals("Move Astronaut"))
        {
            isNavigationEnabled = false;
        }
        else if (eventData.RecognizedText.Equals("Rotate Astronaut"))
        {
            isNavigationEnabled = true;
        }
        else
        {
            return;
        }

        eventData.Use();
    }
}

Você vai notar que os outros eventos de navegação já estão preenchidos com alguma informação. Empurramos o GameObject para a pilha modal do InputSystem do Toolkit, para que o utilizador não tenha de manter o foco no Astronauta uma vez iniciada a rotação. Consequentemente, tiramos o GameObject da pilha assim que o gesto estiver concluído.

Construir e Implementar

  1. Reconstruir a aplicação em Unidade e, em seguida, construir e implantar a partir de Visual Studio para executá-la no HoloLens.
  2. Olhe para o astronauta, duas setas devem aparecer em ambos os lados do cursor. Este novo visual indica que o astronauta pode ser rodado.
  3. Coloque a mão na posição pronta (dedo indicador apontado para o céu) para que o HoloLens comece a seguir a sua mão.
  4. Para rodar o astronauta, baixe o dedo indicador para uma posição de aperto e, em seguida, mova a mão para a esquerda ou direita para ativar o gesto NavigationX.

Capítulo 3 - Orientação manual

Objetivos

  • Utilize a pontuação de orientação da mão para ajudar a prever quando é que o rastreio das mãos será perdido.
  • Forneça feedback sobre o cursor para mostrar quando a mão do utilizador se aproxima do limite de visão da câmara.

Instruções

  1. No painel hierarquia, selecione o objeto CursorWithFeedback.
  2. No painel inspetor, clique no botão Adicionar Componente.
  3. No menu, digite na caixa de pesquisa Manual Guidance. Selecione o resultado da pesquisa.
  4. Na pasta Hologramas painel Project, encontre o ativo HandGuidanceFeedback.
  5. Arraste e deixe cair o ativo HandGuidanceFeedback na propriedade do Indicador de Orientação manual no painel do Inspetor.

Construir e Implementar

  • Reconstruir a aplicação em Unidade e, em seguida, construir e implementar a partir de Visual Studio para experimentar a aplicação em HoloLens.
  • Ponha a mão à vista e levante o dedo indicador para ser rastreado.
  • Comece a rodar o astronauta com o gesto de Navegação (belisque o dedo indicador e o polegar juntos).
  • Mova a mão para a esquerda, direita, para cima e para baixo.
  • À medida que a sua mão se aproxima da borda da moldura do gesto, deve aparecer uma seta ao lado do cursor para avisá-lo de que o rastreio de mãos será perdido. A seta indica em que direção mover a mão para evitar que o rastreio se perca.

Capítulo 4 - Manipulação

Objetivos

  • Use eventos de manipulação para mover o astronauta com as mãos.
  • Forneça feedback sobre o cursor para informar o utilizador quando a Manipulação pode ser utilizada.

Instruções

GestureManager.cs e AstronautManager.cs permitir-nos-á fazer o seguinte:

  1. Use a palavra-chave da fala "Move Astronaut" para permitir gestos de manipulação e "Astronauta Rotativo" para desativá-los.
  2. Mude para responder ao Reconhecedor de Gestos de Manipulação.

Vamos começar.

  1. No painel da Hierarquia, crie um novo GameObject vazio. Diga-lhe "AstronautaManager".
  2. No painel inspetor, clique no botão Adicionar Componente.
  3. No menu, digite na caixa de pesquisa Astronaut Manager. Selecione o resultado da pesquisa.
  4. No painel inspetor, clique no botão Adicionar Componente.
  5. No menu, digite na caixa de pesquisa Fonte de entrada de discurso. Selecione o resultado da pesquisa.

Vamos agora adicionar os comandos de fala necessários para controlar o estado de interação do astronauta.

  1. Expandir a secção palavras-chave no Inspetor.
  2. Clique + no lado direito para adicionar uma nova palavra-chave.
  3. Digite a palavra-chave como Astronauta move. Sinta-se à vontade para adicionar um Atalho chave, se desejar.
  4. Clique + no lado direito para adicionar uma nova palavra-chave.
  5. Digite a palavra-chave como Astronauta Rotativo. Sinta-se à vontade para adicionar um Atalho chave, se desejar.
  6. O código de manipulador correspondente pode ser encontrado no GestureAction.cs, no manipulador ISpeechHandler.OnSpeechKeyword Reconhecido.

Como configurar a Fonte de Entrada de Discurso para o capítulo 4

Em seguida, vamos configurar o feedback de manipulação no cursor.

  1. No painel ProjectHologramas pasta, encontre o ativo PathingFeedback.
  2. Arraste e deixe cair o prefácio PathingFeedback no objeto CursorWithFeedback na Hierarquia.
  3. No painel hierarquia, clique no CursorWithFeedback.
  4. Arraste e largue o objeto PathingFeedback da Hierarquia para a propriedade Pathing Detected Game Object no componente Cursor Feedback no Inspetor.

Agora precisamos adicionar código à GestureAction.cs para ativar o seguinte:

  1. Adicione código à função IManipulationHandler.OnManipulationUpdated, que moverá o astronauta quando for detetado um gesto de manipulação.
  2. Calcular o vetor de movimento para determinar para onde o astronauta deve ser movido com base na posição da mão.
  3. Mova o astronauta para a nova posição.

Complete o exercício de codificação 4.a em GestureAction.cs,ou use a nossa solução completa abaixo:

using HoloToolkit.Unity.InputModule;
using UnityEngine;

/// <summary>
/// GestureAction performs custom actions based on
/// which gesture is being performed.
/// </summary>
public class GestureAction : MonoBehaviour, INavigationHandler, IManipulationHandler, ISpeechHandler
{
    [Tooltip("Rotation max speed controls amount of rotation.")]
    [SerializeField]
    private float RotationSensitivity = 10.0f;

    private bool isNavigationEnabled = true;
    public bool IsNavigationEnabled
    {
        get { return isNavigationEnabled; }
        set { isNavigationEnabled = value; }
    }

    private Vector3 manipulationOriginalPosition = Vector3.zero;

    void INavigationHandler.OnNavigationStarted(NavigationEventData eventData)
    {
        InputManager.Instance.PushModalInputHandler(gameObject);
    }

    void INavigationHandler.OnNavigationUpdated(NavigationEventData eventData)
    {
        if (isNavigationEnabled)
        {
            /* TODO: DEVELOPER CODING EXERCISE 2.c */

            // 2.c: Calculate a float rotationFactor based on eventData's NormalizedOffset.x multiplied by RotationSensitivity.
            // This will help control the amount of rotation.
            float rotationFactor = eventData.NormalizedOffset.x * RotationSensitivity;

            // 2.c: transform.Rotate around the Y axis using rotationFactor.
            transform.Rotate(new Vector3(0, -1 * rotationFactor, 0));
        }
    }

    void INavigationHandler.OnNavigationCompleted(NavigationEventData eventData)
    {
        InputManager.Instance.PopModalInputHandler();
    }

    void INavigationHandler.OnNavigationCanceled(NavigationEventData eventData)
    {
        InputManager.Instance.PopModalInputHandler();
    }

    void IManipulationHandler.OnManipulationStarted(ManipulationEventData eventData)
    {
        if (!isNavigationEnabled)
        {
            InputManager.Instance.PushModalInputHandler(gameObject);

            manipulationOriginalPosition = transform.position;
        }
    }

    void IManipulationHandler.OnManipulationUpdated(ManipulationEventData eventData)
    {
        if (!isNavigationEnabled)
        {
            /* TODO: DEVELOPER CODING EXERCISE 4.a */

            // 4.a: Make this transform's position be the manipulationOriginalPosition + eventData.CumulativeDelta
            transform.position = manipulationOriginalPosition + eventData.CumulativeDelta;
        }
    }

    void IManipulationHandler.OnManipulationCompleted(ManipulationEventData eventData)
    {
        InputManager.Instance.PopModalInputHandler();
    }

    void IManipulationHandler.OnManipulationCanceled(ManipulationEventData eventData)
    {
        InputManager.Instance.PopModalInputHandler();
    }

    void ISpeechHandler.OnSpeechKeywordRecognized(SpeechEventData eventData)
    {
        if (eventData.RecognizedText.Equals("Move Astronaut"))
        {
            isNavigationEnabled = false;
        }
        else if (eventData.RecognizedText.Equals("Rotate Astronaut"))
        {
            isNavigationEnabled = true;
        }
        else
        {
            return;
        }

        eventData.Use();
    }
}

Construir e Implementar

  • Reconstruir em Unidade e, em seguida, construir e implementar a partir de Visual Studio para executar a app em HoloLens.
  • Mova a mão para a frente do HoloLens e levante o dedo indicador para que possa ser rastreado.
  • Concentre o cursor sobre o astronauta.
  • Diga "Mova astronauta" para mover o astronauta com um gesto de manipulação.
  • Quatro setas devem aparecer em torno do cursor para indicar que o programa irá agora responder a eventos de manipulação.
  • Baixa o dedo indicador até ao polegar e mantém-nos apertados.
  • À medida que moves a mão, o astronauta também se move (isto é manipulação).
  • Levante o dedo indicador para parar de manipular o astronauta.
  • Nota: Se não disser "Mova astronauta" antes de mover a mão, então o gesto de Navegação será usado.
  • Diga "Astronauta rotativo" para voltar ao estado rotativo.

Capítulo 5 - Expansão do modelo

Objetivos

  • Expanda o modelo Astronauta em várias peças menores com as que o utilizador pode interagir.
  • Mova cada peça individualmente usando gestos de Navegação e Manipulação.

Instruções

Nesta secção, realizaremos as seguintes tarefas:

  1. Adicione uma nova palavra-chave "Expandir Modelo" para expandir o modelo astronauta.
  2. Adicione uma nova palavra-chave "Reset Model" para devolver o modelo à sua forma original.

Vamos fazê-lo adicionando mais duas palavras-chave à Fonte de Entrada de Discurso do capítulo anterior. Também vamos demonstrar outra forma de lidar com eventos de reconhecimento.

  1. Clique de volta no AstronautManager no Inspetor e expanda a secção palavras-chave no Inspetor.
  2. Clique + no lado direito para adicionar uma nova palavra-chave.
  3. Digite a palavra-chave como Modelo de Expansão. Sinta-se à vontade para adicionar um Atalho chave, se desejar.
  4. Clique + no lado direito para adicionar uma nova palavra-chave.
  5. Digite a palavra-chave como modelo de reset. Sinta-se à vontade para adicionar um Atalho chave, se desejar.
  6. No painel inspetor, clique no botão Adicionar Componente.
  7. No menu, digite na caixa de pesquisa Speech Input Handler. Selecione o resultado da pesquisa.
  8. Check Is Global Listener, já que queremos que estes comandos funcionem independentemente do GameObject que estamos a focar.
  9. Clique no + botão e selecione + a partir do dropdown da palavra-chave.
  10. Clique no + under Response e arraste o + da Hierarquia para o campo Nenhum (Objeto).
  11. Agora, clique no dropdown No Function, selecione AstronautManager,em seguida, ExpandModelCommand.
  12. Clique no botão do Manipulador de Entrada de Discurso + e selecione + a partir do dropdown da palavra-chave.
  13. Clique no + under Response e arraste o + da Hierarquia para o campo Nenhum (Objeto).
  14. Agora, clique no dropdown No Function, selecione AstronautManagere, em seguida, ResetModelCommand.

Como configurar a Fonte de Entrada de Discurso e o Manipulador para o capítulo 5

Construir e Implementar

  • Experimente! Construa e implemente a aplicação para o HoloLens.
  • Diga modelo expandir para ver o modelo de astronauta expandido.
  • Use a Navegação para rodar peças individuais do fato de astronauta.
  • Diga astronauta move-se e depois use manipulação para mover peças individuais do fato de astronauta.
  • Diga ao Astronauta Rota para rodar as peças novamente.
  • Diga "Reset Model" para devolver o astronauta à sua forma original.

Fim

Parabéns! Já completou o MR Input 211: Gesture.

  • Sabe como detetar e responder a eventos de rastreio, navegação e manipulação à mão.
  • Compreende a diferença entre gestos de Navegação e Manipulação.
  • Sabe como alterar o cursor para fornecer feedback visual para quando uma mão é detetada, quando uma mão está prestes a perder-se, e para quando um objeto suporta diferentes interações (Navegação vs Manipulação).