Visão geral
O modelo de execução de um NCLua é orientado a eventos. Como será visto adiante, um script Lua para TV Digital nada mais é que um tratador de eventos.
Isso quer dizer que existem eventos associados aos usos do controle remoto, transmissões pelo canal de interatividade, sincronismos em documentos NCL, etc, e é através deles que toda dinâmica de um NCLua se faz.
Durante a inicialização do NCLua, antes de se tornar orientado a eventos, o script deve registrar pelo menos uma função de tratamento de eventos. A partir de então, qualquer ação tomada pela aplicação é somente em resposta a um evento recebido por essa função tratadora. A função event.register efetua o registro de tratadores.
--- example.lua ---
... -- código de inicialização
function handler (evt)
... -- código do tratador
end
event.register(handler) -- registro do tratador
Durante sua execução, um NCLua também pode enviar eventos para se comunicar com o ambiente. Assim é possível que o NCLua envie dados pelo canal de interatividade, sinalize que sua execução terminou, etc. A função event.post efetua o envio de eventos.
Um NCLua também pode usufruir desse mecanismo de eventos internamente, através
de eventos da classe user
.
Tais eventos, portanto, são postados e recebidos pelo próprio NCLua.
Classes de Eventos
Um evento é descrito por uma tabela Lua simples, onde o campo class
é
obrigatório e identifica a classe do evento.
Por exemplo, um evento para indicar que a tecla '0'
foi pressionada é
descrito pela seguinte tabela:
{ class='key', type='press', key='0' }
As seguintes classes de eventos são definidas:
Classe 'ncl':
Um NCLua se comunica com o documento no qual está inserido através desta classe de eventos.
Em um documento NCL, relacionamentos entre nós de mídia são descritos através de elos que relacionam condições e ações. Um NCLua interage com o documento apenas através de elos em que seu objeto de mídia está associado. Portanto, não é possível que um NCLua interfira diretamente no comportamento de outras mídias presentes no documento.
Em elos que acionam o NCLua, a condição satisfeita faz com que o NCLua receba um evento descrevendo a ação a ser tomada.
Por exemplo, no elo abaixo:
<link xconnector="onBeginStart">
<bind role="onBegin" component="videoId"/>
<bind role="start" component="luaId"/>
</link>
Quando videoId
iniciar, o NCLua receberá o evento:
{ class='ncl', type='presentation', action='start' }
Esse evento será recebido pela função registrada durante a inicialização do script.
Em elos cuja condição depende de um NCLua, a ação será disparada quando o NCLua sinalizar o evento que case com a condição esperada.
Por exemplo, no elo abaixo:
<link xconnector="onBeginStart">
<bind role="onEnd" component="luaId"/>
<bind role="start" component="imageId"/>
</link>
Assim que o NCLua postar o evento:
event.post { class='ncl', type='presentation', action='stop' }
O elo irá exibir a imagem que participa do elo.
Há dois tipos de eventos da classe ncl
suportados pelos NCLua: apresentação e
atribuição.
Eventos de seleção são tratados pela classe de eventos 'key'
.
O tipo é identificado no campo type
do evento e pode assumir, portanto,
apenas os valores 'presentation'
ou 'attribution'
.
Tipo 'presentation'
:
Eventos de apresentação controlam a exibição do nó NCLua.
Eventos de apresentação podem estar associados a áreas (âncoras de
apresentação)
específicas ou ao nó como um todo.
Áreas são identificadas pelo campo area
e equivalem ao nó inteiro
quando ausentes (i.e. iguais a nil
).
O campo action
indica a ação a ser tomada ou sinalizada pelo NCLua,
dependendo se este está recebendo ou gerando o evento.
Em suma, um evento de apresentação possui a seguinte estrutura:
class
:'ncl'
type
:'presentation'
area
:[string]
Nome da âncora (label
) associada ao evento.action
:[string]
Pode assumir os seguintes valores:'start'
,'stop'
,'abort'
,'pause'
e'resume'
.
Tipo 'attribution'
:
Eventos de atribuição controlam as propriedades do nó NCLua.
O campo property
do evento contém o nome da propriedade sendo afetada.
Os eventos de atribuição são bastante similares aos de apresentação, uma vez
que são regidos pelo mesmo modelo de máquina de estados.
Assim, o campo action
pode assumir os mesmos valores encontrados nos eventos
de apresentação.
O campo value
é preenchido com o valor a ser atribuido e é sempre uma
string
, uma vez que vem de um atributo XML.
A ação de start em um evento de atribuição corresponde ao role="set"
em um
elo NCL.
As propriedades dos NCLua não possuem nenhuma relação direta com as variáveis declaradas no script. Um NCLua que pretende alterar o valor de uma propriedade deve postar um evento para tal fim. As propriedades dos nós são controladas pelo próprio documento NCL.
Por exemplo:
event.post {
class = 'ncl',
type = 'attribution',
property = 'myProp',
action = 'start',
value = '10',
}
Em suma, um evento de atribuição possui a seguinte estrutura:
class
:'ncl'
type
:'attribution'
property
:[string]
Nome da propriedade (name
) associada ao evento.action
:[string]
Pode assumir os seguintes valores:'start'
,'stop'
,'abort'
,'pause'
e'resume'
.value
:[string]
Novo valor a ser atribuído à propriedade.
Classe 'key':
Esta classe de eventos é utilizada para representar o uso do controle remoto pelo usuário. Para esta classe não faz sentido que o NCLua gere eventos, uma vez que o controle remoto é um dispositivo unicamente de entrada.
Exemplo:
{ class='key', type='press', key='0' }
Eventos da classe key
possuem a seguinte estrutura:
class
:'key'
type
:[string]
Pode assumir'press'
ou'release'
.key
:[string]
Valor da tecla em questão.
Classe 'user':
Aplicações podem extender sua funcionalidade criando seus próprios eventos através desta classe.
Nenhum campo da tabela representando o evento está definido (além,
claro, do campo class
).
Como eventos desta classe são para uso interno, não faz sentido a postagem de
seus eventos com o destino igual a 'out'
.
Exemplo:
{ class='user', data='mydata' }
Classe 'tcp':
O uso do canal de interatividade é realizado por meio desta classe de eventos.
De modo a enviar e receber dados, uma conexão deve ser pré estabelecida, postando um evento como a seguir.
event.post {
class = 'tcp',
type = 'connect',
host = <addr>,
port = <number>,
[timeout = <number>,]
}
O resultado da conexão é retornado em um tratador de eventos pré registrado. O evento retornado possui a seguinte estrutura:
evt = {
class = 'tcp',
type = 'connect',
host = <addr>,
port = <number>,
connection = identifier,
error = <err_msg>,
}
Os campos error
e connection
são mutuamente exclusivos.
Quando houver um problema na conexão, uma mensagem de erro é retornada no campo
error
.
Quando a conexão sucede, um identificador único para a conexão é retornado no
campo connection
.
Um NCLua envia dados através do canal de retorno postando eventos na seguinte forma:
event.post {
class = 'tcp',
type = 'data',
connection = <identifier>,
value = <string>,
[timeout = number,]
}
De maneira similar, um NCLua recebe dados do canal de retorno em eventos da seguinte forma:
evt = {
class = 'tcp',
type = 'data',
value = <string>,
connection = <identifier>,
error = <err_msg>,
}
Novamente, os campos error
e connection
são mutuamente exclusivos.
Quando houver um problema na conexão, uma mensagem de erro é retornada no campo
error
.
Quando a conexão sucede, um identificador único para a conexão é retornado no
campo connection
.
Para fechar uma conexão, o seguinte evento deve ser postado:
event.post {
class = 'tcp',
type = 'disconnect',
connection = <identifier>,
}
Funções
event.register ([pos,] f)
Registra a função passada como um tratador de eventos, isto é, sempre que ocorrer um evento, `f` será chamada. |
event.unregister (f)
Desregistra a função passada como um tratador de eventos, isto é, novos eventos não serão mais passados a `f`. |
event.post ([dst,] evt)
Posta o evento passado. |
event.timer (time, f)
Cria um timer que expira após `time` (em milisegundos) e então chama a função `f`. |
event.uptime ()
Retorna o número de milisegundos decorridos desde o início da aplicação. |
Recebe:
pos
: [number] Posição de inserção da função de tratamento.f
: [function] Função de tratamento.
A assinatura de f
deve ser:
function f (evt)
-- returns boolean
end
Onde evt
é o evento que, ao ocorrer, ativa a função.
A função pode retornar true
, para sinalizar que o evento foi tratado e,
portanto, não deve ser enviado a outros tratadores.
É recomendado que a função (definida pela aplicação) retorne rapidamente, já que enquanto ela estiver executando, nenhum outro evento é processado.
O formatador NCL garante que as funções recebem os eventos na ordem em que
foram registradas. Enquanto os tratadores não retornam o valor true
, o
formatador notifica o próximo tratador registrado.
O parâmetro pos
é opcional e, caso não seja passado, a função registrada será
a última a receber eventos.
Desregistra a função passada como um tratador de eventos, isto é, novos
eventos não serão mais passados a f
.
Recebe:
f
: [function] Função de tratamento.
Posta o evento passado.
Recebe:
dst
: [string] Destinatário do evento. Pode assumir os valores'in'
(envio para a própria aplicação) e'out'
(envio para o formatador NCL). Caso seja omitido, assume o valor'out'
.evt
: [table] Evento a ser postado.
Retorna:
sent
: [boolean] Se o evento foi enviado com sucesso.err_msg
: [string] Mensagem em caso de erro.
Cria um timer que expira após time
(em milisegundos) e então chama a
função f
.
Recebe:
time
: [number] Tempo em milisegundos.f
: [function] Função de retomada.
Retorna:
unreg
: [function] Função que, quando chamada, cancela o timer.
A assinatura de f é simples, sem parâmetros:
function f () end
O valor de 0
milisegundos é válido. Neste caso, f
é chamada assim que
possível (nunca imediatamente, dentro de um tratador de eventos).
Assim como tratadores de eventos, a função f
deve retornar rapidamente,
pois enquanto ela é executada nenhum evento é tratado.
Retorna o número de milisegundos decorridos desde o início da aplicação.