NAME
Bot::ChatBots::Telegram::Keyboard - Telegram Keyboard handler
SYNOPSIS
use Bot::ChatBots::Telegram::Keyboard qw< keyboard >;
# `keyboard` is a wrapper around constructor
# Bot::ChatBots::Telegram::Keyboard->new()
my $keyboard = keyboard(
[ # first row of the keyboard
{
text => "Happyness", # shown in the button
_value => '/happyness', # substituted upon call
},
{
text => "+1", # shown in the button
_value => '/happyness +1', # substituted upon call
},
{
text => "+2", # shown in the button
_value => '/happyness +2', # substituted upon call
},
{
text => "+3", # shown in the button
_value => '/happyness +3', # substituted upon call
},
],
[ # second row of the keyboard. Note that the second, third
# and fourth button hold the same labels as in the first
# row... which can be problematic because the label is
# what Telegram clients send back when the button is hit
{
text => "Relax", # shown in the button
_value => '/relax', # substituted upon call
},
{
text => "+1", # shown in the button
_value => '/relax +1', # substituted upon call
},
{
text => "+2", # shown in the button
_value => '/relax +2', # substituted upon call
},
{
text => "+3", # shown in the button
_value => '/relax +3', # substituted upon call
},
],
[
{
text => 'Location', # shown in the button
request_location => \1, # flag for Telegram
},
{
text => 'Help', # shown in the button
_value => '/help', # substituted upon call
}
],
# ...
);
# Suppose you have a Bot::ChatBots::Telegram::Sender now...
$sender->send_message(
text => "Here's your keyboard",
chat_id => $chat_id, # whatever it is...
reply_markup => {
resize_keyboard => \1,
keyboard => $keyboard->displayable,
},
);
# You're setting the Bot::ChatBots::Telegram::WebHook and need a
# processor...
sub processor {
my $record = shift;
my $command = $keyboard->get_value($record);
# ...
return $record;
}
DESCRIPTION
Telegram custom keyboards are a handy feature to provide a cleaner interface to your users. They're pretty basic: you set up the keyboard with some text on a few buttons (including emojis) and whenever the user pushes the button, that text is sent back to your bot.
While effective and amazing, this can prove stiff when compared to e.g. how HTML handles buttons. In HTML, you can independently set what the user sees and what's sent to the server (in the form of a value
). This allows you to:
easily manage translations without changing the behavior of the button, and
have buttons with the same labels trigger different actions, e.g. based on where they are placed.
As an example of the latter case, consider a keyboard in which you want to track two different variables, Happyness and Relax. You want to provide a button for showing their current value, and some buttons to increase those values. It might be something like this:
+-----------+-----------+-----------+-----------+
| Happyness | +1 | +2 | +3 |
+-----------+-----------+-----------+-----------+
| Relax | +1 | +2 | +3 |
+-----------+-----------+-----------+-----------+
It's clear from the context what the different +1
, +2
and +3
mean, but they can't be shown like this because they will just send their label without providing any hint about the context.
This module defines a class to help you with this. It allows you to define a Telegram keyboard that allows tracking each button individually and associate a translation _value
to it, so that when it is received you can get that _value
back, and e.g. use it as if it had been written by the client in the first place.
The button tracking is accomplished by appending to the label of each keyboard button a unique sequence of zero-width Unicode characters. This allows having different labels for each of them, while at the same time ensuring that they look exactly the same when printed. Luckily, Telegram clients as of February 2017 send the whole sequence instead of just the visible, non-zero-width characters.
FUNCTIONS
To ease with the creation of keyboards, a helper function is available:
keyboard
my $keyboard = keyboard(@keyboard_rows); # OR
$keyboard = keyboard(\@keyboard_rows); # OR
$keyboard = keyboard(id => $id, keyboard => \@rows);
This is just a wrapper around the constructor. A such, it can throw exeptions, see "DIAGNOSTICS" for the details.
ACCESSORS
displayable
my $kbd_for_client = $obj->displayable;
Read-only accessor for a rendition of the keyboard that is suitable for sending to the client. Any button that originally contained a _value
has this field removed (as it's not in Telegram's specification) and its label is changed with a suitable zero-width tracking code. As such, it can be used like this:
$sender->send_message(
text => "Here's your keyboard",
chat_id => $chat_id, # whatever it is...
reply_markup => {
resize_keyboard => \1,
keyboard => $obj->displayable,
},
);
METHODS
get_value
my $text = $obj->get_value($record); # OR
$text = $obj->get_value($record->{payload}); # OR
$text = $obj->get_value($record->{payload}{text});
Get the command string from an input record (e.g. coming in a webhook). Returns the _value
fields content in the keyboard definition if such a command tracker is found in the input, undef
otherwise.
The input can be:
a record, i.e. something with a
payload
field inside. In this case, whatever is in thetext
subfield is taken;a payload, in which case a
text
field inside is taken;a plain string.
If the input is a hash reference but neither payload
nor text
are found, it is assumed to be a payload hash without a text and the text will be assumed to be undef
. If you want to have 100% of control, always pass a plain string.
get_keyboard_id
my $id = $obj_or_class->get_keyboard_id($record); # OR
$id = $obj_or_class->get_keyboard_id($record->{payload}); # OR
$id = $obj_or_class->get_keyboard_id($record->{payload}{text});
Get the keyboard identifier from an input record (e.g. coming from a webhook). Returns an unsigned integer value. You can set this value for a keyboard via option keyboard_id
during construction, see "new".
The input can be the same as in "get_value". Note that this method can be used as either an instance or a class method, with the same result.
new
my $kbd = Bot::ChatBots::Telegram::Keyboard->new(%args); # OR
$kbd = Bot::ChatBots::Telegram::Keyboard->new(\%args);
Constructor. It accepts the following parameters:
keyboard
-
an array of arrays of hashes, just like a normal Telegram keyboard. As an extension, each keyboard button can additionally support a
_value
parameter, holding the real value to associate to the button (which can be retrieved via "get_value"). id
-
an unsigned integer to enable distinguishing different keyboards, its value can be retrieved via "get_keyboard_id" from a received record. Defaults to
0
.
This method can throw exceptions if the input is not good, see "DIAGNOSTICS" for the details.
DIAGNOSTICS
The following exceptions can be thrown by this class via Ouch, all with code 500
:
no input keyboard
-
the constructor was not provided the requird
keyboard
input parameter. See "new". get_value(): pass either hash references or plain scalars
-
method "get_value" can accept either a plain scalar (used as text) or a hash reference where the text will be searched. Everything else leads to this exception.
invalid input keyboard, not an ARRAY
invalid input keyboard, not an AoA
invalid input keyboard, not an AoAoH
-
constructor "new" accepts a single input parameter
keyboard
that MUST be a reference to an array of arrays of hashes. The first exception is thrown if the input is not an array, the second if any item inside the outer array is not an array itself, the third if the items in each row are not hashes.
SEE ALSO
AUTHOR
Flavio Poletti <polettix@cpan.org>
COPYRIGHT AND LICENSE
Copyright (C) 2016, 2018 by Flavio Poletti <polettix@cpan.org>
This module is free software. You can redistribute it and/or modify it under the terms of the Artistic License 2.0.
This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose.