Merge remote-tracking branch 'old-unl0kr/master' into unl0kr

This commit is contained in:
Johannes Marbach 2024-01-02 20:30:00 +01:00
commit 62e2108d0a
82 changed files with 22939 additions and 1 deletions

2
.gitignore vendored
View file

@ -1,4 +1,4 @@
*.o
Pipfile.lock
/_build
_build
.vscode

73
CHANGELOG.md Normal file
View file

@ -0,0 +1,73 @@
# Changelog
## Unreleased
Nothing at the moment
## 2.0.3 (2023-12-19)
- fix: Clear the screen before exiting (#50)
- feat: Add extra top row for numbers & symbols, drop duplicative label (#49)
- fix: Stopgap solution for slow react on hardware keyboard (#36, thanks @jane400)
## 2.0.2 (2023-10-07)
- fix: Prefer keyboard capability when input devices offer both keyboard and pointer (!24, thanks @TravMurav)
## 2.0.1 (2023-10-01)
- fix: Keyboard layout selection is broken (#45, thanks @Jarrah)
## 2.0.0 (2023-07-28)
- feat: Add man page (#6, thanks @Jarrah)
- feat!: Enable direct rendering
- feat: Add quirk for forcing fbdev refresh (#34, thanks @calebccff)
- fix: Fix slow react on hardware keyboard (#36, thanks @calebccff)
## 1.0.0 (2023-03-14)
- feat!: Handle input device connection/disconnection at runtime; adds new dependency libudev (#38)
- feat: Update lv_drivers to git master (2023-03-14)
- feat: Update lvgl to v8.3 (2023-03-14)
- feat!: Deprecate -c CLI option and add support for reading from /etc/unl0kr.conf.d directory
- fix: Print correct version in logs
- feat: Add config options to enable terminal quirks (#34)
## 0.3.1 (2023-02-25)
- fix: Changed Color of the cursor in breeze_dark to be able to see it (#39)
## 0.3.0 (2022-11-13)
- feat: Update lvgl & lv_drivers to git master (2022-10-16)
- feat: Add config option to customise bullet character (#17)
- fix: Use actual screen DPI value to compute sizes and spaces
- feat: Allow shutting down the device on inactivity
- fix: Disable terminal keyboard while unl0kr is running
- feat: Extend --geometry flag to also accept display offsets
- fix: Swap order of KDSKBMODE and KDSETMODE to prevent blank screen (#34)
- fix: Increase maximum textarea width to prevent clipping on OnePlus 6 (#33)
- fix: Disable unused fonts, widgets and drivers (#13)
- fix: Rework pmOS theme to allow for more key space (#30)
## 0.2.0 (2022-05-27)
- fix: Make meson actually install things (thanks @craftyguy)
- feat!: Make en-US the default layout
- fix: Use correct pointer type in memset to avoid segfault
- feat: Set correct version in meson.build
- feat: Add postmarketOS theme (thanks @dylanvanassche)
- feat: Handle physical return key (#19)
- fix: Avoid TTY cursor blinking (#26)
- fix: Specify `check: true` when running external commands from meson (#23)
- feat!: Hide partition name (#27)
- fix: Prevent scrolling when keyboard hides (#21)
- feat!: Do not show last typed character when typing (#25)
- feat: Update lvgl & lv_drivers to git master (2022-02-21)
- feat: allow runtime selection of the lvgl display driver ("backend")
- feat: allow overriding dpi with the --dpi command line parameter
## 0.1.0 (2021-11-15)
Initial release

674
COPYING Normal file
View file

@ -0,0 +1,674 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<https://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.

Binary file not shown.

BIN
OpenSans-Regular.ttf Normal file

Binary file not shown.

222
README.md Normal file
View file

@ -0,0 +1,222 @@
Unl0kr
======
Disk unlocker for the initramfs based on [LVGL].
[[_TOC_]]
# About
Unl0kr is an [osk-sdl] clone written in [LVGL] and rendering directly to the Linux framebuffer. As a result, it doesn't depend on GPU hardware acceleration.
For some background on how unl0kr came to be, see postmarketOS/osk-sdl#121.
# Status
We are en route to v1 which aims at providing a useable, visually pleasant application including [osk-sdl]'s most essential features. For details about the current status, see the [v1 milestone]. You may also browse the full list of [open issues] to get an idea of what's planned beyond v1.
Here are a few highlights of what already works:
- Password-entry UI including on-screen keyboard on the framebuffer
- Input device discovery (both at start-up and afterwards) for keyboards, mice, trackpads and touch screens
- On-screen keyboard control via:
- One or more mice / trackpads (including cursor)
- One or more hardware keyboards (including support for different layouts using XKB)
- Touchscreen (tested on PinePhone)
- Switching on-screen keyboard layout at runtime (currently supported layouts: de, es, fr, us)
- Toggling on-screen keyboard with slide in/out animation
- Switching between light and dark theme at runtime
- Disclosing and hiding entered password at runtime
- Shutting down the device via a soft button
For a growing collection of demo videos, see the [wiki]. Screenshots of the currently available themes may be found in the [screenshots] folder.
<img src="screenshots/breezy-light-540x960.png" alt="540x960" height="300"/>
<img src="screenshots/breezy-dark-540x960.png" alt="540x960" height="300"/>
<br>
<img src="screenshots/pmos-light-800x480.png" alt="800x480" height="300"/>
<img src="screenshots/pmos-dark-800x480.png" alt="800x480" height="300"/>
# Usage
A man page is planned to be added with #6. For the time being, you can get an overview of available command line options by running unl0kr with the `-h` or `--help` argument.
```
$ unl0kr --help
Usage: unl0kr [OPTION]
Unl0kr values the CRYPTTAB_TRIED variable. Upon completion, the entered
password is printed to STDOUT. All other output happens on STDERR.
Mandatory arguments to long options are mandatory for short options too.
-C, --config-override Path to a config override file. Can be supplied
multiple times. Config files are merged in the
following order:
* /etc/unl0kr.conf
* /etc/unl0kr.conf.d/* (alphabetically)
* Override files (in supplied order)
-g, --geometry=NxM[@X,Y] Force a display size of N horizontal times M
vertical pixels, offset horizontally by X
pixels and vertically by Y pixels
-d --dpi=N Override the display's DPI value
-h, --help Print this message and exit
-v, --verbose Enable more detailed logging output on STDERR
-V, --version Print the unl0kr version and exit
```
For an example configuration file, see [unl0kr.conf].
# Development
## Dependencies
- [inih]
- [lvgl] (git submodule / linked statically)
- [lv_drivers] (git submodule / linked statically)
- [squeek2lvgl] (git submodule / linked statically)
- [libinput]
- [libudev]
- [libxkbcommon]
- [libdrm] (optional, required for the DRM backend)
- evdev kernel module
- [scdoc] (for generating the man page)
## Building & running
Some of unl0kr's dependencies are included as git submodules in this repository. You can clone the repository and initialise the submodules with
```
$ git clone https://gitlab.com/cherrypicker/unl0kr.git
$ cd unl0kr
$ git submodule init
$ git submodule update
```
When pulling changes from the remote later, either use `git pull --recurse-submodules` or manually run `git submodule update` as needed after pulling.
Once you have the sources, you can build the app and run it in a VT. Unless your user account has special privileges, `sudo` will be needed to access input device files.
```
$ meson _build
$ meson compile -C _build
$ sudo chvt 2
$ sudo ./_build/unl0kr
```
With meson <0\.55 use `ninja` instead of `meson compile`\.
## Valgrind
> Using C without Valgrind is like skydiving without a parachute.
To be able to use Valgrind, add `default_options: ['optimization=g']` in the `project` section of `meson.build` and rebuild. Afterwards you can run the application with Valgrind's leaks check enabled via
```
sudo valgrind --leak-check=yes ./_build/unl0kr
```
## Backends
Unl0kr supports multiple LVGL display drivers, referred to as "backends".
- fbdev
- drm (optional)
The active backend can be selected via the `general.backend` option in the configuration file.
Note that if [libdrm] is installed, the DRM backend will be compiled in automatically. It's possible to prevent this behaviour by passing the `with-drm` option to meson.
```
$ meson _build -Dwith-drm=disabled
```
## Fonts
In order to work with [LVGL], fonts need to be converted to bitmaps, stored as C arrays. Unl0kr currently uses a combination of the [OpenSans] font for text and the [FontAwesome] font for pictograms. For both fonts only limited character ranges are included to reduce the binary size. To (re)generate the C file containing the combined font, run the following command
```
$ ./regenerate-fonts.sh
```
Below is a short explanation of the different unicode ranges used above.
- [OpenSans]
- Basic Latin (`0x0020-0x007F`)
- Latin-1 supplement (`0x00A0-0x00FF`)
- Latin extended A (`0x0100-0x017F`)
- Greek and Coptic (`0x0370-0x03FF`)
- General punctuation (`0x2000-0x206F`)
- Currency symbols (`0x20A0-0x20CF`)
- Mathematical operators (`0x2200-0x22FF`)
- [FontAwesome]
- Standard `LV_SYMBOL_*` glyphs (`0xF001,0xF008,0xF00B,0xF00C,0xF00D,0xF011,0xF013,0xF015,0xF019,0xF01C,0xF021,0xF026,0xF027,0xF028,0xF03E,0xF0E0,0xF304,0xF043,0xF048,0xF04B,0xF04C,0xF04D,0xF051,0xF052,0xF053,0xF054,0xF067,0xF068,0xF06E,0xF070,0xF071,0xF074,0xF077,0xF078,0xF079,0xF07B,0xF093,0xF095,0xF0C4,0xF0C5,0xF0C7,0xF0C9,0xF0E7,0xF0EA,0xF0F3,0xF11C,0xF124,0xF158,0xF1EB,0xF240,0xF241,0xF242,0xF243,0xF244,0xF287,0xF293,0xF2ED,0xF55A,0xF7C2,0xF8A2`)
- [adjust](https://fontawesome.com/v5/icons/adjust) (`0xF042`)
- [arrow-alt-circle-up](https://fontawesome.com/v5/icons/arrow-alt-circle-up) (`0xF35B`)
- [chevron-left](https://fontawesome.com/v5/icons/chevron-left) (`0xF053`)
## Keyboard layouts
Unl0kr uses [squeekboard layouts] converted to C via [squeek2lvgl]. To regenerate the layouts, ensure that you have pipenv installed (e.g. via `pip install --user pipenv`) and then run
```
$ ./regenerate-layouts.sh
```
from the root of the repository.
## Generating screenshots
To generate screenshots in a variety of common sizes, build unl0kr and then run
```
$ sudo ./regenerate-screenshots _build/unl0kr
```
where `_build/unl0kr` is the location of the unl0kr binary. Note that you may have to adapt some of the settings inside the script depending on the device you're using to generate the screenshots.
## Screen recording
For demonstration purposes you can record the framebuffer device, e.g. with ffmpeg:
```
$ sudo ffmpeg -f fbdev -i /dev/fb0 -r 24 -c:v libx264 -b:v 500k demo.avi
```
# Acknowledgements
The [lv_port_linux_frame_buffer] project served as a starting point for the codebase.
The mouse cursor image was taken from [lv_sim_emscripten].
# License
Unl0kr is licensed under the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
The [OpenSans] font is licensed under the Apache License 2.0.
The [FontAwesome] font is licensed under the Open Font License version 1.1.
[FontAwesome]: https://fontawesome.com
[LVGL]: https://lvgl.io
[OpenSans]: https://fonts.google.com/specimen/Open+Sans
[adjust]: https://fontawesome.com/v5.15/icons/adjust?style=solid
[arrow-alt-circle-up]: https://fontawesome.com/v5.15/icons/arrow-alt-circle-up?style=solid
[inih]: https://github.com/benhoyt/inih
[libinput]: https://gitlab.freedesktop.org/libinput/libinput
[libudev]: https://github.com/systemd/systemd/tree/main/src/libudev
[libxkbcommon]: https://github.com/xkbcommon/libxkbcommon
[libdrm]: https://gitlab.freedesktop.org/mesa/drm
[lv_drivers]: https://github.com/lvgl/lv_drivers
[lv_port_linux_frame_buffer]: https://github.com/lvgl/lv_port_linux_frame_buffer
[lv_sim_emscripten]: https://github.com/lvgl/lv_sim_emscripten/blob/master/mouse_cursor_icon.c
[lvgl]: https://github.com/lvgl/lvgl
[online font converter]: https://lvgl.io/tools/fontconverter
[open issues]: https://gitlab.com/cherrypicker/unl0kr/-/issues
[osk-sdl]: https://gitlab.com/postmarketOS/osk-sdl
[scdoc]: https://git.sr.ht/~sircmpwn/scdoc
[screenshots]: ./screenshots
[squeek2lvgl]: https://gitlab.com/cherrypicker/squeek2lvgl
[squeekboard layouts]: https://gitlab.gnome.org/World/Phosh/squeekboard/-/tree/master/data/keyboards
[unl0kr.conf]: ./unl0kr.conf
[v1 milestone]: https://gitlab.com/cherrypicker/unl0kr/-/milestones/1
[wiki]: https://gitlab.com/cherrypicker/unl0kr/-/wikis/home

21
archive.sh Executable file
View file

@ -0,0 +1,21 @@
#!/bin/bash
version=$(git describe --exact-match --tags HEAD || git rev-parse HEAD)
archive=unl0kr-${version}.tar.gz
echo "Archiving repository with submodules..."
git-archive-all ${archive}
echo "Uploading archive to GitLab..."
response=$(curl --request POST \
--header "PRIVATE-TOKEN: $1" \
--form "file=@${archive}" \
"https://gitlab.com/api/v4/projects/29322771/uploads")
path=$(echo "${response}" | jq -r .full_path)
echo "${response}"
echo
echo "https://gitlab.com${path}"
rm -f "${archive}"

48
backends.c Normal file
View file

@ -0,0 +1,48 @@
/**
* Copyright 2022 Eugenio Paolantonio (g7)
*
* This file is part of unl0kr, hereafter referred to as the program.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "backends.h"
#include <string.h>
/**
* Public interface
*/
const char *ul_backends_backends[] = {
#if USE_FBDEV
"fbdev",
#endif /* USE_FBDEV */
#if USE_DRM
"drm",
#endif /* USE_DRM */
NULL
};
ul_backends_backend_id_t ul_backends_find_backend_with_name(const char *name) {
for (int i = 0; ul_backends_backends[i] != NULL; ++i) {
if (strcmp(ul_backends_backends[i], name) == 0) {
ul_log(UL_LOG_LEVEL_VERBOSE, "Found backend: %s\n", name);
return i;
}
}
ul_log(UL_LOG_LEVEL_WARNING, "Backend %s not found\n", name);
return UL_BACKENDS_BACKEND_NONE;
}

50
backends.h Normal file
View file

@ -0,0 +1,50 @@
/**
* Copyright 2022 Eugenio Paolantonio (g7)
*
* This file is part of unl0kr, hereafter referred to as the program.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef UL_BACKENDS_H
#define UL_BACKENDS_H
#include "lv_drv_conf.h"
#include "log.h"
/* NOTE: Only UL_BACKENDS_BACKEND_NONE is ought to have an explicit value assigned */
typedef enum {
UL_BACKENDS_BACKEND_NONE = -1,
#if USE_FBDEV
UL_BACKENDS_BACKEND_FBDEV,
#endif /* USE_FBDEV */
#if USE_DRM
UL_BACKENDS_BACKEND_DRM,
#endif /* USE_DRM */
} ul_backends_backend_id_t;
/* Backends */
extern const char *ul_backends_backends[];
/**
* Find the first backend with a given name.
*
* @param name backend name
* @return ID of the first matching backend or UL_BACKENDS_BACKEND_NONE if no backend matched
*/
ul_backends_backend_id_t ul_backends_find_backend_with_name(const char *name);
#endif /* UL_BACKENDS_H */

147
command_line.c Normal file
View file

@ -0,0 +1,147 @@
/**
* Copyright 2021 Johannes Marbach
*
* This file is part of unl0kr, hereafter referred to as the program.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "command_line.h"
#include "log.h"
#include "unl0kr.h"
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
/**
* Static prototypes
*/
/**
* Initialise a command line options struct with default values and exit on failure.
*
* @param opts pointer to the options struct
*/
static void init_opts(ul_cli_opts *opts);
/**
* Output usage instructions.
*/
static void print_usage();
/**
* Static functions
*/
static void init_opts(ul_cli_opts *opts) {
opts->num_config_files = 0;
opts->config_files = NULL;
opts->hor_res = -1;
opts->ver_res = -1;
opts->x_offset = 0;
opts->y_offset = 0;
opts->verbose = false;
}
static void print_usage() {
fprintf(stderr,
/*-------------------------------- 78 CHARS --------------------------------*/
"Usage: unl0kr [OPTION]\n"
"\n"
"Unl0kr values the CRYPTTAB_TRIED variable. Upon completion, the entered\n"
"password is printed to STDOUT. All other output happens on STDERR.\n"
"\n"
"Mandatory arguments to long options are mandatory for short options too.\n"
" -C, --config-override Path to a config override file. Can be supplied\n"
" multiple times. Config files are merged in the\n"
" following order:\n"
" * /etc/unl0kr.conf\n"
" * /etc/unl0kr.conf.d/* (alphabetically)\n"
" * Override files (in supplied order)\n"
" -g, --geometry=NxM[@X,Y] Force a display size of N horizontal times M\n"
" vertical pixels, offset horizontally by X\n"
" pixels and vertically by Y pixels\n"
" -d --dpi=N Override the display's DPI value\n"
" -h, --help Print this message and exit\n"
" -v, --verbose Enable more detailed logging output on STDERR\n"
" -V, --version Print the unl0kr version and exit\n");
/*-------------------------------- 78 CHARS --------------------------------*/
}
/**
* Public functions
*/
void ul_cli_parse_opts(int argc, char *argv[], ul_cli_opts *opts) {
init_opts(opts);
struct option long_opts[] = {
{ "config-override", required_argument, NULL, 'C' },
{ "geometry", required_argument, NULL, 'g' },
{ "dpi", required_argument, NULL, 'd' },
{ "help", no_argument, NULL, 'h' },
{ "verbose", no_argument, NULL, 'v' },
{ "version", no_argument, NULL, 'V' },
{ NULL, 0, NULL, 0 }
};
int opt, index = 0;
while ((opt = getopt_long(argc, argv, "c:C:g:d:hvV", long_opts, &index)) != -1) {
switch (opt) {
case 'C':
opts->config_files = realloc(opts->config_files, (opts->num_config_files + 1) * sizeof(char *));
if (!opts->config_files) {
ul_log(UL_LOG_LEVEL_ERROR, "Could not allocate memory for config file paths");
exit(EXIT_FAILURE);
}
opts->config_files[opts->num_config_files] = optarg;
opts->num_config_files++;
break;
case 'g':
if (sscanf(optarg, "%ix%i@%i,%i", &(opts->hor_res), &(opts->ver_res), &(opts->x_offset), &(opts->y_offset)) != 4) {
if (sscanf(optarg, "%ix%i", &(opts->hor_res), &(opts->ver_res)) != 2) {
ul_log(UL_LOG_LEVEL_ERROR, "Invalid geometry argument \"%s\"\n", optarg);
exit(EXIT_FAILURE);
}
}
break;
case 'd':
if (sscanf(optarg, "%i", &(opts->dpi)) != 1) {
ul_log(UL_LOG_LEVEL_ERROR, "Invalid dpi argument \"%s\"\n", optarg);
exit(EXIT_FAILURE);
}
break;
case 'h':
print_usage();
exit(EXIT_SUCCESS);
case 'v':
opts->verbose = true;
break;
case 'V':
fprintf(stderr, "unl0kr %s\n", UL_VERSION);
exit(0);
default:
print_usage();
exit(EXIT_FAILURE);
}
}
}

57
command_line.h Normal file
View file

@ -0,0 +1,57 @@
/**
* Copyright 2021 Johannes Marbach
*
* This file is part of unl0kr, hereafter referred to as the program.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef UL_COMMAND_LINE_H
#define UL_COMMAND_LINE_H
#include <stdbool.h>
/**
* Options parsed from command line arguments
*/
typedef struct {
/* Number of config files */
int num_config_files;
/* Paths of config file */
const char **config_files;
/* Horizontal display resolution */
int hor_res;
/* Vertical display resolution */
int ver_res;
/* Horizontal display offset */
int x_offset;
/* Vertical display offset */
int y_offset;
/* DPI */
int dpi;
/* Verbose mode. If true, provide more detailed logging output on STDERR. */
bool verbose;
} ul_cli_opts;
/**
* Parse command line arguments and exit on failure.
*
* @param argc number of provided command line arguments
* @param argv arguments as an array of strings
* @param opts pointer for writing the parsed options into
*/
void ul_cli_parse_opts(int argc, char *argv[], ul_cli_opts *opts);
#endif /* UL_COMMAND_LINE_H */

318
config.c Normal file
View file

@ -0,0 +1,318 @@
/**
* Copyright 2021 Johannes Marbach
*
* This file is part of unl0kr, hereafter referred to as the program.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "log.h"
#include "lvgl/lvgl.h"
#include <dirent.h>
#include <ini.h>
#include <stdlib.h>
#include "squeek2lvgl/sq2lv.h"
/**
* Static prototypes
*/
/**
* Compares two strings from opaque types.
*
* @param a first string as void pointer
* @param b second string as void pointer
* @return a positive integer if a > b, a negative integer if a < b and 0 otherwise
*/
static int compare_strings(const void* a, const void* b);
/**
* Checks whether a string ends with a suffix
*
* @param string string to check
* @param suffix suffix to compare to
* @return true if the suffix matches at the end of the string, false otherwise
*/
static bool string_ends_with(const char *string, const char *suffix);
/**
* Non-recursively searches a directory for configuration files.
*
* @param path folder to search in
* @param found pointer to write found configuration file names into (to be freed by the caller)
* @param num_found pointer to write number of found files into
*/
static void find_files(const char *path, char ***found, int *num_found);
/**
* Handle parsing events from INIH.
*
* @param user_data pointer to user data
* @param section current section name
* @param key option key
* @param value option value
* @return 0 on error, non-0 otherwise
*/
static int parsing_handler(void* user_data, const char* section, const char* key, const char* value);
/**
* Attempt to parse a boolean value.
*
* @param value string to parse
* @param result pointer to write result into if parsing is successful
* @return true on success, false otherwise
*/
static bool parse_bool(const char *value, bool *result);
/**
* Static functions
*/
static int compare_strings(const void* a, const void* b) {
return strcmp(*(const char**)a, *(const char**)b);
}
static bool string_ends_with(const char *string, const char *suffix) {
if (!string || !suffix || strlen(suffix) > strlen(string)) {
return false;
}
return strncmp(string + strlen(string) - strlen(suffix), suffix, strlen(suffix)) == 0;
}
static void find_files(const char *path, char ***found, int *num_found) {
/* Initialise output variables */
*found = NULL;
*num_found = 0;
/* Count length of directory path */
const int path_length = strlen(path);
/* Open directory */
DIR *d = opendir(path);
if (!d) {
ul_log(UL_LOG_LEVEL_WARNING, "Could not read contents of folder %s", path);
return;
}
/* Loop over directory contents */
struct dirent *dir;
while ((dir = readdir(d)) != NULL) {
/* Ignore anything except for .conf files */
if (dir->d_type != DT_REG || !string_ends_with(dir->d_name, ".conf")) {
continue;
}
/* Grow output array */
char **tmp = realloc(*found, (*num_found + 1) * sizeof(char *));
if (!tmp) {
ul_log(UL_LOG_LEVEL_ERROR, "Could not reallocate memory for configuration file paths");
break;
}
*found = tmp;
/* Extract file name and length */
char *name = dir->d_name;
int name_length = strlen(name);
/* Allocate memory for full path */
char *found_path = malloc(path_length + name_length + 2); /* +1 for path separator and null terminator, respectively */
if (!found_path) {
ul_log(UL_LOG_LEVEL_ERROR, "Could not allocate memory for configuration file path");
break;
}
/* Build full path */
memcpy(found_path, path, path_length);
found_path[path_length] = '/';
memcpy(found_path + path_length + 1, dir->d_name, name_length + 1); /* +1 for path separator and null terminator, respectively */
/* Store file path */
(*found)[*num_found] = found_path;
*num_found += 1;
}
/* Close directory */
closedir(d);
}
static int parsing_handler(void* user_data, const char* section, const char* key, const char* value) {
ul_config_opts *opts = (ul_config_opts *)user_data;
if (strcmp(section, "general") == 0) {
if (strcmp(key, "animations") == 0) {
if (parse_bool(value, &(opts->general.animations))) {
return 1;
}
} else if (strcmp(key, "backend") == 0) {
ul_backends_backend_id_t id = ul_backends_find_backend_with_name(value);
if (id != UL_BACKENDS_BACKEND_NONE) {
opts->general.backend = id;
return 1;
}
} else if (strcmp(key, "timeout") == 0) {
/* Use a max ceiling of 60 minutes (3600 secs) */
opts->general.timeout = (uint16_t)LV_MIN(strtoul(value, (char **)NULL, 10), 3600);
return 1;
}
} else if (strcmp(section, "keyboard") == 0) {
if (strcmp(key, "autohide") == 0) {
if (parse_bool(value, &(opts->keyboard.autohide))) {
return 1;
}
} else if (strcmp(key, "layout") == 0) {
sq2lv_layout_id_t id = sq2lv_find_layout_with_short_name(value);
if (id != SQ2LV_LAYOUT_NONE) {
opts->keyboard.layout_id = id;
return 1;
}
} else if (strcmp(key, "popovers") == 0) {
if (parse_bool(value, &(opts->keyboard.popovers))) {
return 1;
}
}
} else if (strcmp(section, "textarea") == 0) {
if (strcmp(key, "obscured") == 0) {
if (parse_bool(value, &(opts->textarea.obscured))) {
return 1;
}
} else if (strcmp(key, "bullet") == 0) {
char *bullet = strdup(value);
if (bullet) {
opts->textarea.bullet = bullet;
return 1;
}
}
} else if (strcmp(section, "theme") == 0) {
if (strcmp(key, "default") == 0) {
ul_themes_theme_id_t id = ul_themes_find_theme_with_name(value);
if (id != UL_THEMES_THEME_NONE) {
opts->theme.default_id = id;
return 1;
}
} else if (strcmp(key, "alternate") == 0) {
ul_themes_theme_id_t id = ul_themes_find_theme_with_name(value);
if (id != UL_THEMES_THEME_NONE) {
opts->theme.alternate_id = id;
return 1;
}
}
} else if (strcmp(section, "input") == 0) {
if (strcmp(key, "keyboard") == 0) {
if (parse_bool(value, &(opts->input.keyboard))) {
return 1;
}
} else if (strcmp(key, "pointer") == 0) {
if (parse_bool(value, &(opts->input.pointer))) {
return 1;
}
} else if (strcmp(key, "touchscreen") == 0) {
if (parse_bool(value, &(opts->input.touchscreen))) {
return 1;
}
}
} else if (strcmp(section, "quirks") == 0) {
if (strcmp(key, "fbdev_force_refresh") == 0) {
if (parse_bool(value, &(opts->quirks.fbdev_force_refresh))) {
return 1;
}
} else if (strcmp(key, "terminal_prevent_graphics_mode") == 0) {
if (parse_bool(value, &(opts->quirks.terminal_prevent_graphics_mode))) {
return 1;
}
} else if (strcmp(key, "terminal_allow_keyboard_input") == 0) {
if (parse_bool(value, &(opts->quirks.terminal_allow_keyboard_input))) {
return 1;
}
}
}
ul_log(UL_LOG_LEVEL_ERROR, "Ignoring invalid config value \"%s\" for key \"%s\" in section \"%s\"", value, key, section);
return 1; /* Return 1 (true) so that we can use the return value of ini_parse exclusively for file-level errors (e.g. file not found) */
}
static bool parse_bool(const char *value, bool *result) {
if (strcmp(value, "true") == 0) {
*result = true;
return true;
}
if (strcmp(value, "false") == 0) {
*result = false;
return true;
}
return false;
}
/**
* Public functions
*/
void ul_config_init_opts(ul_config_opts *opts) {
opts->general.animations = false;
opts->general.backend = ul_backends_backends[0] == NULL ? UL_BACKENDS_BACKEND_NONE : 0;
opts->general.timeout = 0;
opts->keyboard.autohide = true;
opts->keyboard.layout_id = SQ2LV_LAYOUT_US;
opts->keyboard.popovers = true;
opts->textarea.obscured = true;
opts->textarea.bullet = LV_SYMBOL_BULLET;
opts->theme.default_id = UL_THEMES_THEME_BREEZY_DARK;
opts->theme.alternate_id = UL_THEMES_THEME_BREEZY_LIGHT;
opts->input.keyboard = true;
opts->input.pointer = true;
opts->input.touchscreen = true;
opts->quirks.fbdev_force_refresh = false;
opts->quirks.terminal_prevent_graphics_mode = false;
opts->quirks.terminal_allow_keyboard_input = false;
}
void ul_config_parse_directory(const char *path, ul_config_opts *opts) {
/* Find files in directory */
char **found = NULL;
int num_found = 0;
find_files(path, &found, &num_found);
/* Sort and parse files */
qsort(found, num_found, sizeof(char *), compare_strings);
ul_config_parse_files((const char **)found, num_found, opts);
/* Free memory */
for (int i = 0; i < num_found; ++i) {
free(found[i]);
}
free(found);
}
void ul_config_parse_files(const char **files, int num_files, ul_config_opts *opts) {
for (int i = 0; i < num_files; ++i) {
ul_config_parse_file(files[i], opts);
}
}
void ul_config_parse_file(const char *path, ul_config_opts *opts) {
ul_log(UL_LOG_LEVEL_VERBOSE, "Parsing config file %s", path);
if (ini_parse(path, parsing_handler, opts) != 0) {
ul_log(UL_LOG_LEVEL_ERROR, "Ignoring invalid config file %s", path);
}
}

151
config.h Normal file
View file

@ -0,0 +1,151 @@
/**
* Copyright 2021 Johannes Marbach
*
* This file is part of unl0kr, hereafter referred to as the program.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef UL_CONFIG_H
#define UL_CONFIG_H
#include "backends.h"
#include "themes.h"
#include "sq2lv_layouts.h"
#include <stdbool.h>
#include <stdint.h>
/**
* General options
*/
typedef struct {
/* If true, use animations */
bool animations;
/* Backend to use */
ul_backends_backend_id_t backend;
/* Timeout (in seconds) - once elapsed, the device will shutdown. 0 (default) to disable */
uint16_t timeout;
} ul_config_opts_general;
/**
* Options related to the keyboard
*/
typedef struct {
/* If true, hide the keyboard on launch when a hardware keyboard is connected */
bool autohide;
/* Keyboard layout */
sq2lv_layout_id_t layout_id;
/* If true, display key popovers on press */
bool popovers;
} ul_config_opts_keyboard;
/**
* Options related to the password textarea
*/
typedef struct {
/* If true, disguise the entered text with dots */
bool obscured;
/* The character to use for disguising the entered text */
const char *bullet;
} ul_config_opts_textarea;
/**
* Options related to the theme
*/
typedef struct {
/* Default theme */
ul_themes_theme_id_t default_id;
/* Alternate theme */
ul_themes_theme_id_t alternate_id;
} ul_config_opts_theme;
/**
* Options related to input devices
*/
typedef struct {
/* If true and a keyboard device is connected, use it for input */
bool keyboard;
/* If true and a pointer device is connected, use it for input */
bool pointer;
/* If true and a touchscreen device is connected, use it for input */
bool touchscreen;
} ul_config_opts_input;
/**
* (Normally unneeded) quirky options
*/
typedef struct {
/* If true and using the framebuffer backend, force a refresh on every draw operation */
bool fbdev_force_refresh;
/* If true, do *not* switch terminal into graphics mode (will show terminal command prompt) */
bool terminal_prevent_graphics_mode;
/* If true, do *not* turn off terminal keyboard input (will show entered characters) */
bool terminal_allow_keyboard_input;
} ul_config_opts_quirks;
/**
* Options parsed from config file(s)
*/
typedef struct {
/* General options */
ul_config_opts_general general;
/* Options related to the keyboard */
ul_config_opts_keyboard keyboard;
/* Options related to the password textarea */
ul_config_opts_textarea textarea;
/* Options related to the theme */
ul_config_opts_theme theme;
/* Options related to input devices */
ul_config_opts_input input;
/* Options related to (normally unneeded) quirks */
ul_config_opts_quirks quirks;
} ul_config_opts;
/**
* Initialise a config options struct with default values.
*
* @param opts pointer to the options struct
*/
void ul_config_init_opts(ul_config_opts *opts);
/**
* Find configuration files in a directory and parse them in alphabetic order.
*
* @param path directory path
* @param opts pointer for writing the parsed options into
*/
void ul_config_parse_directory(const char *path, ul_config_opts *opts);
/**
* Parse one or more configuration files.
*
* @param files paths to configuration files
* @param num_files number of configuration files
* @param opts pointer for writing the parsed options into
*/
void ul_config_parse_files(const char **files, int num_files, ul_config_opts *opts);
/**
* Parse a configuration file.
*
* @param path path to configuration file
* @param opts pointer for writing the parsed options into
*/
void ul_config_parse_file(const char *path, ul_config_opts *opts);
#endif /* UL_CONFIG_H */

135
cursor.c Normal file
View file

@ -0,0 +1,135 @@
/**
* Copyright 2021 Johannes Marbach
*
* This file is part of unl0kr, hereafter referred to as the program.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "cursor.h"
/**
* Static variables
*/
/* Cursor image taken from https://github.com/lvgl/lv_sim_emscripten/blob/master/mouse_cursor_icon.c */
static const uint8_t data[] = {
#if LV_COLOR_DEPTH == 1 || LV_COLOR_DEPTH == 8
/*Pixel format: Alpha 8 bit, Red: 3 bit, Green: 3 bit, Blue: 2 bit*/
0x24, 0xb8, 0x24, 0xc8, 0x00, 0x13, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x49, 0xcc, 0xdb, 0xff, 0x49, 0xcc, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x49, 0xc8, 0xff, 0xff, 0xff, 0xff, 0x49, 0xe0, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x49, 0xcb, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0x6d, 0xf3, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x49, 0xcb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x92, 0xff, 0x00, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x49, 0xcb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x92, 0xff, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x49, 0xcb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb7, 0xff, 0x24, 0xab, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x49, 0xcb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdb, 0xff, 0x24, 0xbb, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x49, 0xcc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdb, 0xff, 0x49, 0xd8, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00,
0x49, 0xcc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6d, 0xef, 0x00, 0x4f, 0x00, 0x00,
0x49, 0xcc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x92, 0xff, 0x00, 0x6b,
0x49, 0xcc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdb, 0xff, 0x92, 0xf7, 0x92, 0xf8, 0x6e, 0xfb, 0x92, 0xf8, 0x6d, 0xff, 0x00, 0xb3,
0x49, 0xcc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdb, 0xff, 0x24, 0xb7, 0x00, 0x1b, 0x00, 0x14, 0x00, 0x13, 0x00, 0x0c, 0x25, 0x07,
0x49, 0xcc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6e, 0xf0, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x49, 0xcc, 0xff, 0xff, 0xff, 0xff, 0x49, 0xd8, 0x00, 0x78, 0x92, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xdb, 0xff, 0x00, 0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x6d, 0xd3, 0xff, 0xff, 0x6d, 0xef, 0x00, 0x34, 0x00, 0x00, 0x49, 0xc7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6d, 0xdc, 0x00, 0x14, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
0x49, 0xe0, 0x6d, 0xff, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x92, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb7, 0xff, 0x00, 0x78, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
0x00, 0x68, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x49, 0xd0, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0x6d, 0xd8, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0xb7, 0xff, 0xff, 0xff, 0x92, 0xff, 0x49, 0xac, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00,
0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x25, 0xd7, 0x49, 0xc7, 0x00, 0x47, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
#endif
#if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP == 0
/*Pixel format: Alpha 8 bit, Red: 5 bit, Green: 6 bit, Blue: 5 bit*/
0xc3, 0x18, 0xb8, 0xe4, 0x20, 0xc8, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x49, 0x4a, 0xcc, 0x96, 0xb5, 0xff, 0xc7, 0x39, 0xcc, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xe7, 0x39, 0xc8, 0xbf, 0xff, 0xff, 0xfb, 0xde, 0xff, 0x28, 0x42, 0xe0, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xe7, 0x39, 0xcb, 0x3d, 0xef, 0xff, 0xff, 0xff, 0xfc, 0x3d, 0xef, 0xff, 0xcb, 0x5a, 0xf3, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xe7, 0x39, 0xcb, 0x5d, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0x8e, 0x73, 0xff, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xe8, 0x41, 0xcb, 0x5d, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x51, 0x8c, 0xff, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x9c, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xe8, 0x41, 0xcb, 0x5d, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x14, 0xa5, 0xff, 0xa2, 0x10, 0xab, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x08, 0x42, 0xcb, 0x5d, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd7, 0xbd, 0xff, 0x04, 0x21, 0xbb, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x08, 0x42, 0xcc, 0x5d, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x59, 0xce, 0xff, 0xe8, 0x41, 0xd8, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x08, 0x42, 0xcc, 0x5d, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xe6, 0xff, 0xab, 0x5a, 0xef, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00,
0x08, 0x42, 0xcc, 0x5d, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbe, 0xf7, 0xff, 0xaf, 0x7b, 0xff, 0x00, 0x00, 0x6b,
0x28, 0x42, 0xcc, 0x5d, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7a, 0xd6, 0xff, 0x10, 0x84, 0xf7, 0xae, 0x73, 0xf8, 0x6e, 0x73, 0xfb, 0x8e, 0x73, 0xf8, 0xcb, 0x5a, 0xff, 0x61, 0x08, 0xb3,
0x28, 0x42, 0xcc, 0x7d, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x59, 0xce, 0xff, 0xa2, 0x10, 0xb7, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x14, 0x00, 0x00, 0x13, 0x00, 0x00, 0x0c, 0x45, 0x29, 0x07,
0x29, 0x4a, 0xcc, 0x5d, 0xef, 0xff, 0xff, 0xff, 0xff, 0xdb, 0xde, 0xff, 0xec, 0x62, 0xff, 0x1c, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0c, 0x63, 0xf0, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x29, 0x4a, 0xcc, 0xdf, 0xff, 0xff, 0x7d, 0xef, 0xff, 0x49, 0x4a, 0xd8, 0x00, 0x00, 0x78, 0x51, 0x8c, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x38, 0xc6, 0xff, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xcb, 0x5a, 0xd3, 0xdb, 0xde, 0xff, 0xec, 0x62, 0xef, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0xe7, 0x39, 0xc7, 0x5d, 0xef, 0xff, 0xff, 0xff, 0xff, 0xbe, 0xf7, 0xff, 0xaa, 0x52, 0xdc, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0xe8, 0x41, 0xe0, 0xaa, 0x52, 0xff, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x72, 0x94, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x96, 0xb5, 0xff, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x61, 0x08, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x68, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x69, 0x4a, 0xd0, 0x7d, 0xef, 0xff, 0xff, 0xff, 0xfc, 0xbe, 0xf7, 0xff, 0xaa, 0x52, 0xd8, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x75, 0xad, 0xff, 0xbf, 0xff, 0xff, 0x10, 0x84, 0xff, 0x86, 0x31, 0xac, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x41, 0x08, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x66, 0x31, 0xd7, 0xc7, 0x39, 0xc7, 0x00, 0x00, 0x47, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
#endif
#if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP != 0
/*Pixel format: Alpha 8 bit, Red: 5 bit, Green: 6 bit, Blue: 5 bit BUT the 2 color bytes are swapped*/
0x18, 0xc3, 0xb8, 0x20, 0xe4, 0xc8, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x4a, 0x49, 0xcc, 0xb5, 0x96, 0xff, 0x39, 0xc7, 0xcc, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x39, 0xe7, 0xc8, 0xff, 0xbf, 0xff, 0xde, 0xfb, 0xff, 0x42, 0x28, 0xe0, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x39, 0xe7, 0xcb, 0xef, 0x3d, 0xff, 0xff, 0xff, 0xfc, 0xef, 0x3d, 0xff, 0x5a, 0xcb, 0xf3, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x39, 0xe7, 0xcb, 0xef, 0x5d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0x73, 0x8e, 0xff, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x41, 0xe8, 0xcb, 0xef, 0x5d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8c, 0x51, 0xff, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0xd3, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x41, 0xe8, 0xcb, 0xef, 0x5d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa5, 0x14, 0xff, 0x10, 0xa2, 0xab, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x42, 0x08, 0xcb, 0xef, 0x5d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbd, 0xd7, 0xff, 0x21, 0x04, 0xbb, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x42, 0x08, 0xcc, 0xef, 0x5d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0x59, 0xff, 0x41, 0xe8, 0xd8, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x42, 0x08, 0xcc, 0xef, 0x5d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe6, 0xfc, 0xff, 0x5a, 0xab, 0xef, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00,
0x42, 0x08, 0xcc, 0xef, 0x5d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xbe, 0xff, 0x7b, 0xaf, 0xff, 0x00, 0x00, 0x6b,
0x42, 0x28, 0xcc, 0xef, 0x5d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd6, 0x7a, 0xff, 0x84, 0x10, 0xf7, 0x73, 0xae, 0xf8, 0x73, 0x6e, 0xfb, 0x73, 0x8e, 0xf8, 0x5a, 0xcb, 0xff, 0x08, 0x61, 0xb3,
0x42, 0x28, 0xcc, 0xef, 0x7d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0x59, 0xff, 0x10, 0xa2, 0xb7, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x14, 0x00, 0x00, 0x13, 0x00, 0x00, 0x0c, 0x29, 0x45, 0x07,
0x4a, 0x29, 0xcc, 0xef, 0x5d, 0xff, 0xff, 0xff, 0xff, 0xde, 0xdb, 0xff, 0x62, 0xec, 0xff, 0xe7, 0x1c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x63, 0x0c, 0xf0, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x4a, 0x29, 0xcc, 0xff, 0xdf, 0xff, 0xef, 0x7d, 0xff, 0x4a, 0x49, 0xd8, 0x00, 0x00, 0x78, 0x8c, 0x51, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc6, 0x38, 0xff, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x5a, 0xcb, 0xd3, 0xde, 0xdb, 0xff, 0x62, 0xec, 0xef, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x39, 0xe7, 0xc7, 0xef, 0x5d, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xbe, 0xff, 0x52, 0xaa, 0xdc, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x41, 0xe8, 0xe0, 0x52, 0xaa, 0xff, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x94, 0x72, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb5, 0x96, 0xff, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x08, 0x61, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x68, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x4a, 0x69, 0xd0, 0xef, 0x7d, 0xff, 0xff, 0xff, 0xfc, 0xf7, 0xbe, 0xff, 0x52, 0xaa, 0xd8, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xe4, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0xad, 0x75, 0xff, 0xff, 0xbf, 0xff, 0x84, 0x10, 0xff, 0x31, 0x86, 0xac, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x08, 0x41, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x31, 0x66, 0xd7, 0x39, 0xc7, 0xc7, 0x00, 0x00, 0x47, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
#endif
#if LV_COLOR_DEPTH == 32
0x19, 0x19, 0x19, 0xb8, 0x1e, 0x1e, 0x1e, 0xc8, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x48, 0x48, 0x48, 0xcc, 0xb2, 0xb2, 0xb2, 0xff, 0x3a, 0x3a, 0x3a, 0xcc, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3b, 0x3b, 0x3b, 0xc8, 0xf6, 0xf6, 0xf6, 0xff, 0xdc, 0xdc, 0xdc, 0xff, 0x43, 0x43, 0x43, 0xe0, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3b, 0x3b, 0x3b, 0xcb, 0xe6, 0xe6, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xe5, 0xe5, 0xe5, 0xff, 0x59, 0x59, 0x59, 0xf3, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3c, 0x3c, 0x3c, 0xcb, 0xe9, 0xe9, 0xe9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf5, 0xf5, 0xf5, 0xff, 0x72, 0x72, 0x72, 0xff, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3d, 0x3d, 0x3d, 0xcb, 0xe9, 0xe9, 0xe9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8a, 0x8a, 0x8a, 0xff, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x99, 0x99, 0x00, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3e, 0x3e, 0x3e, 0xcb, 0xe9, 0xe9, 0xe9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa2, 0xa2, 0xa2, 0xff, 0x13, 0x13, 0x13, 0xab, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3f, 0x3f, 0x3f, 0xcb, 0xe9, 0xe9, 0xe9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb7, 0xb7, 0xb7, 0xff, 0x1f, 0x1f, 0x1f, 0xbb, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x41, 0x41, 0x41, 0xcc, 0xea, 0xea, 0xea, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xca, 0xca, 0xca, 0xff, 0x3d, 0x3d, 0x3d, 0xd8, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x41, 0x41, 0x41, 0xcc, 0xea, 0xea, 0xea, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xde, 0xde, 0xde, 0xff, 0x56, 0x56, 0x56, 0xef, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x00,
0x42, 0x42, 0x42, 0xcc, 0xea, 0xea, 0xea, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xf3, 0xf3, 0xff, 0x76, 0x76, 0x76, 0xff, 0x00, 0x00, 0x00, 0x6b,
0x43, 0x43, 0x43, 0xcc, 0xea, 0xea, 0xea, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xce, 0xce, 0xce, 0xff, 0x80, 0x80, 0x80, 0xf7, 0x74, 0x74, 0x74, 0xf8, 0x6d, 0x6d, 0x6d, 0xfb, 0x72, 0x72, 0x72, 0xf8, 0x57, 0x57, 0x57, 0xff, 0x0c, 0x0c, 0x0c, 0xb3,
0x44, 0x44, 0x44, 0xcc, 0xeb, 0xeb, 0xeb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xfb, 0xfb, 0xfb, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc9, 0xc9, 0xc9, 0xff, 0x13, 0x13, 0x13, 0xb7, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x0c, 0x29, 0x29, 0x29, 0x07,
0x45, 0x45, 0x45, 0xcc, 0xe8, 0xe8, 0xe8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd9, 0xd9, 0xd9, 0xff, 0x5e, 0x5e, 0x5e, 0xff, 0xe2, 0xe2, 0xe2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x62, 0x62, 0x62, 0xf0, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x45, 0x45, 0x45, 0xcc, 0xf9, 0xf9, 0xf9, 0xff, 0xec, 0xec, 0xec, 0xff, 0x4a, 0x4a, 0x4a, 0xd8, 0x00, 0x00, 0x00, 0x78, 0x8a, 0x8a, 0x8a, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0xc3, 0xc3, 0xff, 0x00, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x58, 0x58, 0x58, 0xd3, 0xd9, 0xd9, 0xd9, 0xff, 0x5e, 0x5e, 0x5e, 0xef, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x3b, 0x3b, 0xc7, 0xe9, 0xe9, 0xe9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf4, 0xf4, 0xf4, 0xff, 0x54, 0x54, 0x54, 0xdc, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
0x3e, 0x3e, 0x3e, 0xe0, 0x54, 0x54, 0x54, 0xff, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x8e, 0x8e, 0x8e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb0, 0xb0, 0xb0, 0xff, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x0c, 0x0c, 0x04, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x4c, 0x4c, 0x4c, 0xd0, 0xec, 0xec, 0xec, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xf4, 0xf4, 0xf4, 0xff, 0x53, 0x53, 0x53, 0xd8, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x1e, 0x1e, 0x00, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0xab, 0xab, 0xab, 0xff, 0xf6, 0xf6, 0xf6, 0xff, 0x80, 0x80, 0x80, 0xff, 0x31, 0x31, 0x31, 0xac, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x09, 0x09, 0x09, 0x03, 0x02, 0x02, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x2e, 0x2e, 0x2e, 0xd7, 0x38, 0x38, 0x38, 0xc7, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
#endif
};
/**
* Public interface
*/
const lv_img_dsc_t ul_cursor_img_dsc = {
.header.always_zero = 0,
.header.w = 14,
.header.h = 20,
.data_size = 280 * LV_IMG_PX_SIZE_ALPHA_BYTE,
.header.cf = LV_IMG_CF_TRUE_COLOR_ALPHA,
.data = data,
};

29
cursor.h Normal file
View file

@ -0,0 +1,29 @@
/**
* Copyright 2021 Johannes Marbach
*
* This file is part of unl0kr, hereafter referred to as the program.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BB_CURSOR_H
#define BB_CURSOR_H
#include "lvgl/lvgl.h"
/* Image description of the mouse cursor */
extern const lv_img_dsc_t ul_cursor_img_dsc;
#endif /* BB_CURSOR_H */

52
doc/unl0kr.1.scd Normal file
View file

@ -0,0 +1,52 @@
unl0kr(1) "unl0kr"
# NAME
UNL0KR - LVGL based initramfs disk unlocker
# SYNOPSIS
unl0kr [OPTION]
# DESCRIPTION
UNL0KR is a disk unlocker for the initramfs based on LVGL. By using LVGL and
rendering directly to the framebuffer it can work without relying on GPU
hardware acceleration. This makes for much more managable initramfs sizes.
Unl0kr utilises the CRYPTTAB_TRIED variable. Upon completion, the entered
password is printed to STDOUT. All other output happens on STDERR.
# OPTIONS
## Optional
*-C, --config-override*
Path to a config override file. Can be supplied multiple times. Config
files are merged in the following order:
- /etc/unl0kr.conf
- /etc/unl0kr.conf.d/\* (alphabetically)
- Override files (in supplied order)
*-g, --geometry=NxM[@X,Y]*
Force a display size of N horizontal times M vertical pixels, offset
horizontally by X pixels and vertically by Y pixels.
*-d --dpi=N*
Override the display's DPI value.
*-h, --help*
Print this message and exit.
*-v, --verbose*
Enable more detailed logging output on STDERR.
*-V, --version*
Print the unl0kr version and exit.
# EXAMPLES
*Decrypt /dev/sda1 to name "root"*
CRYPTTAB_SOURCE="/dev/sda1" CRYPTTAB_TRIED="0" unl0kr | cryptsetup --perf-no_read_workqueue --perf-no_write_workqueue open "/dev/sda1" root -
# SEE ALSO
*unl0kr.conf*(5)
# AUTHORS
*Undef* <debian@undef.tools>

101
doc/unl0kr.conf.5.scd Normal file
View file

@ -0,0 +1,101 @@
unl0kr(5) "unl0kr"
# NAME
UNL0KR - configuration file
# DESCRIPTION
UNL0KR expects a configuration file with options in the following format, with
one option/value pair per line:
```
[section]
<option>=<value>
```
The default configuration file is at /etc/unl0kr.conf, UNL0KR will use this
configuration file if present along with overrides placed in
/etc/unl0kr.conf.d/ and those specified with the -C option. All config files
will be merged in the following order:
- /etc/unl0kr.conf
- /etc/unl0kr.conf.d/ (alphabetically)
- Override files (in supplied order)
# OPTIONS
## General
*animations* = <true|false>
Enable or disable animations. Useful for slower devices. Default: false.
*backend* = <fbdev|drm>
The rendering backend to use. Default: fbdev.
*timeout* = <value>
The time in seconds before unl0kr will consider the entry a failure
and shutdown. Setting timeout to 0 disables this feature. Default: 0.
## Keyboard
*autohide* = <true|false>
Whether to automatically hide the keyboard when a hardware keyboard
is detected on launch. Default: true.
*layout* = <us|de|fr|...>
The default layout to use. Can be changed from the UI at runtime.
The available options are defined by the available keyboards at build time.
Default: us.
*popovers* = <true|false>
Enable or disable key press popovers showing the selected key.
default: true.
## Textarea
*obscured* = <true|false>
Whether the password in the text entry box can be read. Selectable in
the UI at runtime. Default: true.
*bullet* = <value>
The character that will be used to obscure the password. Default: bullet.
## Theme
*default* = <breezy-light|breezy-dark|pmos-light|pmos-dark>
Selects the default theme on boot. Can be changed at runtime to the
alternative theme. Default: breezy-dark.
*alternative* = <breezy-light|breezy-dark|pmos-light|pmos-dark>
Selects the alternative theme which the user can then choose on boot.
Default: breezy-light.
## Input
*keyboard* = <true|false>
Enable or disable the use of hardware keyboards. Default: true
*pointer* = <true|false>
Enable or disable the use of a hardware mouse or other pointing device.
Default: true.
*touchscreen* = <true|false>
Enable or disable the use of the touchscreen.
Default: true.
## Quirks
*fbdev_force_refresh* = <true|false>
If true and using the framebuffer backend, this triggers a display refresh
after every draw operation. This has a negative performance impact.
Default: false.
*terminal_prevent_graphics_mode* = <true|false>
If true, this avoids setting the terminal into graphics mode. This will
show the terminal command prompt. Default: false.
*terminal_allow_keyboard_input* = <true|false>
If true, this avoids turning off terminal keyboard input. This will show
your password on the terminal. Default: false.
# SEE ALSO
*unl0kr*(1)
# AUTHORS
*Undef* <debian@undef.tools>
*Johannes Marbach* <n0-0ne@mailbox.org>

31
find-lvgl-sources.sh Executable file
View file

@ -0,0 +1,31 @@
#!/bin/sh
# Copyright 2022 Johannes Marbach, Oliver Smith
#
# This file is part of unl0kr, hereafter referred to as the program.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# 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. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
find lv_drivers -name '*.c'
find lvgl/src/core -name '*.c'
find lvgl/src/draw -name '*.c'
find lvgl/src/extra -name '*.c'
find lvgl/src/extra/layouts/flex -name '*.c'
find lvgl/src/extra/widgets/keyboard -name '*.c'
find lvgl/src/extra/widgets/msgbox -name '*.c'
find lvgl/src/extra/widgets/span -name '*.c'
find lvgl/src/font -name '*.c'
find lvgl/src/hal -name '*.c'
find lvgl/src/misc -name '*.c'
find lvgl/src/widgets -name '*.c'

15523
font_32.c Normal file

File diff suppressed because it is too large Load diff

583
indev.c Normal file
View file

@ -0,0 +1,583 @@
/**
* Copyright 2021 Johannes Marbach
*
* This file is part of unl0kr, hereafter referred to as the program.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "indev.h"
#include "cursor.h"
#include "log.h"
#include "lv_drivers/indev/libinput_drv.h"
#include <libinput.h>
#include <libudev.h>
#include <limits.h>
#include <stdio.h>
#include <linux/input.h>
#include <sys/select.h>
/**
* Defines
*/
#define INPUT_DEVICE_NODE_PREFIX "/dev/input/event"
#define MAX_KEYBOARD_DEVS 4
#define MAX_POINTER_DEVS 4
#define MAX_TOUCHSCREEN_DEVS 1
/**
* Static variables
*/
static libinput_capability allowed_capability = LIBINPUT_CAPABILITY_NONE;
static struct udev *context = NULL;
static struct udev_monitor *monitor = NULL;
static int monitor_fd = -1;
struct input_device {
char *node;
libinput_capability capability;
libinput_drv_state_t drv_state;
lv_indev_drv_t indev_drv;
lv_indev_t *indev;
};
static struct input_device **devices = NULL;
static int num_devices = 0;
static int num_connected_devices = 0;
lv_group_t *keyboard_input_group = NULL;
lv_obj_t *cursor_obj = NULL;
/**
* Static prototypes
*/
/**
* Test whether a device can act as a keyboard device.
*
* @param device the device to test
* @return true if the device has the keyboard capability
*/
static bool is_keyboard_device(struct input_device *device);
/**
* Test whether a device can act as a pointer device.
*
* @param device the device to test
* @return true if the device has the pointer capability
*/
static bool is_pointer_device(struct input_device *device);
/**
* Test whether a device can act as a touch device.
*
* @param device the device to test
* @return true if the device has the touch capability
*/
static bool is_touch_device(struct input_device *device);
/**
* Convert a device capability into a descriptive string.
*
* @param capability input device capability
* @return textual description
*/
static char *capability_to_str(libinput_capability capability);
/**
* Connect a specific input device using its udev device.
*
* @param device udev device
*/
static void connect_udev_device(struct udev_device *device);
/**
* Connect a specific input device using its device node.
*
* @param node device node path
*/
static void connect_devnode(const char *node);
/**
* Disconnect a specific input device using its device node.
*
* @param node device node path
*/
static void disconnect_devnode(const char *node);
/**
* Disconnect a specific input device using its index in the devices array.
*
* @param idx index in devices array
*/
static void disconnect_idx(int idx);
/**
* Perform an input read on a device using the libinput driver.
*
* @param indev_drv input device driver
* @param data input device data to write into
*/
static void libinput_read_cb(lv_indev_drv_t *indev_drv, lv_indev_data_t *data);
/**
* Set up the input group for a keyboard device.
*
* @param device the input device
*/
static void set_keyboard_input_group(struct input_device *device);
/**
* Set up the mouse cursor image for a pointer device.
*
* @param device the input device
*/
static void set_mouse_cursor(struct input_device *device);
/**
* Static functions
*/
static bool is_keyboard_device(struct input_device *device) {
return (device->capability & LIBINPUT_CAPABILITY_KEYBOARD) != LIBINPUT_CAPABILITY_NONE;
}
static bool is_pointer_device(struct input_device *device) {
return (device->capability & LIBINPUT_CAPABILITY_POINTER) != LIBINPUT_CAPABILITY_NONE;
}
static bool is_touch_device(struct input_device *device) {
return (device->capability & LIBINPUT_CAPABILITY_TOUCH) != LIBINPUT_CAPABILITY_NONE;
}
static char *capability_to_str(libinput_capability capability) {
if (capability == LIBINPUT_CAPABILITY_KEYBOARD) {
return "keyboard";
}
if (capability == LIBINPUT_CAPABILITY_POINTER) {
return "pointer";
}
if (capability == LIBINPUT_CAPABILITY_TOUCH) {
return "touch";
}
return "none";
}
static void connect_udev_device(struct udev_device *device) {
/* Obtain and verify device node */
const char *node = udev_device_get_devnode(device);
if (!node || strncmp(node, INPUT_DEVICE_NODE_PREFIX, strlen(INPUT_DEVICE_NODE_PREFIX)) != 0) {
ul_log(UL_LOG_LEVEL_VERBOSE, "Ignoring unsupported input device %s", udev_device_get_syspath(device));
return;
}
/* Connect device using its node */
connect_devnode(node);
}
static void connect_devnode(const char *node) {
/* Check if the device is already connected */
for (int i = 0; i < num_connected_devices; ++i) {
if (strcmp(devices[i]->node, node) == 0) {
ul_log(UL_LOG_LEVEL_WARNING, "Ignoring already connected input device %s", node);
return;
}
}
/* Double array size every time it's filled */
if (num_connected_devices == num_devices) {
/* Re-allocate array */
struct input_device **tmp = realloc(devices, (2 * num_devices + 1) * sizeof(struct input_device *));
if (!tmp) {
ul_log(UL_LOG_LEVEL_ERROR, "Could not reallocate memory for input device array");
return;
}
devices = tmp;
/* Update size counter */
num_devices = 2 * num_devices + 1;
/* Fill empty space with zeros */
lv_memzero(devices + num_connected_devices, (num_devices - num_connected_devices) * sizeof(struct input_device *));
}
/* Allocate memory for new input device and insert it */
struct input_device *device = malloc(sizeof(struct input_device));
lv_memzero(device, sizeof(struct input_device));
devices[num_connected_devices] = device;
/* Get pointers to driver state & indev driver */
libinput_drv_state_t *drv_state = &(device->drv_state);
lv_indev_drv_t *indev_drv = &(device->indev_drv);
/* Copy the node path so that it can be used beyond the caller's scope */
device->node = strdup(node);
/* Initialise the driver state and obtain the libinput device */
libinput_init_state(drv_state, device->node);
struct libinput_device *device_libinput = drv_state->libinput_device;
/* If libinput failed to connect the device, exit */
if (!device_libinput) {
ul_log(UL_LOG_LEVEL_WARNING, "Aborting connection of input device %s because libinput failed to connect it", node);
disconnect_idx(num_connected_devices);
return;
}
/* Obtain device capabilities */
device->capability = libinput_query_capability(device_libinput);
/* If the device doesn't have any supported capabilities, exit */
if ((device->capability & allowed_capability) == LIBINPUT_CAPABILITY_NONE) {
ul_log(UL_LOG_LEVEL_WARNING, "Aborting connection of input device %s because it has no allowed capabilities", node);
disconnect_idx(num_connected_devices);
return;
}
/* Initialise indev driver */
lv_indev_drv_init(indev_drv);
indev_drv->read_cb = libinput_read_cb;
indev_drv->user_data = drv_state;
/*
* Set up indev driver type and related properties
*
* FIXME: Some libinput devices (notably, certain hid-i2c keyboards)
* report both keyboard and pointer capability. Since lvgl expects
* every input device to have only one type, we register those devices
* as keyboards, considering this capability more useful. However
* we must also assume that keyboard+touch devices are touch.
*/
if (is_touch_device(device)) {
indev_drv->type = LV_INDEV_TYPE_POINTER;
indev_drv->long_press_repeat_time = USHRT_MAX;
} else if (is_keyboard_device(device)) {
indev_drv->type = LV_INDEV_TYPE_KEYPAD;
} else if (is_pointer_device(device)) {
indev_drv->type = LV_INDEV_TYPE_POINTER;
indev_drv->long_press_repeat_time = USHRT_MAX;
}
/* Register indev */
device->indev = lv_indev_drv_register(indev_drv);
/* Set the input group for keyboard devices */
if (is_keyboard_device(device)) {
set_keyboard_input_group(device);
}
/* Set the mouse cursor for pointer devices */
if (is_pointer_device(device)) {
set_mouse_cursor(device);
}
/* Increment connected device count */
num_connected_devices++;
ul_log(UL_LOG_LEVEL_VERBOSE, "Connected input device %s (%s)", node, capability_to_str(device->capability));
}
static void disconnect_udev_device(struct udev_device *device) {
/* Obtain and verify device node */
const char *node = udev_device_get_devnode(device);
if (!node || strncmp(node, INPUT_DEVICE_NODE_PREFIX, strlen(INPUT_DEVICE_NODE_PREFIX)) != 0) {
ul_log(UL_LOG_LEVEL_VERBOSE, "Ignoring unsupported input device %s", udev_device_get_syspath(device));
return;
}
/* Disconnect device using its node */
disconnect_devnode(node);
}
static void disconnect_devnode(const char *node) {
/* Find connected device matching the specified node */
int idx = -1;
for (int i = 0; i < num_connected_devices; ++i) {
if (strcmp(devices[i]->node, node) == 0) {
idx = i;
break;
}
}
/* If no matching device was found, exit */
if (idx < 0) {
ul_log(UL_LOG_LEVEL_WARNING, "Ignoring already disconnected input device %s", node);
return;
}
/* Disconnect device using its index */
disconnect_idx(idx);
/* Shift subsequent devices forward */
for (int i = idx + 1; i < num_connected_devices; ++i) {
devices[i - 1] = devices[i];
/* Zero out the last element after shifting it forward */
if (i == num_connected_devices - 1) {
lv_memzero(devices + i, sizeof(struct input_device *));
}
}
/* Decrement connected device count */
--num_connected_devices;
ul_log(UL_LOG_LEVEL_VERBOSE, "Disconnected input device %s", node);
}
static void disconnect_idx(int idx) {
/* Delete LVGL indev */
if (devices[idx]->indev) {
lv_indev_delete(devices[idx]->indev);
}
/* Free previously copied node path */
if (devices[idx]->node) {
free(devices[idx]->node);
}
/* De-initialise driver state */
libinput_deinit_state(&(devices[idx]->drv_state));
/* Deallocate memory and zero out freed array element */
free(devices[idx]);
lv_memzero(devices + idx, sizeof(struct input_device *));
}
static void libinput_read_cb(lv_indev_drv_t *indev_drv, lv_indev_data_t *data) {
libinput_read_state(indev_drv->user_data, indev_drv, data);
}
static void set_keyboard_input_group(struct input_device *device) {
/* Ignore non-keyboard devices */
if (!is_keyboard_device(device)) {
return;
}
/* Apply the input group */
lv_indev_set_group(device->indev, keyboard_input_group);
}
static void set_mouse_cursor(struct input_device *device) {
/* Ignore non-pointer devices */
if (!is_pointer_device(device)) {
return;
}
/* Initialise cursor image if needed */
if (!cursor_obj) {
cursor_obj = lv_img_create(lv_scr_act());
lv_img_set_src(cursor_obj, &ul_cursor_img_dsc);
}
/* Apply the cursor image */
lv_indev_set_cursor(device->indev, cursor_obj);
}
/**
* Public functions
*/
void ul_indev_set_allowed_device_capability(bool keyboard, bool pointer, bool touchscreen) {
allowed_capability = LIBINPUT_CAPABILITY_NONE;
if (keyboard) {
allowed_capability |= LIBINPUT_CAPABILITY_KEYBOARD;
}
if (pointer) {
allowed_capability |= LIBINPUT_CAPABILITY_POINTER;
}
if (touchscreen) {
allowed_capability |= LIBINPUT_CAPABILITY_TOUCH;
}
}
void ul_indev_set_keyboard_input_group(lv_group_t *group) {
/* Store the group */
keyboard_input_group = group;
/* Apply the group on all connected keyboard devices */
for (int i = 0; i < num_connected_devices; ++i) {
if (is_keyboard_device(devices[i])) {
set_keyboard_input_group(devices[i]);
}
}
}
void ul_indev_auto_connect() {
ul_log(UL_LOG_LEVEL_VERBOSE, "Auto-connecting supported input devices");
/* Make sure udev context is initialised */
if (!context) {
context = udev_new();
if (!context) {
ul_log(UL_LOG_LEVEL_WARNING, "Could not create udev context");
return;
}
}
/* Scan for available input devices */
struct udev_enumerate *enumerate = udev_enumerate_new(context);
udev_enumerate_add_match_subsystem(enumerate, "input");
udev_enumerate_scan_devices(enumerate);
/* Prepare for enumerating found devices */
struct udev_list_entry *first_entry = udev_enumerate_get_list_entry(enumerate);
struct udev_list_entry *entry;
udev_list_entry_foreach(entry, first_entry) {
/* Obtain system path */
const char *path = udev_list_entry_get_name(entry);
/* Create udev device */
struct udev_device *device = udev_device_new_from_syspath(context, path);
if (!device) {
ul_log(UL_LOG_LEVEL_WARNING, "Could not create udev device for %s", path);
continue;
}
/* Connect device */
connect_udev_device(device);
/* Unreference udev device */
udev_device_unref(device);
}
/* Unreference enumeration */
udev_enumerate_unref(enumerate);
}
void ul_indev_start_monitor() {
/* Make sure udev context is initialised */
if (!context) {
context = udev_new();
if (!context) {
ul_log(UL_LOG_LEVEL_WARNING, "Could not create udev context");
return;
}
}
/* Check if monitor is already running */
if (monitor) {
ul_log(UL_LOG_LEVEL_WARNING, "Not starting udev monitor because it is already running");
return;
}
/* Create new monitor */
monitor = udev_monitor_new_from_netlink(context, "udev");
if (!monitor) {
ul_log(UL_LOG_LEVEL_WARNING, "Could not create udev monitor");
ul_indev_stop_monitor();
return;
}
/* Apply input subsystem filter */
if (udev_monitor_filter_add_match_subsystem_devtype(monitor, "input", NULL) < 0) {
ul_log(UL_LOG_LEVEL_WARNING, "Could not add input subsystem filter for udev monitor");
}
/* Start monitor */
if (udev_monitor_enable_receiving(monitor) < 0) {
ul_log(UL_LOG_LEVEL_WARNING, "Could not enable udev monitor");
ul_indev_stop_monitor();
return;
}
/* Obtain monitor file descriptor */
if ((monitor_fd = udev_monitor_get_fd(monitor)) < 0) {
ul_log(UL_LOG_LEVEL_WARNING, "Could not acquire file descriptor for udev monitor");
ul_indev_stop_monitor();
return;
}
}
void ul_indev_stop_monitor() {
/* Unreference monitor */
if (monitor) {
udev_monitor_unref(monitor);
monitor = NULL;
}
/* Reset monitor file descriptor */
if (monitor_fd >= 0) {
monitor_fd = -1;
}
/* Unreference udev context */
if (context) {
udev_unref(context);
context = NULL;
}
}
void ul_indev_query_monitor() {
/* Make sure the monitor is running */
if (!monitor) {
ul_log(UL_LOG_LEVEL_ERROR, "Cannot query udev monitor because it is not running");
return;
}
/* Prepare file descriptor set for reading */
fd_set fds;
FD_ZERO(&fds);
FD_SET(monitor_fd, &fds);
/* Set up timeval to not block when no updates are available */
struct timeval tv = { .tv_sec = 0, .tv_usec = 0 };
/* Read and process all updates */
while (select(monitor_fd + 1, &fds, NULL, NULL, &tv) > 0 && FD_ISSET(monitor_fd, &fds)) {
/* Obtain udev device */
struct udev_device *device = udev_monitor_receive_device(monitor);
if (!device) {
continue;
}
/* Obtain action */
const char *action = udev_device_get_action(device);
/* Connect or disconnect the device */
if (strcmp(action, "add") == 0) {
connect_udev_device(device);
} else if (strcmp(action, "remove") == 0) {
disconnect_udev_device(device);
}
/* Unreference udev device */
udev_device_unref(device);
}
}
bool ul_indev_is_keyboard_connected() {
for (int i = 0; i < num_connected_devices; ++i) {
if (is_keyboard_device(devices[i])) {
return true;
}
}
return false;
}

71
indev.h Normal file
View file

@ -0,0 +1,71 @@
/**
* Copyright 2021 Johannes Marbach
*
* This file is part of unl0kr, hereafter referred to as the program.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef UL_INDEV_H
#define UL_INDEV_H
#include "lvgl/lvgl.h"
#include <stdbool.h>
/**
* Set the required capabilities for input devices.
*
* @param keyboard if true, allow connection of keyboard devices
* @param pointer if true, allow connection of pointer devices
* @param touchscreen if true, allow connection of touchscreen devices
*/
void ul_indev_set_allowed_device_capability(bool keyboard, bool pointer, bool touchscreen);
/**
* Set the group for receiving input from keyboard devices.
*
* @param group group that should receive input
*/
void ul_indev_set_keyboard_input_group(lv_group_t *group);
/**
* Auto-connect currently available keyboard, pointer and touchscreen input devices.
*/
void ul_indev_auto_connect();
/**
* Start the udev device monitor.
*/
void ul_indev_start_monitor();
/**
* Stop the udev device monitor.
*/
void ul_indev_stop_monitor();
/**
* Query the udev device monitor and (dis)connect added or removed devices
*/
void ul_indev_query_monitor();
/**
* Check if any keyboard devices are connected.
*
* @return true if at least one keyboard device is connected, false otherwise
*/
bool ul_indev_is_keyboard_connected();
#endif /* UL_INDEV_H */

61
log.c Normal file
View file

@ -0,0 +1,61 @@
/**
* Copyright 2021 Johannes Marbach
*
* This file is part of unl0kr, hereafter referred to as the program.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "log.h"
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
/**
* Static variables
*/
static ul_log_level log_level = UL_LOG_LEVEL_ERROR;
/**
* Public functions
*/
void ul_log_set_level(ul_log_level level) {
log_level = level;
}
void ul_log(ul_log_level level, const char *format, ...) {
if (level > log_level) {
return;
}
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
size_t l = strlen(format);
if (l > 0 && format[l - 1] != '\n') {
fprintf(stderr, "\n");
}
}
void ul_log_print_cb(const char *msg) {
ul_log(UL_LOG_LEVEL_VERBOSE, msg);
}

59
log.h Normal file
View file

@ -0,0 +1,59 @@
/**
* Copyright 2021 Johannes Marbach
*
* This file is part of unl0kr, hereafter referred to as the program.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef UL_LOG_H
#define UL_LOG_H
/**
* Log levels
*/
typedef enum {
/* Errors only */
UL_LOG_LEVEL_ERROR = 0,
/* Warnings and errors */
UL_LOG_LEVEL_WARNING = 1,
/* Include non-errors in log */
UL_LOG_LEVEL_VERBOSE = 2
} ul_log_level;
/**
* Set the log level.
*
* @param level new log level value
*/
void ul_log_set_level(ul_log_level level);
/**
* Log a message. A newline character is appended unless the message ends in one.
*
* @param level log level of the message
* @param format message format string
* @param ... parameters to fill into the format string
*/
void ul_log(ul_log_level level, const char *format, ...);
/**
* Handle an LVGL log message.
*
* @param msg message to print
*/
void ul_log_print_cb(const char *msg);
#endif /* UL_LOG_H */

527
lv_conf.h Normal file
View file

@ -0,0 +1,527 @@
/**
* Copyright 2021 Johannes Marbach
*
* This file is part of unl0kr, hereafter referred to as the program.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#if 1 /*Set it to "1" to enable content*/
#ifndef LV_CONF_H
#define LV_CONF_H
/*clang-format off*/
#include <stdint.h>
/*====================
COLOR SETTINGS
*====================*/
/*Color depth: 1 (1 byte per pixel), 8 (RGB332), 16 (RGB565), 32 (ARGB8888)*/
#define LV_COLOR_DEPTH 32
/*Swap the 2 bytes of RGB565 color. Useful if the display has a 8 bit interface (e.g. SPI)*/
#define LV_COLOR_16_SWAP 0
/*Enable more complex drawing routines to manage screens transparency.
*Can be used if the UI is above another layer, e.g. an OSD menu or video player.
*Requires `LV_COLOR_DEPTH = 32` colors and the screen's `bg_opa` should be set to non LV_OPA_COVER value*/
#define LV_COLOR_SCREEN_TRANSP 0
/*Images pixels with this color will not be drawn if they are chroma keyed)*/
#define LV_COLOR_CHROMA_KEY lv_color_hex(0x00ff00) /*pure green*/
/*=========================
MEMORY SETTINGS
*=========================*/
/*1: use custom malloc/free, 0: use the built-in `lv_mem_alloc()` and `lv_mem_free()`*/
#define LV_MEM_CUSTOM 0
#if LV_MEM_CUSTOM == 0
/*Size of the memory available for `lv_mem_alloc()` in bytes (>= 2kB)*/
# define LV_MEM_SIZE (128U * 1024U) /*[bytes]*/
/*Set an address for the memory pool instead of allocating it as a normal array. Can be in external SRAM too.*/
# define LV_MEM_ADR 0 /*0: unused*/
#else /*LV_MEM_CUSTOM*/
# define LV_MEM_CUSTOM_INCLUDE <stdlib.h> /*Header for the dynamic memory function*/
# define LV_MEM_CUSTOM_ALLOC malloc
# define LV_MEM_CUSTOM_FREE free
# define LV_MEM_CUSTOM_REALLOC realloc
#endif /*LV_MEM_CUSTOM*/
/*Use the standard `memcpy` and `memset` instead of LVGL's own functions. (Might or might not be faster).*/
#define LV_MEMCPY_MEMSET_STD 0
/*TODO: Remove once lv_memzero becomes available in a release. Currently it is only available on master.*/
#define lv_memzero(dst, len) (lv_memset(dst, 0x00, len))
/*====================
HAL SETTINGS
*====================*/
/*Default display refresh period. LVG will redraw changed ares with this period time*/
#define LV_DISP_DEF_REFR_PERIOD 30 /*[ms]*/
/*Input device read period in milliseconds*/
#define LV_INDEV_DEF_READ_PERIOD 5 /*[ms]*/
/*Use a custom tick source that tells the elapsed time in milliseconds.
*It removes the need to manually update the tick with `lv_tick_inc()`)*/
uint32_t ul_get_tick(void);
#define LV_TICK_CUSTOM 1
#if LV_TICK_CUSTOM
#define LV_TICK_CUSTOM_INCLUDE <stdint.h> /*Header for the system time function*/
#define LV_TICK_CUSTOM_SYS_TIME_EXPR (ul_get_tick()) /*Expression evaluating to current system time in ms*/
#endif /*LV_TICK_CUSTOM*/
/*Default Dot Per Inch. Used to initialize default sizes such as widgets sized, style paddings.
*(Not so important, you can adjust it to modify default sizes and spaces)*/
#define LV_DPI_DEF 130 /*[px/inch]*/
/*=======================
* FEATURE CONFIGURATION
*=======================*/
/*-------------
* Drawing
*-----------*/
/*Enable complex draw engine.
*Required to draw shadow, gradient, rounded corners, circles, arc, skew lines, image transformations or any masks*/
#define LV_DRAW_COMPLEX 1
#if LV_DRAW_COMPLEX != 0
/*Allow buffering some shadow calculation.
*LV_SHADOW_CACHE_SIZE is the max. shadow size to buffer, where shadow size is `shadow_width + radius`
*Caching has LV_SHADOW_CACHE_SIZE^2 RAM cost*/
#define LV_SHADOW_CACHE_SIZE 0
#endif /*LV_DRAW_COMPLEX*/
/*Default image cache size. Image caching keeps the images opened.
*If only the built-in image formats are used there is no real advantage of caching. (I.e. if no new image decoder is added)
*With complex image decoders (e.g. PNG or JPG) caching can save the continuous open/decode of images.
*However the opened images might consume additional RAM.
*0: to disable caching*/
#define LV_IMG_CACHE_DEF_SIZE 0
/*Maximum buffer size to allocate for rotation. Only used if software rotation is enabled in the display driver.*/
#define LV_DISP_ROT_MAX_BUF (10*1024)
/*-------------
* GPU
*-----------*/
/*Use STM32's DMA2D (aka Chrom Art) GPU*/
#define LV_USE_GPU_STM32_DMA2D 0
#if LV_USE_GPU_STM32_DMA2D
/*Must be defined to include path of CMSIS header of target processor
e.g. "stm32f769xx.h" or "stm32f429xx.h"*/
#define LV_GPU_DMA2D_CMSIS_INCLUDE
#endif
/*Use NXP's PXP GPU iMX RTxxx platforms*/
#define LV_USE_GPU_NXP_PXP 0
#if LV_USE_GPU_NXP_PXP
/*1: Add default bare metal and FreeRTOS interrupt handling routines for PXP (lv_gpu_nxp_pxp_osa.c)
* and call lv_gpu_nxp_pxp_init() automatically during lv_init(). Note that symbol FSL_RTOS_FREE_RTOS
* has to be defined in order to use FreeRTOS OSA, otherwise bare-metal implementation is selected.
*0: lv_gpu_nxp_pxp_init() has to be called manually before lv_init()
*/
#define LV_USE_GPU_NXP_PXP_AUTO_INIT 0
#endif
/*Use NXP's VG-Lite GPU iMX RTxxx platforms*/
#define LV_USE_GPU_NXP_VG_LITE 0
/*-------------
* Logging
*-----------*/
/*Enable the log module*/
#define LV_USE_LOG 1
#if LV_USE_LOG
/*How important log should be added:
*LV_LOG_LEVEL_TRACE A lot of logs to give detailed information
*LV_LOG_LEVEL_INFO Log important events
*LV_LOG_LEVEL_WARN Log if something unwanted happened but didn't cause a problem
*LV_LOG_LEVEL_ERROR Only critical issue, when the system may fail
*LV_LOG_LEVEL_USER Only logs added by the user
*LV_LOG_LEVEL_NONE Do not log anything*/
# define LV_LOG_LEVEL LV_LOG_LEVEL_WARN
/*1: Print the log with 'printf';
*0: User need to register a callback with `lv_log_register_print_cb()`*/
# define LV_LOG_PRINTF 1
/*Enable/disable LV_LOG_TRACE in modules that produces a huge number of logs*/
# define LV_LOG_TRACE_MEM 1
# define LV_LOG_TRACE_TIMER 1
# define LV_LOG_TRACE_INDEV 1
# define LV_LOG_TRACE_DISP_REFR 1
# define LV_LOG_TRACE_EVENT 1
# define LV_LOG_TRACE_OBJ_CREATE 1
# define LV_LOG_TRACE_LAYOUT 1
# define LV_LOG_TRACE_ANIM 1
#endif /*LV_USE_LOG*/
/*-------------
* Asserts
*-----------*/
/*Enable asserts if an operation is failed or an invalid data is found.
*If LV_USE_LOG is enabled an error message will be printed on failure*/
#define LV_USE_ASSERT_NULL 1 /*Check if the parameter is NULL. (Very fast, recommended)*/
#define LV_USE_ASSERT_MALLOC 1 /*Checks is the memory is successfully allocated or no. (Very fast, recommended)*/
#define LV_USE_ASSERT_STYLE 0 /*Check if the styles are properly initialized. (Very fast, recommended)*/
#define LV_USE_ASSERT_MEM_INTEGRITY 0 /*Check the integrity of `lv_mem` after critical operations. (Slow)*/
#define LV_USE_ASSERT_OBJ 0 /*Check the object's type and existence (e.g. not deleted). (Slow)*/
/*Add a custom handler when assert happens e.g. to restart the MCU*/
#define LV_ASSERT_HANDLER_INCLUDE <stdint.h>
#define LV_ASSERT_HANDLER while(1); /*Halt by default*/
/*-------------
* Others
*-----------*/
/*1: Show CPU usage and FPS count in the right bottom corner*/
#define LV_USE_PERF_MONITOR 0
/*1: Show the used memory and the memory fragmentation in the left bottom corner
* Requires LV_MEM_CUSTOM = 0*/
#define LV_USE_MEM_MONITOR 0
/*1: Draw random colored rectangles over the redrawn areas*/
#define LV_USE_REFR_DEBUG 0
/*Change the built in (v)snprintf functions*/
#define LV_SPRINTF_CUSTOM 0
#if LV_SPRINTF_CUSTOM
# define LV_SPRINTF_INCLUDE <stdio.h>
# define lv_snprintf snprintf
# define lv_vsnprintf vsnprintf
#else /*LV_SPRINTF_CUSTOM*/
# define LV_SPRINTF_USE_FLOAT 0
#endif /*LV_SPRINTF_CUSTOM*/
#define LV_USE_USER_DATA 1
/*Garbage Collector settings
*Used if lvgl is binded to higher level language and the memory is managed by that language*/
#define LV_ENABLE_GC 0
#if LV_ENABLE_GC != 0
# define LV_GC_INCLUDE "gc.h" /*Include Garbage Collector related things*/
#endif /*LV_ENABLE_GC*/
/*=====================
* COMPILER SETTINGS
*====================*/
/*For big endian systems set to 1*/
#define LV_BIG_ENDIAN_SYSTEM 0
/*Define a custom attribute to `lv_tick_inc` function*/
#define LV_ATTRIBUTE_TICK_INC
/*Define a custom attribute to `lv_timer_handler` function*/
#define LV_ATTRIBUTE_TIMER_HANDLER
/*Define a custom attribute to `lv_disp_flush_ready` function*/
#define LV_ATTRIBUTE_FLUSH_READY
/*Required alignment size for buffers*/
#define LV_ATTRIBUTE_MEM_ALIGN_SIZE
/*Will be added where memories needs to be aligned (with -Os data might not be aligned to boundary by default).
* E.g. __attribute__((aligned(4)))*/
#define LV_ATTRIBUTE_MEM_ALIGN
/*Attribute to mark large constant arrays for example font's bitmaps*/
#define LV_ATTRIBUTE_LARGE_CONST
/*Complier prefix for a big array declaration in RAM*/
#define LV_ATTRIBUTE_LARGE_RAM_ARRAY
/*Place performance critical functions into a faster memory (e.g RAM)*/
#define LV_ATTRIBUTE_FAST_MEM
/*Prefix variables that are used in GPU accelerated operations, often these need to be placed in RAM sections that are DMA accessible*/
#define LV_ATTRIBUTE_DMA
/*Export integer constant to binding. This macro is used with constants in the form of LV_<CONST> that
*should also appear on LVGL binding API such as Micropython.*/
#define LV_EXPORT_CONST_INT(int_value) struct _silence_gcc_warning /*The default value just prevents GCC warning*/
/*Extend the default -32k..32k coordinate range to -4M..4M by using int32_t for coordinates instead of int16_t*/
#define LV_USE_LARGE_COORD 0
/*==================
* FONT USAGE
*===================*/
/*Montserrat fonts with ASCII range and some symbols using bpp = 4
*https://fonts.google.com/specimen/Montserrat*/
#define LV_FONT_MONTSERRAT_8 0
#define LV_FONT_MONTSERRAT_10 0
#define LV_FONT_MONTSERRAT_12 0
#define LV_FONT_MONTSERRAT_14 0
#define LV_FONT_MONTSERRAT_16 0
#define LV_FONT_MONTSERRAT_18 0
#define LV_FONT_MONTSERRAT_20 0
#define LV_FONT_MONTSERRAT_22 0
#define LV_FONT_MONTSERRAT_24 0
#define LV_FONT_MONTSERRAT_26 0
#define LV_FONT_MONTSERRAT_28 0
#define LV_FONT_MONTSERRAT_30 0
#define LV_FONT_MONTSERRAT_32 0
#define LV_FONT_MONTSERRAT_34 0
#define LV_FONT_MONTSERRAT_36 0
#define LV_FONT_MONTSERRAT_38 0
#define LV_FONT_MONTSERRAT_40 0
#define LV_FONT_MONTSERRAT_42 0
#define LV_FONT_MONTSERRAT_44 0
#define LV_FONT_MONTSERRAT_46 0
#define LV_FONT_MONTSERRAT_48 0
/*Demonstrate special features*/
#define LV_FONT_MONTSERRAT_12_SUBPX 0
#define LV_FONT_MONTSERRAT_28_COMPRESSED 0 /*bpp = 3*/
#define LV_FONT_DEJAVU_16_PERSIAN_HEBREW 0 /*Hebrew, Arabic, Perisan letters and all their forms*/
#define LV_FONT_SIMSUN_16_CJK 0 /*1000 most common CJK radicals*/
/*Pixel perfect monospace fonts*/
#define LV_FONT_UNSCII_8 0
#define LV_FONT_UNSCII_16 0
/*Optionally declare custom fonts here.
*You can use these fonts as default font too and they will be available globally.
*E.g. #define LV_FONT_CUSTOM_DECLARE LV_FONT_DECLARE(my_font_1) LV_FONT_DECLARE(my_font_2)*/
#define LV_FONT_CUSTOM_DECLARE LV_FONT_DECLARE(font_32)
/*Always set a default font*/
#define LV_FONT_DEFAULT &font_32
/*Enable handling large font and/or fonts with a lot of characters.
*The limit depends on the font size, font face and bpp.
*Compiler error will be triggered if a font needs it.*/
#define LV_FONT_FMT_TXT_LARGE 0
/*Enables/disables support for compressed fonts.*/
#define LV_USE_FONT_COMPRESSED 0
/*Enable subpixel rendering*/
#define LV_USE_FONT_SUBPX 0
#if LV_USE_FONT_SUBPX
/*Set the pixel order of the display. Physical order of RGB channels. Doesn't matter with "normal" fonts.*/
#define LV_FONT_SUBPX_BGR 0 /*0: RGB; 1:BGR order*/
#endif
/*=================
* TEXT SETTINGS
*=================*/
/**
* Select a character encoding for strings.
* Your IDE or editor should have the same character encoding
* - LV_TXT_ENC_UTF8
* - LV_TXT_ENC_ASCII
*/
#define LV_TXT_ENC LV_TXT_ENC_UTF8
/*Can break (wrap) texts on these chars*/
#define LV_TXT_BREAK_CHARS " ,.;:-_"
/*If a word is at least this long, will break wherever "prettiest"
*To disable, set to a value <= 0*/
#define LV_TXT_LINE_BREAK_LONG_LEN 0
/*Minimum number of characters in a long word to put on a line before a break.
*Depends on LV_TXT_LINE_BREAK_LONG_LEN.*/
#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3
/*Minimum number of characters in a long word to put on a line after a break.
*Depends on LV_TXT_LINE_BREAK_LONG_LEN.*/
#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 3
/*The control character to use for signalling text recoloring.*/
#define LV_TXT_COLOR_CMD "#"
/*Support bidirectional texts. Allows mixing Left-to-Right and Right-to-Left texts.
*The direction will be processed according to the Unicode Bidirectioanl Algorithm:
*https://www.w3.org/International/articles/inline-bidi-markup/uba-basics*/
#define LV_USE_BIDI 0
#if LV_USE_BIDI
/*Set the default direction. Supported values:
*`LV_BASE_DIR_LTR` Left-to-Right
*`LV_BASE_DIR_RTL` Right-to-Left
*`LV_BASE_DIR_AUTO` detect texts base direction*/
#define LV_BIDI_BASE_DIR_DEF LV_BASE_DIR_AUTO
#endif
/*Enable Arabic/Persian processing
*In these languages characters should be replaced with an other form based on their position in the text*/
#define LV_USE_ARABIC_PERSIAN_CHARS 0
/*==================
* WIDGET USAGE
*================*/
/*Documentation of the widgets: https://docs.lvgl.io/latest/en/html/widgets/index.html*/
#define LV_USE_ARC 0
#define LV_USE_ANIMIMG 0
#define LV_USE_BAR 1
#define LV_USE_BTN 1
#define LV_USE_BTNMATRIX 1
#define LV_USE_CANVAS 0
#define LV_USE_CHECKBOX 0
#define LV_USE_DROPDOWN 1 /*Requires: lv_label*/
#define LV_USE_IMG 1 /*Requires: lv_label*/
#define LV_USE_LABEL 1
#if LV_USE_LABEL
# define LV_LABEL_TEXT_SELECTION 1 /*Enable selecting text of the label*/
# define LV_LABEL_LONG_TXT_HINT 1 /*Store some extra info in labels to speed up drawing of very long texts*/
#endif
#define LV_USE_LINE 0
#define LV_USE_ROLLER 0 /*Requires: lv_label*/
#if LV_USE_ROLLER
# define LV_ROLLER_INF_PAGES 7 /*Number of extra "pages" when the roller is infinite*/
#endif
#define LV_USE_SLIDER 0 /*Requires: lv_bar*/
#define LV_USE_SWITCH 0
#define LV_USE_TEXTAREA 1 /*Requires: lv_label*/
#if LV_USE_TEXTAREA != 0
# define LV_TEXTAREA_DEF_PWD_SHOW_TIME 0 /*ms*/
#endif
#define LV_USE_TABLE 0
/*==================
* EXTRA COMPONENTS
*==================*/
/*-----------
* Widgets
*----------*/
#define LV_USE_CALENDAR 0
#if LV_USE_CALENDAR
# define LV_CALENDAR_WEEK_STARTS_MONDAY 0
# if LV_CALENDAR_WEEK_STARTS_MONDAY
# define LV_CALENDAR_DEFAULT_DAY_NAMES {"Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"}
# else
# define LV_CALENDAR_DEFAULT_DAY_NAMES {"Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"}
# endif
# define LV_CALENDAR_DEFAULT_MONTH_NAMES {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}
# define LV_USE_CALENDAR_HEADER_ARROW 1
# define LV_USE_CALENDAR_HEADER_DROPDOWN 1
#endif /*LV_USE_CALENDAR*/
#define LV_USE_CHART 0
#define LV_USE_COLORWHEEL 0
#define LV_USE_IMGBTN 0
#define LV_USE_KEYBOARD 1
#define LV_USE_LED 0
#define LV_USE_LIST 0
#define LV_USE_METER 0
#define LV_USE_MSGBOX 1
#define LV_USE_SPINBOX 0
#define LV_USE_SPINNER 0
#define LV_USE_TABVIEW 0
#define LV_USE_TILEVIEW 0
#define LV_USE_WIN 0
#define LV_USE_SPAN 1
#if LV_USE_SPAN
/*A line text can contain maximum num of span descriptor */
# define LV_SPAN_SNIPPET_STACK_SIZE 64
#endif
/*-----------
* Themes
*----------*/
/*A simple, impressive and very complete theme*/
#define LV_USE_THEME_DEFAULT 0
#if LV_USE_THEME_DEFAULT
/*0: Light mode; 1: Dark mode*/
# define LV_THEME_DEFAULT_DARK 0
/*1: Enable grow on press*/
# define LV_THEME_DEFAULT_GROW 0
/*Default transition time in [ms]*/
# define LV_THEME_DEFAULT_TRANSITON_TIME 80
#endif /*LV_USE_THEME_DEFAULT*/
/*An very simple them that is a good starting point for a custom theme*/
#define LV_USE_THEME_BASIC 0
/*A theme designed for monochrome displays*/
#define LV_USE_THEME_MONO 0
/*-----------
* Layouts
*----------*/
/*A layout similar to Flexbox in CSS.*/
#define LV_USE_FLEX 1
/*A layout similar to Grid in CSS.*/
#define LV_USE_GRID 0
/*==================
* EXAMPLES
*==================*/
/*Enable the examples to be built with the library*/
#define LV_BUILD_EXAMPLES 0
/*--END OF LV_CONF_H--*/
#endif /*LV_CONF_H*/
#endif /*End of "Content enable"*/

1
lv_drivers Submodule

@ -0,0 +1 @@
Subproject commit 71dbdf07c4ab808bc6f04251d58f78bb57869bf9

455
lv_drv_conf.h Normal file
View file

@ -0,0 +1,455 @@
/**
* Copyright 2021 Johannes Marbach
*
* This file is part of unl0kr, hereafter referred to as the program.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#if 1 /*Set it to "1" to enable the content*/
#ifndef LV_DRV_CONF_H
#define LV_DRV_CONF_H
#include "lv_conf.h"
/*********************
* DELAY INTERFACE
*********************/
#define LV_DRV_DELAY_INCLUDE <stdint.h> /*Dummy include by default*/
#define LV_DRV_DELAY_US(us) /*delay_us(us)*/ /*Delay the given number of microseconds*/
#define LV_DRV_DELAY_MS(ms) /*delay_ms(ms)*/ /*Delay the given number of milliseconds*/
/*********************
* DISPLAY INTERFACE
*********************/
/*------------
* Common
*------------*/
#define LV_DRV_DISP_INCLUDE <stdint.h> /*Dummy include by default*/
#define LV_DRV_DISP_CMD_DATA(val) /*pin_x_set(val)*/ /*Set the command/data pin to 'val'*/
#define LV_DRV_DISP_RST(val) /*pin_x_set(val)*/ /*Set the reset pin to 'val'*/
/*---------
* SPI
*---------*/
#define LV_DRV_DISP_SPI_CS(val) /*spi_cs_set(val)*/ /*Set the SPI's Chip select to 'val'*/
#define LV_DRV_DISP_SPI_WR_BYTE(data) /*spi_wr(data)*/ /*Write a byte the SPI bus*/
#define LV_DRV_DISP_SPI_WR_ARRAY(adr, n) /*spi_wr_mem(adr, n)*/ /*Write 'n' bytes to SPI bus from 'adr'*/
/*------------------
* Parallel port
*-----------------*/
#define LV_DRV_DISP_PAR_CS(val) /*par_cs_set(val)*/ /*Set the Parallel port's Chip select to 'val'*/
#define LV_DRV_DISP_PAR_SLOW /*par_slow()*/ /*Set low speed on the parallel port*/
#define LV_DRV_DISP_PAR_FAST /*par_fast()*/ /*Set high speed on the parallel port*/
#define LV_DRV_DISP_PAR_WR_WORD(data) /*par_wr(data)*/ /*Write a word to the parallel port*/
#define LV_DRV_DISP_PAR_WR_ARRAY(adr, n) /*par_wr_mem(adr,n)*/ /*Write 'n' bytes to Parallel ports from 'adr'*/
/***************************
* INPUT DEVICE INTERFACE
***************************/
/*----------
* Common
*----------*/
#define LV_DRV_INDEV_INCLUDE <stdint.h> /*Dummy include by default*/
#define LV_DRV_INDEV_RST(val) /*pin_x_set(val)*/ /*Set the reset pin to 'val'*/
#define LV_DRV_INDEV_IRQ_READ 0 /*pn_x_read()*/ /*Read the IRQ pin*/
/*---------
* SPI
*---------*/
#define LV_DRV_INDEV_SPI_CS(val) /*spi_cs_set(val)*/ /*Set the SPI's Chip select to 'val'*/
#define LV_DRV_INDEV_SPI_XCHG_BYTE(data) 0 /*spi_xchg(val)*/ /*Write 'val' to SPI and give the read value*/
/*---------
* I2C
*---------*/
#define LV_DRV_INDEV_I2C_START /*i2c_start()*/ /*Make an I2C start*/
#define LV_DRV_INDEV_I2C_STOP /*i2c_stop()*/ /*Make an I2C stop*/
#define LV_DRV_INDEV_I2C_RESTART /*i2c_restart()*/ /*Make an I2C restart*/
#define LV_DRV_INDEV_I2C_WR(data) /*i2c_wr(data)*/ /*Write a byte to the I1C bus*/
#define LV_DRV_INDEV_I2C_READ(last_read) 0 /*i2c_rd()*/ /*Read a byte from the I2C bud*/
/*********************
* DISPLAY DRIVERS
*********************/
/*-------------------
* Monitor of PC
*-------------------*/
#ifndef USE_MONITOR
# define USE_MONITOR 0
#endif
#if USE_MONITOR
# define MONITOR_HOR_RES 480
# define MONITOR_VER_RES 320
/* Scale window by this factor (useful when simulating small screens) */
# define MONITOR_ZOOM 1
/* Used to test true double buffering with only address changing.
* Use 2 draw buffers, bith with MONITOR_HOR_RES x MONITOR_VER_RES size*/
# define MONITOR_DOUBLE_BUFFERED 0
/*Eclipse: <SDL2/SDL.h> Visual Studio: <SDL.h>*/
# define MONITOR_SDL_INCLUDE_PATH <SDL2/SDL.h>
/*Open two windows to test multi display support*/
# define MONITOR_DUAL 0
#endif
/*-----------------------------------
* Native Windows (including mouse)
*----------------------------------*/
#ifndef USE_WINDOWS
# define USE_WINDOWS 0
#endif
#if USE_WINDOWS
# define WINDOW_HOR_RES 480
# define WINDOW_VER_RES 320
#endif
/*----------------------------
* Native Windows (win32drv)
*---------------------------*/
#ifndef USE_WIN32DRV
# define USE_WIN32DRV 0
#endif
#if USE_WIN32DRV
/* Scale window by this factor (useful when simulating small screens) */
# define WIN32DRV_MONITOR_ZOOM 1
#endif
/*----------------------------------------
* GTK drivers (monitor, mouse, keyboard
*---------------------------------------*/
#ifndef USE_GTK
# define USE_GTK 0
#endif
/*----------------------------------------
* Wayland drivers (monitor, mouse, keyboard, touchscreen)
*---------------------------------------*/
#ifndef USE_WAYLAND
# define USE_WAYLAND 0
#endif
#if USE_WAYLAND
# define WAYLAND_HOR_RES 480
# define WAYLAND_VER_RES 320
# define WAYLAND_SURF_TITLE "LVGL"
#endif
/*----------------
* SSD1963
*--------------*/
#ifndef USE_SSD1963
# define USE_SSD1963 0
#endif
#if USE_SSD1963
# define SSD1963_HOR_RES LV_HOR_RES
# define SSD1963_VER_RES LV_VER_RES
# define SSD1963_HT 531
# define SSD1963_HPS 43
# define SSD1963_LPS 8
# define SSD1963_HPW 10
# define SSD1963_VT 288
# define SSD1963_VPS 12
# define SSD1963_FPS 4
# define SSD1963_VPW 10
# define SSD1963_HS_NEG 0 /*Negative hsync*/
# define SSD1963_VS_NEG 0 /*Negative vsync*/
# define SSD1963_ORI 0 /*0, 90, 180, 270*/
# define SSD1963_COLOR_DEPTH 16
#endif
/*----------------
* R61581
*--------------*/
#ifndef USE_R61581
# define USE_R61581 0
#endif
#if USE_R61581
# define R61581_HOR_RES LV_HOR_RES
# define R61581_VER_RES LV_VER_RES
# define R61581_HSPL 0 /*HSYNC signal polarity*/
# define R61581_HSL 10 /*HSYNC length (Not Implemented)*/
# define R61581_HFP 10 /*Horitontal Front poarch (Not Implemented)*/
# define R61581_HBP 10 /*Horitontal Back poarch (Not Implemented */
# define R61581_VSPL 0 /*VSYNC signal polarity*/
# define R61581_VSL 10 /*VSYNC length (Not Implemented)*/
# define R61581_VFP 8 /*Vertical Front poarch*/
# define R61581_VBP 8 /*Vertical Back poarch */
# define R61581_DPL 0 /*DCLK signal polarity*/
# define R61581_EPL 1 /*ENABLE signal polarity*/
# define R61581_ORI 0 /*0, 180*/
# define R61581_LV_COLOR_DEPTH 16 /*Fix 16 bit*/
#endif
/*------------------------------
* ST7565 (Monochrome, low res.)
*-----------------------------*/
#ifndef USE_ST7565
# define USE_ST7565 0
#endif
#if USE_ST7565
/*No settings*/
#endif /*USE_ST7565*/
/*------------------------------
* GC9A01 (color, low res.)
*-----------------------------*/
#ifndef USE_GC9A01
# define USE_GC9A01 0
#endif
#if USE_GC9A01
/*No settings*/
#endif /*USE_GC9A01*/
/*------------------------------------------
* UC1610 (4 gray 160*[104|128])
* (EA DOGXL160 160x104 tested)
*-----------------------------------------*/
#ifndef USE_UC1610
# define USE_UC1610 0
#endif
#if USE_UC1610
# define UC1610_HOR_RES LV_HOR_RES
# define UC1610_VER_RES LV_VER_RES
# define UC1610_INIT_CONTRAST 33 /* init contrast, values in [%] */
# define UC1610_INIT_HARD_RST 0 /* 1 : hardware reset at init, 0 : software reset */
# define UC1610_TOP_VIEW 0 /* 0 : Bottom View, 1 : Top View */
#endif /*USE_UC1610*/
/*-------------------------------------------------
* SHARP memory in pixel monochrome display series
* LS012B7DD01 (184x38 pixels.)
* LS013B7DH03 (128x128 pixels.)
* LS013B7DH05 (144x168 pixels.)
* LS027B7DH01 (400x240 pixels.) (tested)
* LS032B7DD02 (336x536 pixels.)
* LS044Q7DH01 (320x240 pixels.)
*------------------------------------------------*/
#ifndef USE_SHARP_MIP
# define USE_SHARP_MIP 0
#endif
#if USE_SHARP_MIP
# define SHARP_MIP_HOR_RES LV_HOR_RES
# define SHARP_MIP_VER_RES LV_VER_RES
# define SHARP_MIP_SOFT_COM_INVERSION 0
# define SHARP_MIP_REV_BYTE(b) /*((uint8_t) __REV(__RBIT(b)))*/ /*Architecture / compiler dependent byte bits order reverse*/
#endif /*USE_SHARP_MIP*/
/*-------------------------------------------------
* ILI9341 240X320 TFT LCD
*------------------------------------------------*/
#ifndef USE_ILI9341
# define USE_ILI9341 0
#endif
#if USE_ILI9341
# define ILI9341_HOR_RES LV_HOR_RES
# define ILI9341_VER_RES LV_VER_RES
# define ILI9341_GAMMA 1
# define ILI9341_TEARING 0
#endif /*USE_ILI9341*/
/*-----------------------------------------
* Linux frame buffer device (/dev/fbx)
*-----------------------------------------*/
#ifndef USE_FBDEV
# define USE_FBDEV 1
#endif
#if USE_FBDEV
# define FBDEV_PATH "/dev/fb0"
#endif
/*-----------------------------------------
* FreeBSD frame buffer device (/dev/fbx)
*.........................................*/
#ifndef USE_BSD_FBDEV
# define USE_BSD_FBDEV 0
#endif
#if USE_BSD_FBDEV
# define FBDEV_PATH "/dev/fb0"
#endif
/*-----------------------------------------
* DRM/KMS device (/dev/dri/cardX)
*-----------------------------------------*/
#ifndef USE_DRM
# define USE_DRM 0
#endif
#if USE_DRM
# define DRM_CARD "/dev/dri/card0"
# define DRM_CONNECTOR_ID -1 /* -1 for the first connected one */
#endif
/*********************
* INPUT DEVICES
*********************/
/*--------------
* XPT2046
*--------------*/
#ifndef USE_XPT2046
# define USE_XPT2046 0
#endif
#if USE_XPT2046
# define XPT2046_HOR_RES 480
# define XPT2046_VER_RES 320
# define XPT2046_X_MIN 200
# define XPT2046_Y_MIN 200
# define XPT2046_X_MAX 3800
# define XPT2046_Y_MAX 3800
# define XPT2046_AVG 4
# define XPT2046_X_INV 0
# define XPT2046_Y_INV 0
# define XPT2046_XY_SWAP 0
#endif
/*-----------------
* FT5406EE8
*-----------------*/
#ifndef USE_FT5406EE8
# define USE_FT5406EE8 0
#endif
#if USE_FT5406EE8
# define FT5406EE8_I2C_ADR 0x38 /*7 bit address*/
#endif
/*---------------
* AD TOUCH
*--------------*/
#ifndef USE_AD_TOUCH
# define USE_AD_TOUCH 0
#endif
#if USE_AD_TOUCH
/*No settings*/
#endif
/*---------------------------------------
* Mouse or touchpad on PC (using SDL)
*-------------------------------------*/
#ifndef USE_MOUSE
# define USE_MOUSE 0
#endif
#if USE_MOUSE
/*No settings*/
#endif
/*-------------------------------------------
* Mousewheel as encoder on PC (using SDL)
*------------------------------------------*/
#ifndef USE_MOUSEWHEEL
# define USE_MOUSEWHEEL 0
#endif
#if USE_MOUSEWHEEL
/*No settings*/
#endif
/*-------------------------------------------------
* Touchscreen as libinput interface (for Linux based systems)
*------------------------------------------------*/
#ifndef USE_LIBINPUT
# define USE_LIBINPUT 1
#endif
#ifndef USE_BSD_LIBINPUT
# define USE_BSD_LIBINPUT 0
#endif
#if USE_LIBINPUT || USE_BSD_LIBINPUT
# define LIBINPUT_NAME "/dev/input/event4" /*You can use the "evtest" Linux tool to get the list of devices and test them*/
#endif /*USE_LIBINPUT*/
/*-------------------------------------------------
* Mouse or touchpad as evdev interface (for Linux based systems)
*------------------------------------------------*/
#ifndef USE_EVDEV
# define USE_EVDEV 0
#endif
#ifndef USE_BSD_EVDEV
# define USE_BSD_EVDEV 0
#endif
#if USE_EVDEV || USE_BSD_EVDEV
# define EVDEV_NAME "/dev/input/event4" /*You can use the "evtest" Linux tool to get the list of devices and test them*/
# define EVDEV_SWAP_AXES 0 /*Swap the x and y axes of the touchscreen*/
# define EVDEV_CALIBRATE 1 /*Scale and offset the touchscreen coordinates by using maximum and minimum values for each axis*/
# if EVDEV_CALIBRATE
# define EVDEV_HOR_MIN -3600 /*to invert axis swap EVDEV_XXX_MIN by EVDEV_XXX_MAX*/
# define EVDEV_HOR_MAX 3866 /*"evtest" Linux tool can help to get the correct calibraion values>*/
# define EVDEV_VER_MIN -2444
# define EVDEV_VER_MAX 2550
# endif /*EVDEV_CALIBRATE*/
#endif /*USE_EVDEV*/
/*-------------------------------------------------
* Full keyboard support for evdev and libinput interface
*------------------------------------------------*/
#if USE_LIBINPUT || USE_BSD_LIBINPUT || USE_EVDEV || USE_BSD_EVDEV
# ifndef USE_XKB
# define USE_XKB 1
# endif
# if USE_XKB
# define XKB_KEY_MAP { .rules = NULL, \
.model = "pc101", \
.layout = "us", \
.variant = NULL, \
.options = NULL } /*"setxkbmap -query" can help find the right values for your keyboard*/
# endif /*USE_XKB*/
#endif /*USE_LIBINPUT || USE_BSD_LIBINPUT || USE_EVDEV || USE_BSD_EVDEV*/
/*-------------------------------
* Keyboard of a PC (using SDL)
*------------------------------*/
#ifndef USE_KEYBOARD
# define USE_KEYBOARD 0
#endif
#if USE_KEYBOARD
/*No settings*/
#endif
#endif /*LV_DRV_CONF_H*/
#endif /*End of "Content enable"*/

1
lvgl Submodule

@ -0,0 +1 @@
Subproject commit 2f294aa76c8fece98a4fa72304bc6f267ed2a228

634
main.c Normal file
View file

@ -0,0 +1,634 @@
/**
* Copyright 2021 Johannes Marbach
*
* This file is part of unl0kr, hereafter referred to as the program.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "backends.h"
#include "command_line.h"
#include "config.h"
#include "indev.h"
#include "log.h"
#include "unl0kr.h"
#include "terminal.h"
#include "theme.h"
#include "themes.h"
#include "lv_drv_conf.h"
#if USE_FBDEV
#include "lv_drivers/display/fbdev.h"
#endif /* USE_FBDEV */
#if USE_DRM
#include "lv_drivers/display/drm.h"
#endif /* USE_DRM */
#include "lvgl/lvgl.h"
#include "squeek2lvgl/sq2lv.h"
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/reboot.h>
#include <sys/time.h>
/**
* Static variables
*/
ul_cli_opts cli_opts;
ul_config_opts conf_opts;
bool is_alternate_theme = false;
bool is_password_obscured = true;
bool is_keyboard_hidden = false;
lv_obj_t *keyboard = NULL;
/**
* Static prototypes
*/
/**
* Query the device monitor and handle updates.
*
* @param timer the timer object
*/
static void query_device_monitor(lv_timer_t *timer);
/**
* Handle LV_EVENT_CLICKED events from the theme toggle button.
*
* @param event the event object
*/
static void toggle_theme_btn_clicked_cb(lv_event_t *event);
/**
* Toggle between the light and dark theme.
*/
static void toggle_theme(void);
/**
* Set the UI theme.
*
* @param is_alternate true if the alternate theme should be applied, false if the default theme should be applied
*/
static void set_theme(bool is_alternate);
/**
* Get the UI theme.
*
* @param is_alternate true if the alternate theme should be selected, false if the default theme should be selected
*/
static const ul_theme * get_theme(bool is_alternate);
/**
* Handle LV_EVENT_CLICKED events from the show/hide password toggle button.
*
* @param event the event object
*/
static void toggle_pw_btn_clicked_cb(lv_event_t *event);
/**
* Toggle between showing and hiding the password.
*/
static void toggle_password_obscured(void);
/**
* Show / hide the password.
*
* @param is_hidden true if the password should be hidden, false if it should be shown
*/
static void set_password_obscured(bool is_obscured);
/**
* Handle LV_EVENT_CLICKED events from the show/hide keyboard toggle button.
*
* @param event the event object
*/
static void toggle_kb_btn_clicked_cb(lv_event_t *event);
/**
* Toggle between showing and hiding the keyboard.
*/
static void toggle_keyboard_hidden(void);
/**
* Show / hide the keyboard
*
* @param is_hidden true if the keyboard should be hidden, false if it should be shown
*/
static void set_keyboard_hidden(bool is_hidden);
/**
* Callback for the keyboard's vertical slide in / out animation.
*
* @param obj keyboard widget
* @param value y position
*/
static void keyboard_anim_y_cb(void *obj, int32_t value);
/**
* Handle LV_EVENT_VALUE_CHANGED events from the keyboard layout dropdown.
*
* @param event the event object
*/
static void layout_dropdown_value_changed_cb(lv_event_t *event);
/**
* Handle LV_EVENT_CLICKED events from the shutdown button.
*
* @param event the event object
*/
static void shutdown_btn_clicked_cb(lv_event_t *event);
/**
* Handle LV_EVENT_VALUE_CHANGED events from the shutdown message box.
*
* @param event the event object
*/
static void shutdown_mbox_value_changed_cb(lv_event_t *event);
/**
* Handle LV_EVENT_VALUE_CHANGED events from the keyboard widget.
*
* @param event the event object
*/
static void keyboard_value_changed_cb(lv_event_t *event);
/**
* Handle LV_EVENT_READY events from the keyboard widget.
*
* @param event the event object
*/
static void keyboard_ready_cb(lv_event_t *event);
/**
* Handle LV_EVENT_READY events from the textarea widget.
*
* @param event the event object
*/
static void textarea_ready_cb(lv_event_t *event);
/**
* Print out the entered password and exit.
*
* @param textarea the textarea widget
*/
static void print_password_and_exit(lv_obj_t *textarea);
/**
* Shuts down the device.
*/
static void shutdown(void);
/**
* Handle termination signals sent to the process.
*
* @param signum the signal's number
*/
static void sigaction_handler(int signum);
/**
* Static functions
*/
static void query_device_monitor(lv_timer_t *timer) {
LV_UNUSED(timer);
ul_indev_query_monitor();
}
static void toggle_theme_btn_clicked_cb(lv_event_t *event) {
LV_UNUSED(event);
toggle_theme();
}
static void toggle_theme(void) {
is_alternate_theme = !is_alternate_theme;
set_theme(is_alternate_theme);
}
static void set_theme(bool is_alternate) {
ul_theme_apply(get_theme(is_alternate));
}
static const ul_theme * get_theme(bool is_alternate) {
return ul_themes_themes[is_alternate ? conf_opts.theme.alternate_id : conf_opts.theme.default_id];
}
static void toggle_pw_btn_clicked_cb(lv_event_t *event) {
LV_UNUSED(event);
toggle_password_obscured();
}
static void toggle_password_obscured(void) {
is_password_obscured = !is_password_obscured;
set_password_obscured(is_password_obscured);
}
static void set_password_obscured(bool is_obscured) {
lv_obj_t *textarea = lv_keyboard_get_textarea(keyboard);
lv_textarea_set_password_mode(textarea, is_obscured);
}
static void toggle_kb_btn_clicked_cb(lv_event_t *event) {
LV_UNUSED(event);
toggle_keyboard_hidden();
}
static void toggle_keyboard_hidden(void) {
is_keyboard_hidden = !is_keyboard_hidden;
set_keyboard_hidden(is_keyboard_hidden);
}
static void set_keyboard_hidden(bool is_hidden) {
if (!conf_opts.general.animations) {
lv_obj_set_y(keyboard, is_hidden ? lv_obj_get_height(keyboard) : 0);
return;
}
lv_anim_t keyboard_anim;
lv_anim_init(&keyboard_anim);
lv_anim_set_var(&keyboard_anim, keyboard);
lv_anim_set_values(&keyboard_anim, is_hidden ? 0 : lv_obj_get_height(keyboard), is_hidden ? lv_obj_get_height(keyboard) : 0);
lv_anim_set_path_cb(&keyboard_anim, lv_anim_path_ease_out);
lv_anim_set_time(&keyboard_anim, 500);
lv_anim_set_exec_cb(&keyboard_anim, keyboard_anim_y_cb);
lv_anim_start(&keyboard_anim);
}
static void keyboard_anim_y_cb(void *obj, int32_t value) {
lv_obj_set_y(obj, value);
}
static void layout_dropdown_value_changed_cb(lv_event_t *event) {
lv_obj_t *dropdown = lv_event_get_target(event);
uint16_t idx = lv_dropdown_get_selected(dropdown);
sq2lv_switch_layout(keyboard, idx);
}
static void shutdown_btn_clicked_cb(lv_event_t *event) {
LV_UNUSED(event);
static const char *btns[] = { "Yes", "No", "" };
lv_obj_t *mbox = lv_msgbox_create(NULL, NULL, "Shutdown device?", btns, false);
lv_obj_set_size(mbox, 400, LV_SIZE_CONTENT);
lv_obj_add_event_cb(mbox, shutdown_mbox_value_changed_cb, LV_EVENT_VALUE_CHANGED, NULL);
lv_obj_center(mbox);
}
static void shutdown_mbox_value_changed_cb(lv_event_t *event) {
lv_obj_t *mbox = lv_event_get_current_target(event);
if (lv_msgbox_get_active_btn(mbox) == 0) {
shutdown();
}
lv_msgbox_close(mbox);
}
static void keyboard_value_changed_cb(lv_event_t *event) {
lv_obj_t *kb = lv_event_get_target(event);
uint16_t btn_id = lv_btnmatrix_get_selected_btn(kb);
if (btn_id == LV_BTNMATRIX_BTN_NONE) {
return;
}
if (sq2lv_is_layer_switcher(kb, btn_id)) {
sq2lv_switch_layer(kb, btn_id);
return;
}
lv_keyboard_def_event_cb(event);
}
static void keyboard_ready_cb(lv_event_t *event) {
print_password_and_exit(lv_keyboard_get_textarea(lv_event_get_target(event)));
}
static void textarea_ready_cb(lv_event_t *event) {
print_password_and_exit(lv_event_get_target(event));
}
static void print_password_and_exit(lv_obj_t *textarea) {
/* Print the password to STDOUT */
printf("%s\n", lv_textarea_get_text(textarea));
/* Clear the screen so that when the password field was unobscured, it cannot
* leak via stale display buffers after we've exited */
lv_obj_t *rect = lv_obj_create(lv_scr_act());
lv_obj_set_size(rect, LV_PCT(100), LV_PCT(100));
lv_obj_set_pos(rect, 0, 0);
lv_obj_set_style_bg_opa(rect, LV_OPA_COVER, LV_PART_MAIN);
lv_obj_set_style_bg_color(rect , lv_color_hex(get_theme(is_alternate_theme)->window.bg_color), LV_PART_MAIN);
lv_refr_now(lv_disp_get_default()); /* Force the screen to be drawn */
/* Trigger SIGTERM to exit */
sigaction_handler(SIGTERM);
}
static void shutdown(void) {
sync();
reboot(RB_POWER_OFF);
}
static void sigaction_handler(int signum) {
LV_UNUSED(signum);
ul_terminal_reset_current_terminal();
exit(0);
}
/**
* Main
*/
int main(int argc, char *argv[]) {
/* Parse command line options */
ul_cli_parse_opts(argc, argv, &cli_opts);
/* Set up log level */
if (cli_opts.verbose) {
ul_log_set_level(UL_LOG_LEVEL_VERBOSE);
}
/* Announce ourselves */
ul_log(UL_LOG_LEVEL_VERBOSE, "unl0kr %s", UL_VERSION);
/* Parse config files */
ul_config_init_opts(&conf_opts);
ul_config_parse_file("/etc/unl0kr.conf", &conf_opts);
ul_config_parse_directory("/etc/unl0kr.conf.d", &conf_opts);
ul_config_parse_files(cli_opts.config_files, cli_opts.num_config_files, &conf_opts);
/* Prepare current TTY and clean up on termination */
ul_terminal_prepare_current_terminal(!conf_opts.quirks.terminal_prevent_graphics_mode, !conf_opts.quirks.terminal_allow_keyboard_input);
struct sigaction action;
memset(&action, 0, sizeof(action));
action.sa_handler = sigaction_handler;
sigaction(SIGINT, &action, NULL);
sigaction(SIGTERM, &action, NULL);
/* Initialise LVGL and set up logging callback */
lv_init();
lv_log_register_print_cb(ul_log_print_cb);
/* Initialise display driver */
static lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);
/* Initialise framebuffer driver and query display size */
uint32_t hor_res = 0;
uint32_t ver_res = 0;
uint32_t dpi = 0;
switch (conf_opts.general.backend) {
#if USE_FBDEV
case UL_BACKENDS_BACKEND_FBDEV:
fbdev_init();
if (conf_opts.quirks.fbdev_force_refresh) {
fbdev_force_refresh(true);
}
fbdev_get_sizes(&hor_res, &ver_res, &dpi);
disp_drv.flush_cb = fbdev_flush;
break;
#endif /* USE_FBDEV */
#if USE_DRM
case UL_BACKENDS_BACKEND_DRM:
drm_init();
drm_get_sizes((lv_coord_t *)&hor_res, (lv_coord_t *)&ver_res, &dpi);
disp_drv.flush_cb = drm_flush;
break;
#endif /* USE_DRM */
default:
ul_log(UL_LOG_LEVEL_ERROR, "Unable to find suitable backend");
exit(EXIT_FAILURE);
}
/* Override display parameters with command line options if necessary */
if (cli_opts.hor_res > 0) {
hor_res = cli_opts.hor_res;
}
if (cli_opts.ver_res > 0) {
ver_res = cli_opts.ver_res;
}
if (cli_opts.dpi > 0) {
dpi = cli_opts.dpi;
}
/* Prepare display buffer */
const size_t buf_size = hor_res * ver_res; /* Direct rendering requires using the screen size for the buffer */
lv_disp_draw_buf_t disp_buf;
lv_color_t *buf = (lv_color_t *)malloc(buf_size * sizeof(lv_color_t));
lv_disp_draw_buf_init(&disp_buf, buf, NULL, buf_size);
/* Register display driver */
disp_drv.draw_buf = &disp_buf;
disp_drv.hor_res = hor_res;
disp_drv.ver_res = ver_res;
disp_drv.offset_x = cli_opts.x_offset;
disp_drv.offset_y = cli_opts.y_offset;
disp_drv.dpi = dpi;
disp_drv.direct_mode = true;
lv_disp_drv_register(&disp_drv);
/* Prepare for routing physical keyboard input into the textarea */
lv_group_t *keyboard_input_group = lv_group_create();
ul_indev_set_keyboard_input_group(keyboard_input_group);
/* Start input device monitor and auto-connect available devices */
ul_indev_set_allowed_device_capability(conf_opts.input.keyboard, conf_opts.input.pointer, conf_opts.input.touchscreen);
ul_indev_start_monitor();
lv_timer_create(query_device_monitor, 1000, NULL);
ul_indev_auto_connect();
/* Hide the on-screen keyboard by default if a physical keyboard is connected */
if (conf_opts.keyboard.autohide && ul_indev_is_keyboard_connected()) {
is_keyboard_hidden = true;
}
/* Initialise theme */
set_theme(is_alternate_theme);
/* Prevent scrolling when keyboard is off-screen */
lv_obj_clear_flag(lv_scr_act(), LV_OBJ_FLAG_SCROLLABLE);
/* Figure out a few numbers for sizing and positioning */
const int base_keyboard_height = ver_res > hor_res ? ver_res / 3 : ver_res / 2; /* Height for 4 rows */
const int keyboard_height = base_keyboard_height * 1.25; /* Add space for an extra top row */
const int padding = keyboard_height / 10;
const int textarea_container_max_width = LV_MIN(hor_res, ver_res);
/* Main flexbox */
lv_obj_t *container = lv_obj_create(lv_scr_act());
lv_obj_set_flex_flow(container, LV_FLEX_FLOW_COLUMN);
lv_obj_set_flex_align(container, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
lv_obj_set_size(container, LV_PCT(100), ver_res - keyboard_height);
lv_obj_set_pos(container, 0, 0);
lv_obj_clear_flag(container, LV_OBJ_FLAG_SCROLLABLE);
/* Header flexbox */
lv_obj_t *header = lv_obj_create(container);
lv_obj_add_flag(header, UL_WIDGET_HEADER);
lv_theme_apply(header); /* Force re-apply theme after setting flag so that the widget can be identified */
lv_obj_set_flex_flow(header, LV_FLEX_FLOW_ROW);
lv_obj_set_flex_align(header, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
lv_obj_set_size(header, LV_PCT(100), LV_SIZE_CONTENT);
/* Theme switcher button */
lv_obj_t *toggle_theme_btn = lv_btn_create(header);
lv_obj_add_event_cb(toggle_theme_btn, toggle_theme_btn_clicked_cb, LV_EVENT_CLICKED, NULL);
lv_obj_t *toggle_theme_btn_label = lv_label_create(toggle_theme_btn);
lv_label_set_text(toggle_theme_btn_label, UL_SYMBOL_ADJUST);
lv_obj_center(toggle_theme_btn_label);
/* Show / hide keyboard button */
lv_obj_t *toggle_kb_btn = lv_btn_create(header);
lv_obj_add_event_cb(toggle_kb_btn, toggle_kb_btn_clicked_cb, LV_EVENT_CLICKED, NULL);
lv_obj_t *toggle_kb_btn_label = lv_label_create(toggle_kb_btn);
lv_label_set_text(toggle_kb_btn_label, LV_SYMBOL_KEYBOARD);
lv_obj_center(toggle_kb_btn_label);
/* Keyboard layout dropdown */
lv_obj_t *layout_dropdown = lv_dropdown_create(header);
lv_dropdown_set_options(layout_dropdown, sq2lv_layout_short_names);
lv_obj_add_event_cb(layout_dropdown, layout_dropdown_value_changed_cb, LV_EVENT_VALUE_CHANGED, NULL);
lv_obj_set_width(layout_dropdown, 90);
/* Spacer */
lv_obj_t *spacer = lv_obj_create(header);
lv_obj_set_height(spacer, 0);
lv_obj_set_flex_grow(spacer, 1);
/* Shutdown button */
lv_obj_t *shutdown_btn = lv_btn_create(header);
lv_obj_add_event_cb(shutdown_btn, shutdown_btn_clicked_cb, LV_EVENT_CLICKED, NULL);
lv_obj_t *shutdown_btn_label = lv_label_create(shutdown_btn);
lv_label_set_text(shutdown_btn_label, LV_SYMBOL_POWER);
lv_obj_center(shutdown_btn_label);
/* Flexible spacer */
lv_obj_t *flexible_spacer = lv_obj_create(container);
lv_obj_set_size(flexible_spacer, LV_PCT(100), 0);
lv_obj_set_flex_grow(flexible_spacer, 1);
/* Textarea flexbox */
lv_obj_t *textarea_container = lv_obj_create(container);
lv_obj_set_size(textarea_container, LV_PCT(100), LV_SIZE_CONTENT);
lv_obj_set_style_max_width(textarea_container, textarea_container_max_width, LV_PART_MAIN);
lv_obj_set_flex_flow(textarea_container, LV_FLEX_FLOW_ROW);
lv_obj_set_flex_align(textarea_container, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
lv_obj_set_style_pad_left(textarea_container, padding, LV_PART_MAIN);
lv_obj_set_style_pad_right(textarea_container, padding, LV_PART_MAIN);
/* Textarea */
lv_obj_t *textarea = lv_textarea_create(textarea_container);
lv_textarea_set_one_line(textarea, true);
lv_textarea_set_password_mode(textarea, true);
lv_textarea_set_password_bullet(textarea, conf_opts.textarea.bullet);
lv_textarea_set_placeholder_text(textarea, "Enter password...");
lv_obj_add_event_cb(textarea, textarea_ready_cb, LV_EVENT_READY, NULL);
lv_obj_set_flex_grow(textarea, 1);
lv_obj_add_state(textarea, LV_STATE_FOCUSED);
/* Route physical keyboard input into textarea */
lv_group_add_obj(keyboard_input_group, textarea);
/* Reveal / obscure password button */
lv_obj_t *toggle_pw_btn = lv_btn_create(textarea_container);
const int textarea_height = lv_obj_get_height(textarea);
lv_obj_set_size(toggle_pw_btn, textarea_height, textarea_height);
lv_obj_t *toggle_pw_btn_label = lv_label_create(toggle_pw_btn);
lv_obj_center(toggle_pw_btn_label);
lv_label_set_text(toggle_pw_btn_label, LV_SYMBOL_EYE_OPEN);
lv_obj_add_event_cb(toggle_pw_btn, toggle_pw_btn_clicked_cb, LV_EVENT_CLICKED, NULL);
/* Set header button size to match dropdown (for some reason the height is only available here) */
const int dropwdown_height = lv_obj_get_height(layout_dropdown);
lv_obj_set_size(toggle_theme_btn, dropwdown_height, dropwdown_height);
lv_obj_set_size(toggle_kb_btn, dropwdown_height, dropwdown_height);
lv_obj_set_size(shutdown_btn, dropwdown_height, dropwdown_height);
/* Fixed spacer */
lv_obj_t *fixed_spacer = lv_obj_create(container);
lv_obj_set_size(fixed_spacer, LV_PCT(100), padding);
/* Keyboard (after textarea / label so that key popovers are not drawn over) */
keyboard = lv_keyboard_create(lv_scr_act());
lv_keyboard_set_mode(keyboard, LV_KEYBOARD_MODE_TEXT_LOWER);
lv_keyboard_set_textarea(keyboard, textarea);
lv_obj_remove_event_cb(keyboard, lv_keyboard_def_event_cb);
lv_obj_add_event_cb(keyboard, keyboard_value_changed_cb, LV_EVENT_VALUE_CHANGED, NULL);
lv_obj_add_event_cb(keyboard, keyboard_ready_cb, LV_EVENT_READY, NULL);
lv_obj_set_pos(keyboard, 0, is_keyboard_hidden ? keyboard_height : 0);
lv_obj_set_size(keyboard, hor_res, keyboard_height);
ul_theme_prepare_keyboard(keyboard);
/* Apply textarea options */
set_password_obscured(conf_opts.textarea.obscured);
/* Apply keyboard options */
sq2lv_switch_layout(keyboard, conf_opts.keyboard.layout_id);
lv_dropdown_set_selected(layout_dropdown, conf_opts.keyboard.layout_id);
if (conf_opts.keyboard.popovers) {
lv_keyboard_set_popovers(keyboard, true);
}
/* Run lvgl in "tickless" mode */
uint32_t timeout = conf_opts.general.timeout * 1000; /* ms */
while(1) {
if (!timeout || lv_disp_get_inactive_time(NULL) < timeout) {
lv_task_handler();
} else if (timeout) {
shutdown();
}
usleep(5000);
}
return 0;
}
/**
* Tick generation
*/
/**
* Generate tick for LVGL.
*
* @return tick in ms
*/
uint32_t ul_get_tick(void) {
static uint64_t start_ms = 0;
if (start_ms == 0) {
struct timeval tv_start;
gettimeofday(&tv_start, NULL);
start_ms = (tv_start.tv_sec * 1000000 + tv_start.tv_usec) / 1000;
}
struct timeval tv_now;
gettimeofday(&tv_now, NULL);
uint64_t now_ms;
now_ms = (tv_now.tv_sec * 1000000 + tv_now.tv_usec) / 1000;
uint32_t time_ms = now_ms - start_ms;
return time_ms;
}

98
meson.build Normal file
View file

@ -0,0 +1,98 @@
# Copyright 2021 Clayton Craft
#
# This file is part of unl0kr, hereafter referred to as the program.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# 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. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
project(
'unl0kr',
'c',
version: '2.0.2',
default_options: 'warning_level=3',
meson_version: '>=0.53.0'
)
add_project_arguments('-DUL_VERSION="@0@"'.format(meson.project_version()), language: ['c'])
unl0kr_sources = [
'backends.c',
'command_line.c',
'config.c',
'cursor.c',
'font_32.c',
'indev.c',
'log.c',
'main.c',
'sq2lv_layouts.c',
'terminal.c',
'theme.c',
'themes.c',
]
squeek2lvgl_sources = [
'squeek2lvgl/sq2lv.c',
]
man_files = [
'doc/unl0kr.1',
'doc/unl0kr.conf.5',
]
unl0kr_dependencies = [
dependency('inih'),
dependency('libinput'),
dependency('libudev'),
dependency('xkbcommon'),
]
libdrm_dep = dependency('libdrm', required: get_option('with-drm'))
if libdrm_dep.found()
unl0kr_dependencies += [libdrm_dep]
add_project_arguments('-DUSE_DRM=1', language: ['c'])
endif
lvgl_sources = run_command('find-lvgl-sources.sh', 'lvgl', check: true).stdout().strip().split('\n')
lv_drivers_sources = run_command('find-lvgl-sources.sh', 'lv_drivers', check: true).stdout().strip().split('\n')
install_data(sources: 'unl0kr.conf', install_dir : get_option('sysconfdir'))
executable(
'unl0kr',
sources: unl0kr_sources + squeek2lvgl_sources + lvgl_sources + lv_drivers_sources,
include_directories: ['lvgl', 'lv_drivers'],
dependencies: unl0kr_dependencies,
install: true
)
scdoc = dependency('scdoc')
scdoc_prog = find_program(scdoc.get_pkgconfig_variable('scdoc'), native : true)
sh = find_program('sh', native : true)
foreach file : man_files
filename = file + '.scd'
section = file.split('.')[-1]
topic = file.split('.' + section)[-2].split('/')[-1]
output = '@0@.@1@'.format(topic, section)
custom_target(
output,
input : filename,
output : output,
capture : true,
command : [sh, '-c', scdoc_prog.path() + ' < @INPUT@'],
install : true,
install_dir : get_option('mandir') / 'man' + section
)
endforeach

1
meson_options.txt Normal file
View file

@ -0,0 +1 @@
option('with-drm', type : 'feature', value : 'auto', description : 'Enable DRM backend')

17
regenerate-fonts.sh Executable file
View file

@ -0,0 +1,17 @@
#!/bin/sh -ex
# Copyright 2022 Johannes Marbach
# SPDX-License-Identifier: GPL-3.0-or-later
npx lv_font_conv --bpp 4 --size 32 --no-compress -o font_32.c --format lvgl \
--font OpenSans-Regular.ttf \
--range '0x0020-0x007F' \
--range '0x00A0-0x00FF' \
--range '0x0100-0x017F' \
--range '0x0370-0x03FF' \
--range '0x2000-0x206F' \
--range '0x20A0-0x20CF' \
--range '0x2200-0x22FF' \
--font FontAwesome5-Solid+Brands+Regular.woff \
--range '0xF001,0xF008,0xF00B,0xF00C,0xF00D,0xF011,0xF013,0xF015,0xF019,0xF01C,0xF021,0xF026,0xF027,0xF028,0xF03E,0xF0E0,0xF304,0xF043,0xF048,0xF04B,0xF04C,0xF04D,0xF051,0xF052,0xF053,0xF054,0xF067,0xF068,0xF06E,0xF070,0xF071,0xF074,0xF077,0xF078,0xF079,0xF07B,0xF093,0xF095,0xF0C4,0xF0C5,0xF0C7,0xF0C9,0xF0E7,0xF0EA,0xF0F3,0xF11C,0xF124,0xF158,0xF1EB,0xF240,0xF241,0xF242,0xF243,0xF244,0xF287,0xF293,0xF2ED,0xF55A,0xF7C2,0xF8A2' \
--range '0xF042' \
--range '0xF35B'

36
regenerate-layouts.sh Executable file
View file

@ -0,0 +1,36 @@
#!/bin/bash
# Copyright 2021 Johannes Marbach
#
# This file is part of unl0kr, hereafter referred to as the program.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# 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. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
cd squeek2lvgl
pipenv install
pipenv run python squeek2lvgl.py \
--input us.yaml \
--name "US English" \
--input de.yaml \
--name "Deutsch" \
--input es.yaml \
--name "Español" \
--input fr.yaml \
--name "Français" \
--extra-top-row-base "1 2 3 4 5 6 7 8 9 0" \
--extra-top-row-upper "! @ # $ % ^ & * ( )" \
--output .. \
--surround-space-with-arrows \
--shift-keycap '\xef\x8d\x9b'

98
regenerate-screenshots.sh Executable file
View file

@ -0,0 +1,98 @@
#!/bin/bash
# Change this depending on what device you're generating the screenshots on
fb_res=1920x1080
fb_depth=8
fb_format=rgba
unl0kr=$1
outdir=screenshots
config=unl0kr-screenshots.conf
themes=(
breezy-light
breezy-dark
pmos-light
pmos-dark
)
resolutions=(
# Nokia N900
480x800
800x480
# Samsung Galaxy A3 2015
540x960
960x540
# Samsung Galaxy Tab A 8.0 2015
768x1024
1024x768
# Pine64 PineTab (landscape)
1280x800
# Pine64 PinePhone (landscape)
1440x720
# BQ Aquaris X Pro (landscape)
1920x1080
)
if [[ ! -f $unl0kr || ! -x $unl0kr ]]; then
echo "Error: Could not find unl0kr executable at $unl0kr" 1>&2
exit 1
fi
function write_config() {
cat << EOF > $config
[general]
animations=true
[keyboard]
autohide=false
layout=de
popovers=true
[textarea]
obscured=true
[theme]
default=$1
[input]
keyboard=true
pointer=false
touchscreen=false
EOF
}
function nuke_config() {
rm -f $config
}
trap "nuke_config" EXIT
rm -rf "$outdir"
mkdir "$outdir"
readme="# Unl0kr themes"$'\n'
for theme in ${themes[@]}; do
write_config $theme
readme="$readme"$'\n'"## $theme"$'\n\n'
for res in ${resolutions[@]}; do
CRYPTTAB_SOURCE=/dev/sda1 $unl0kr -g $res -C unl0kr-screenshots.conf &
pid=$!
sleep 3 # Wait for UI to render
cat /dev/fb0 > "$outdir/$theme-$res"
convert -size $fb_res -depth $fb_depth $fb_format:"$outdir/$theme-$res" -crop $res+0+0 "$outdir/$theme-$res.png"
rm "$outdir/$theme-$res"
kill -15 $pid
readme="$readme<img src=\"$theme-$res.png\" alt=\"$res\" height=\"300\"/>"$'\n'
sleep 1 # Delay to prevent terminal mode set / reset interference
done
done
echo -n "$readme" > "$outdir/README.md"

28
release.sh Executable file
View file

@ -0,0 +1,28 @@
#!/bin/bash
if [[ -z "$1" ]]; then
echo "Error: No version number provided"
exit 1
fi
if [[ -z "$2" ]]; then
echo "Error: No GitLab API token provided"
exit 1
fi
if ! grep "## $1" CHANGELOG.md > /dev/null; then
echo "Error: No entry in CHANGELOG.md for version $1"
exit 1
fi
if ! grep -E "^\s*version:\s*'$1'" meson.build > /dev/null; then
echo "Error: Version $1 differs from version in meson.build"
exit 1
fi
git tag "$1"
git push --tags
./archive.sh "$2"
echo "Now create a release for https://gitlab.com/cherrypicker/unl0kr/-/tags/$1 and attach the uploaded archive"

49
screenshots/README.md Normal file
View file

@ -0,0 +1,49 @@
# Unl0kr themes
## breezy-light
<img src="breezy-light-480x800.png" alt="480x800" height="300"/>
<img src="breezy-light-800x480.png" alt="800x480" height="300"/>
<img src="breezy-light-540x960.png" alt="540x960" height="300"/>
<img src="breezy-light-960x540.png" alt="960x540" height="300"/>
<img src="breezy-light-768x1024.png" alt="768x1024" height="300"/>
<img src="breezy-light-1024x768.png" alt="1024x768" height="300"/>
<img src="breezy-light-1280x800.png" alt="1280x800" height="300"/>
<img src="breezy-light-1440x720.png" alt="1440x720" height="300"/>
<img src="breezy-light-1920x1080.png" alt="1920x1080" height="300"/>
## breezy-dark
<img src="breezy-dark-480x800.png" alt="480x800" height="300"/>
<img src="breezy-dark-800x480.png" alt="800x480" height="300"/>
<img src="breezy-dark-540x960.png" alt="540x960" height="300"/>
<img src="breezy-dark-960x540.png" alt="960x540" height="300"/>
<img src="breezy-dark-768x1024.png" alt="768x1024" height="300"/>
<img src="breezy-dark-1024x768.png" alt="1024x768" height="300"/>
<img src="breezy-dark-1280x800.png" alt="1280x800" height="300"/>
<img src="breezy-dark-1440x720.png" alt="1440x720" height="300"/>
<img src="breezy-dark-1920x1080.png" alt="1920x1080" height="300"/>
## pmos-light
<img src="pmos-light-480x800.png" alt="480x800" height="300"/>
<img src="pmos-light-800x480.png" alt="800x480" height="300"/>
<img src="pmos-light-540x960.png" alt="540x960" height="300"/>
<img src="pmos-light-960x540.png" alt="960x540" height="300"/>
<img src="pmos-light-768x1024.png" alt="768x1024" height="300"/>
<img src="pmos-light-1024x768.png" alt="1024x768" height="300"/>
<img src="pmos-light-1280x800.png" alt="1280x800" height="300"/>
<img src="pmos-light-1440x720.png" alt="1440x720" height="300"/>
<img src="pmos-light-1920x1080.png" alt="1920x1080" height="300"/>
## pmos-dark
<img src="pmos-dark-480x800.png" alt="480x800" height="300"/>
<img src="pmos-dark-800x480.png" alt="800x480" height="300"/>
<img src="pmos-dark-540x960.png" alt="540x960" height="300"/>
<img src="pmos-dark-960x540.png" alt="960x540" height="300"/>
<img src="pmos-dark-768x1024.png" alt="768x1024" height="300"/>
<img src="pmos-dark-1024x768.png" alt="1024x768" height="300"/>
<img src="pmos-dark-1280x800.png" alt="1280x800" height="300"/>
<img src="pmos-dark-1440x720.png" alt="1440x720" height="300"/>
<img src="pmos-dark-1920x1080.png" alt="1920x1080" height="300"/>

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

948
sq2lv_layouts.c Normal file
View file

@ -0,0 +1,948 @@
/**
* Auto-generated with squeek2lvgl
**/
#include "sq2lv_layouts.h"
#define SQ2LV_SYMBOL_SHIFT "\xef\x8d\x9b"
/**
* Layout: US English - generated from us
**/
static const char * const name_us = "US English";
static const char * const short_name_us = "us";
/* Layer: Lowercase letters - generated from base */
static const int num_keys_lower_us = 44;
static const char * const keycaps_lower_us[] = { \
"1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "\n", \
"q", "w", "e", "r", "t", "y", "u", "i", "o", "p", "\n", \
"a", "s", "d", "f", "g", "h", "j", "k", "l", "\n", \
SQ2LV_SYMBOL_SHIFT, "z", "x", "c", "v", "b", "n", "m", LV_SYMBOL_BACKSPACE, "\n", \
"123", LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, ".", LV_SYMBOL_OK, "" \
};
static const lv_btnmatrix_ctrl_t attributes_lower_us[] = { \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, \
SQ2LV_CTRL_MOD_INACTIVE | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3, \
SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 2, 7, SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3 \
};
static const int num_modifiers_lower_us = 0;
static const int * const modifier_idxs_lower_us = NULL;
static const int num_switchers_lower_us = 2;
static const int switcher_idxs_lower_us[] = { \
29, 38 \
};
static const int switcher_dests_lower_us[] = { \
1, 2 \
};
/* Layer: Uppercase letters - generated from upper */
static const int num_keys_upper_us = 44;
static const char * const keycaps_upper_us[] = { \
"!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "\n", \
"Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "\n", \
"A", "S", "D", "F", "G", "H", "J", "K", "L", "\n", \
SQ2LV_SYMBOL_SHIFT, "Z", "X", "C", "V", "B", "N", "M", LV_SYMBOL_BACKSPACE, "\n", \
"123", LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, ".", LV_SYMBOL_OK, "" \
};
static const lv_btnmatrix_ctrl_t attributes_upper_us[] = { \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, \
SQ2LV_CTRL_MOD_ACTIVE | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3, \
SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 2, 7, SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3 \
};
static const int num_modifiers_upper_us = 0;
static const int * const modifier_idxs_upper_us = NULL;
static const int num_switchers_upper_us = 2;
static const int switcher_idxs_upper_us[] = { \
29, 38 \
};
static const int switcher_dests_upper_us[] = { \
0, 2 \
};
/* Layer: Numbers / symbols - generated from numbers */
static const int num_keys_numbers_us = 36;
static const char * const keycaps_numbers_us[] = { \
"<hidden>", "\n", \
"1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "\n", \
"@", "#", "$", "%", "&", "-", "_", "+", "(", ")", "\n", \
"*/=", ",", "\"", "'", ":", ";", "!", "?", LV_SYMBOL_BACKSPACE, "\n", \
"ABC", LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, ".", LV_SYMBOL_OK, "" \
};
static const lv_btnmatrix_ctrl_t attributes_numbers_us[] = { \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_HIDDEN | 2, \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, \
SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3, \
SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 2, 7, SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3 \
};
static const int num_modifiers_numbers_us = 0;
static const int * const modifier_idxs_numbers_us = NULL;
static const int num_switchers_numbers_us = 2;
static const int switcher_idxs_numbers_us[] = { \
21, 30 \
};
static const int switcher_dests_numbers_us[] = { \
3, 0 \
};
/* Layer: Symbols - generated from symbols */
static const int num_keys_symbols_us = 36;
static const char * const keycaps_symbols_us[] = { \
"<hidden>", "\n", \
"~", "`", "|", "·", "", "π", "τ", "÷", "×", "", "\n", \
"©", "®", "£", "", "¥", "^", "°", "*", "{", "}", "\n", \
"123", "\\", "/", "<", ">", "=", "[", "]", LV_SYMBOL_BACKSPACE, "\n", \
"ABC", LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, ".", LV_SYMBOL_OK, "" \
};
static const lv_btnmatrix_ctrl_t attributes_symbols_us[] = { \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_HIDDEN | 2, \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, \
SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3, \
SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 2, 7, SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3 \
};
static const int num_modifiers_symbols_us = 0;
static const int * const modifier_idxs_symbols_us = NULL;
static const int num_switchers_symbols_us = 2;
static const int switcher_idxs_symbols_us[] = { \
21, 30 \
};
static const int switcher_dests_symbols_us[] = { \
2, 0 \
};
/* Layer array */
static const int num_layers_us = 4;
static const sq2lv_layer_t layers_us[] = {
{
.num_keys = num_keys_lower_us,
.keycaps = keycaps_lower_us,
.attributes = attributes_lower_us,
.num_modifiers = num_modifiers_lower_us,
.modifier_idxs = modifier_idxs_lower_us,
.num_switchers = num_switchers_lower_us,
.switcher_idxs = switcher_idxs_lower_us,
.switcher_dests = switcher_dests_lower_us
},
{
.num_keys = num_keys_upper_us,
.keycaps = keycaps_upper_us,
.attributes = attributes_upper_us,
.num_modifiers = num_modifiers_upper_us,
.modifier_idxs = modifier_idxs_upper_us,
.num_switchers = num_switchers_upper_us,
.switcher_idxs = switcher_idxs_upper_us,
.switcher_dests = switcher_dests_upper_us
},
{
.num_keys = num_keys_numbers_us,
.keycaps = keycaps_numbers_us,
.attributes = attributes_numbers_us,
.num_modifiers = num_modifiers_numbers_us,
.modifier_idxs = modifier_idxs_numbers_us,
.num_switchers = num_switchers_numbers_us,
.switcher_idxs = switcher_idxs_numbers_us,
.switcher_dests = switcher_dests_numbers_us
},
{
.num_keys = num_keys_symbols_us,
.keycaps = keycaps_symbols_us,
.attributes = attributes_symbols_us,
.num_modifiers = num_modifiers_symbols_us,
.modifier_idxs = modifier_idxs_symbols_us,
.num_switchers = num_switchers_symbols_us,
.switcher_idxs = switcher_idxs_symbols_us,
.switcher_dests = switcher_dests_symbols_us
}
};
/**
* Layout: Deutsch - generated from de
**/
static const char * const name_de = "Deutsch";
static const char * const short_name_de = "de";
/* Layer: Lowercase letters - generated from base */
static const int num_keys_lower_de = 46;
static const char * const keycaps_lower_de[] = { \
"1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "\n", \
"q", "w", "e", "r", "t", "z", "u", "i", "o", "p", "\n", \
"a", "s", "d", "f", "g", "h", "j", "k", "l", "\n", \
SQ2LV_SYMBOL_SHIFT, "y", "x", "c", "v", "b", "n", "m", LV_SYMBOL_BACKSPACE, "\n", \
"123", "äÄ", LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, ",", ".", LV_SYMBOL_OK, "" \
};
static const lv_btnmatrix_ctrl_t attributes_lower_de[] = { \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, \
SQ2LV_CTRL_MOD_INACTIVE | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3, \
SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_MOD_INACTIVE | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 2, 7, SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3 \
};
static const int num_modifiers_lower_de = 0;
static const int * const modifier_idxs_lower_de = NULL;
static const int num_switchers_lower_de = 3;
static const int switcher_idxs_lower_de[] = { \
29, 38, 39 \
};
static const int switcher_dests_lower_de[] = { \
1, 2, 4 \
};
/* Layer: Uppercase letters - generated from upper */
static const int num_keys_upper_de = 46;
static const char * const keycaps_upper_de[] = { \
"!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "\n", \
"Q", "W", "E", "R", "T", "Z", "U", "I", "O", "P", "\n", \
"A", "S", "D", "F", "G", "H", "J", "K", "L", "\n", \
SQ2LV_SYMBOL_SHIFT, "Y", "X", "C", "V", "B", "N", "M", LV_SYMBOL_BACKSPACE, "\n", \
"123", "äÄ", LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, "!", "?", LV_SYMBOL_OK, "" \
};
static const lv_btnmatrix_ctrl_t attributes_upper_de[] = { \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, \
SQ2LV_CTRL_MOD_ACTIVE | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3, \
SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_MOD_INACTIVE | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 2, 7, SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3 \
};
static const int num_modifiers_upper_de = 0;
static const int * const modifier_idxs_upper_de = NULL;
static const int num_switchers_upper_de = 3;
static const int switcher_idxs_upper_de[] = { \
29, 38, 39 \
};
static const int switcher_dests_upper_de[] = { \
0, 2, 4 \
};
/* Layer: Numbers / symbols - generated from numbers */
static const int num_keys_numbers_de = 38;
static const char * const keycaps_numbers_de[] = { \
"<hidden>", "\n", \
"1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "\n", \
"@", "#", "", "%", "&", "-", "_", "+", "(", ")", "\n", \
"*/=", ";", "\"", "'", ":", "=", "<", ">", LV_SYMBOL_BACKSPACE, "\n", \
"abc", "äÄ", LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, ",", ".", LV_SYMBOL_OK, "" \
};
static const lv_btnmatrix_ctrl_t attributes_numbers_de[] = { \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_HIDDEN | 2, \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, \
SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3, \
SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_MOD_INACTIVE | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 2, 7, SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3 \
};
static const int num_modifiers_numbers_de = 0;
static const int * const modifier_idxs_numbers_de = NULL;
static const int num_switchers_numbers_de = 3;
static const int switcher_idxs_numbers_de[] = { \
21, 30, 31 \
};
static const int switcher_dests_numbers_de[] = { \
3, 0, 4 \
};
/* Layer: Symbols - generated from symbols */
static const int num_keys_symbols_de = 38;
static const char * const keycaps_symbols_de[] = { \
"<hidden>", "\n", \
"~", "`", "´", "|", "·", "", "µ", "÷", "×", "", "\n", \
"©", "®", "£", "$", "¥", "^", "°", "*", "{", "}", "\n", \
"123", "\\", "/", "§", "π", "τ", "[", "]", LV_SYMBOL_BACKSPACE, "\n", \
"abc", "äÄ", LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, ",", ".", LV_SYMBOL_OK, "" \
};
static const lv_btnmatrix_ctrl_t attributes_symbols_de[] = { \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_HIDDEN | 2, \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, \
SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3, \
SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_MOD_INACTIVE | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 2, 7, SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3 \
};
static const int num_modifiers_symbols_de = 0;
static const int * const modifier_idxs_symbols_de = NULL;
static const int num_switchers_symbols_de = 3;
static const int switcher_idxs_symbols_de[] = { \
21, 30, 31 \
};
static const int switcher_dests_symbols_de[] = { \
2, 0, 4 \
};
/* Layer: Special characters - generated from eschars */
static const int num_keys_special_de = 38;
static const char * const keycaps_special_de[] = { \
"<hidden>", "\n", \
"ä", "è", "é", "ö", "ü", "Ä", "È", "É", "Ö", "Ü", "\n", \
"à", "â", "ê", "î", "ô", "À", "Â", "È", "Î", "Ô", "\n", \
"123", "«", "»", "ç", "Ç", "æ", "œ", "ß", LV_SYMBOL_BACKSPACE, "\n", \
"abc", "äÄ", LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, "", "", LV_SYMBOL_OK, "" \
};
static const lv_btnmatrix_ctrl_t attributes_special_de[] = { \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_HIDDEN | 2, \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, \
SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3, \
SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_MOD_ACTIVE | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 2, 7, SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3 \
};
static const int num_modifiers_special_de = 0;
static const int * const modifier_idxs_special_de = NULL;
static const int num_switchers_special_de = 3;
static const int switcher_idxs_special_de[] = { \
21, 30, 31 \
};
static const int switcher_dests_special_de[] = { \
2, 0, 0 \
};
/* Layer array */
static const int num_layers_de = 5;
static const sq2lv_layer_t layers_de[] = {
{
.num_keys = num_keys_lower_de,
.keycaps = keycaps_lower_de,
.attributes = attributes_lower_de,
.num_modifiers = num_modifiers_lower_de,
.modifier_idxs = modifier_idxs_lower_de,
.num_switchers = num_switchers_lower_de,
.switcher_idxs = switcher_idxs_lower_de,
.switcher_dests = switcher_dests_lower_de
},
{
.num_keys = num_keys_upper_de,
.keycaps = keycaps_upper_de,
.attributes = attributes_upper_de,
.num_modifiers = num_modifiers_upper_de,
.modifier_idxs = modifier_idxs_upper_de,
.num_switchers = num_switchers_upper_de,
.switcher_idxs = switcher_idxs_upper_de,
.switcher_dests = switcher_dests_upper_de
},
{
.num_keys = num_keys_numbers_de,
.keycaps = keycaps_numbers_de,
.attributes = attributes_numbers_de,
.num_modifiers = num_modifiers_numbers_de,
.modifier_idxs = modifier_idxs_numbers_de,
.num_switchers = num_switchers_numbers_de,
.switcher_idxs = switcher_idxs_numbers_de,
.switcher_dests = switcher_dests_numbers_de
},
{
.num_keys = num_keys_symbols_de,
.keycaps = keycaps_symbols_de,
.attributes = attributes_symbols_de,
.num_modifiers = num_modifiers_symbols_de,
.modifier_idxs = modifier_idxs_symbols_de,
.num_switchers = num_switchers_symbols_de,
.switcher_idxs = switcher_idxs_symbols_de,
.switcher_dests = switcher_dests_symbols_de
},
{
.num_keys = num_keys_special_de,
.keycaps = keycaps_special_de,
.attributes = attributes_special_de,
.num_modifiers = num_modifiers_special_de,
.modifier_idxs = modifier_idxs_special_de,
.num_switchers = num_switchers_special_de,
.switcher_idxs = switcher_idxs_special_de,
.switcher_dests = switcher_dests_special_de
}
};
/**
* Layout: Español - generated from es
**/
static const char * const name_es = "Español";
static const char * const short_name_es = "es";
/* Layer: Lowercase letters - generated from base */
static const int num_keys_lower_es = 47;
static const char * const keycaps_lower_es[] = { \
"1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "\n", \
"q", "w", "e", "r", "t", "y", "u", "i", "o", "p", "\n", \
"a", "s", "d", "f", "g", "h", "j", "k", "l", "ñ", "\n", \
SQ2LV_SYMBOL_SHIFT, "z", "x", "c", "v", "b", "n", "m", LV_SYMBOL_BACKSPACE, "\n", \
"123", "áÁ", LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, "?", ".", LV_SYMBOL_OK, "" \
};
static const lv_btnmatrix_ctrl_t attributes_lower_es[] = { \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, \
SQ2LV_CTRL_MOD_INACTIVE | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3, \
SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_MOD_INACTIVE | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 2, 7, SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3 \
};
static const int num_modifiers_lower_es = 0;
static const int * const modifier_idxs_lower_es = NULL;
static const int num_switchers_lower_es = 3;
static const int switcher_idxs_lower_es[] = { \
30, 39, 40 \
};
static const int switcher_dests_lower_es[] = { \
1, 2, 4 \
};
/* Layer: Uppercase letters - generated from upper */
static const int num_keys_upper_es = 47;
static const char * const keycaps_upper_es[] = { \
"!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "\n", \
"Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "\n", \
"A", "S", "D", "F", "G", "H", "J", "K", "L", "Ñ", "\n", \
SQ2LV_SYMBOL_SHIFT, "Z", "X", "C", "V", "B", "N", "M", LV_SYMBOL_BACKSPACE, "\n", \
"123", "áÁ", LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, "¿", ".", LV_SYMBOL_OK, "" \
};
static const lv_btnmatrix_ctrl_t attributes_upper_es[] = { \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, \
SQ2LV_CTRL_MOD_ACTIVE | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3, \
SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_MOD_INACTIVE | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 2, 7, SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3 \
};
static const int num_modifiers_upper_es = 0;
static const int * const modifier_idxs_upper_es = NULL;
static const int num_switchers_upper_es = 3;
static const int switcher_idxs_upper_es[] = { \
30, 39, 40 \
};
static const int switcher_dests_upper_es[] = { \
0, 2, 4 \
};
/* Layer: Numbers / symbols - generated from numbers */
static const int num_keys_numbers_es = 38;
static const char * const keycaps_numbers_es[] = { \
"<hidden>", "\n", \
"1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "\n", \
"@", "#", "", "%", "&", "-", "_", "+", "(", ")", "\n", \
"*/=", ",", "\"", "'", ":", ";", "!", "=", LV_SYMBOL_BACKSPACE, "\n", \
"abc", "áÁ", LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, "?", ".", LV_SYMBOL_OK, "" \
};
static const lv_btnmatrix_ctrl_t attributes_numbers_es[] = { \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_HIDDEN | 2, \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, \
SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3, \
SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_MOD_INACTIVE | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 2, 7, SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3 \
};
static const int num_modifiers_numbers_es = 0;
static const int * const modifier_idxs_numbers_es = NULL;
static const int num_switchers_numbers_es = 3;
static const int switcher_idxs_numbers_es[] = { \
21, 30, 31 \
};
static const int switcher_dests_numbers_es[] = { \
3, 0, 4 \
};
/* Layer: Symbols - generated from symbols */
static const int num_keys_symbols_es = 38;
static const char * const keycaps_symbols_es[] = { \
"<hidden>", "\n", \
"~", "`", "|", "·", "", "π", "τ", "÷", "×", "", "\n", \
"©", "®", "£", "$", "¥", "^", "°", "*", "{", "}", "\n", \
"123", "\\", "/", "<", ">", "=", "[", "]", LV_SYMBOL_BACKSPACE, "\n", \
"abc", "áÁ", LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, "?", ".", LV_SYMBOL_OK, "" \
};
static const lv_btnmatrix_ctrl_t attributes_symbols_es[] = { \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_HIDDEN | 2, \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, \
SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3, \
SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_MOD_INACTIVE | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 2, 7, SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3 \
};
static const int num_modifiers_symbols_es = 0;
static const int * const modifier_idxs_symbols_es = NULL;
static const int num_switchers_symbols_es = 3;
static const int switcher_idxs_symbols_es[] = { \
21, 30, 31 \
};
static const int switcher_dests_symbols_es[] = { \
2, 0, 4 \
};
/* Layer: Special characters - generated from eschars */
static const int num_keys_special_es = 38;
static const char * const keycaps_special_es[] = { \
"<hidden>", "\n", \
"á", "é", "í", "ó", "ú", "Á", "É", "Í", "Ó", "Ú", "\n", \
"à", "è", "ì", "ò", "ù", "À", "È", "Ì", "Ò", "Ù", "\n", \
"123", "ü", "ç", "ï", "Ü", "Ç", "Ï", "¡", LV_SYMBOL_BACKSPACE, "\n", \
"abc", "áÁ", LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, "«", "»", LV_SYMBOL_OK, "" \
};
static const lv_btnmatrix_ctrl_t attributes_special_es[] = { \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_HIDDEN | 2, \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, \
SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3, \
SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_MOD_ACTIVE | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 2, 7, SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3 \
};
static const int num_modifiers_special_es = 0;
static const int * const modifier_idxs_special_es = NULL;
static const int num_switchers_special_es = 3;
static const int switcher_idxs_special_es[] = { \
21, 30, 31 \
};
static const int switcher_dests_special_es[] = { \
2, 0, 0 \
};
/* Layer array */
static const int num_layers_es = 5;
static const sq2lv_layer_t layers_es[] = {
{
.num_keys = num_keys_lower_es,
.keycaps = keycaps_lower_es,
.attributes = attributes_lower_es,
.num_modifiers = num_modifiers_lower_es,
.modifier_idxs = modifier_idxs_lower_es,
.num_switchers = num_switchers_lower_es,
.switcher_idxs = switcher_idxs_lower_es,
.switcher_dests = switcher_dests_lower_es
},
{
.num_keys = num_keys_upper_es,
.keycaps = keycaps_upper_es,
.attributes = attributes_upper_es,
.num_modifiers = num_modifiers_upper_es,
.modifier_idxs = modifier_idxs_upper_es,
.num_switchers = num_switchers_upper_es,
.switcher_idxs = switcher_idxs_upper_es,
.switcher_dests = switcher_dests_upper_es
},
{
.num_keys = num_keys_numbers_es,
.keycaps = keycaps_numbers_es,
.attributes = attributes_numbers_es,
.num_modifiers = num_modifiers_numbers_es,
.modifier_idxs = modifier_idxs_numbers_es,
.num_switchers = num_switchers_numbers_es,
.switcher_idxs = switcher_idxs_numbers_es,
.switcher_dests = switcher_dests_numbers_es
},
{
.num_keys = num_keys_symbols_es,
.keycaps = keycaps_symbols_es,
.attributes = attributes_symbols_es,
.num_modifiers = num_modifiers_symbols_es,
.modifier_idxs = modifier_idxs_symbols_es,
.num_switchers = num_switchers_symbols_es,
.switcher_idxs = switcher_idxs_symbols_es,
.switcher_dests = switcher_dests_symbols_es
},
{
.num_keys = num_keys_special_es,
.keycaps = keycaps_special_es,
.attributes = attributes_special_es,
.num_modifiers = num_modifiers_special_es,
.modifier_idxs = modifier_idxs_special_es,
.num_switchers = num_switchers_special_es,
.switcher_idxs = switcher_idxs_special_es,
.switcher_dests = switcher_dests_special_es
}
};
/**
* Layout: Français - generated from fr
**/
static const char * const name_fr = "Français";
static const char * const short_name_fr = "fr";
/* Layer: Lowercase letters - generated from base */
static const int num_keys_lower_fr = 45;
static const char * const keycaps_lower_fr[] = { \
"1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "\n", \
"a", "z", "e", "r", "t", "y", "u", "i", "o", "p", "\n", \
"q", "s", "d", "f", "g", "h", "j", "k", "l", "m", "\n", \
SQ2LV_SYMBOL_SHIFT, "w", "x", "c", "v", "b", "n", ".", LV_SYMBOL_BACKSPACE, "\n", \
"123", LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, "âÂ", LV_SYMBOL_OK, "" \
};
static const lv_btnmatrix_ctrl_t attributes_lower_fr[] = { \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, \
SQ2LV_CTRL_MOD_INACTIVE | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3, \
SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 2, 7, SQ2LV_CTRL_NON_CHAR | 2, SQ2LV_CTRL_MOD_INACTIVE | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 3 \
};
static const int num_modifiers_lower_fr = 0;
static const int * const modifier_idxs_lower_fr = NULL;
static const int num_switchers_lower_fr = 3;
static const int switcher_idxs_lower_fr[] = { \
30, 39, 43 \
};
static const int switcher_dests_lower_fr[] = { \
1, 2, 4 \
};
/* Layer: Uppercase letters - generated from upper */
static const int num_keys_upper_fr = 45;
static const char * const keycaps_upper_fr[] = { \
"!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "\n", \
"A", "Z", "E", "R", "T", "Y", "U", "I", "O", "P", "\n", \
"Q", "S", "D", "F", "G", "H", "J", "K", "L", "M", "\n", \
SQ2LV_SYMBOL_SHIFT, "W", "X", "C", "V", "B", "N", ",", LV_SYMBOL_BACKSPACE, "\n", \
"123", LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, "âÂ", LV_SYMBOL_OK, "" \
};
static const lv_btnmatrix_ctrl_t attributes_upper_fr[] = { \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | 2, \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, \
SQ2LV_CTRL_MOD_ACTIVE | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3, \
SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 2, 7, SQ2LV_CTRL_NON_CHAR | 2, SQ2LV_CTRL_MOD_INACTIVE | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 3 \
};
static const int num_modifiers_upper_fr = 0;
static const int * const modifier_idxs_upper_fr = NULL;
static const int num_switchers_upper_fr = 3;
static const int switcher_idxs_upper_fr[] = { \
30, 39, 43 \
};
static const int switcher_dests_upper_fr[] = { \
0, 2, 4 \
};
/* Layer: Numbers / symbols - generated from numbers */
static const int num_keys_numbers_fr = 36;
static const char * const keycaps_numbers_fr[] = { \
"<hidden>", "\n", \
"1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "\n", \
"@", "#", "", "%", "&", "-", "_", "+", "(", ")", "\n", \
"*/=", ",", "\"", "'", ":", ";", "!", "?", LV_SYMBOL_BACKSPACE, "\n", \
"abc", LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, "âÂ", LV_SYMBOL_OK, "" \
};
static const lv_btnmatrix_ctrl_t attributes_numbers_fr[] = { \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_HIDDEN | 2, \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, \
SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3, \
SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 2, 7, SQ2LV_CTRL_NON_CHAR | 2, SQ2LV_CTRL_MOD_INACTIVE | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 3 \
};
static const int num_modifiers_numbers_fr = 0;
static const int * const modifier_idxs_numbers_fr = NULL;
static const int num_switchers_numbers_fr = 3;
static const int switcher_idxs_numbers_fr[] = { \
21, 30, 34 \
};
static const int switcher_dests_numbers_fr[] = { \
3, 0, 4 \
};
/* Layer: Symbols - generated from symbols */
static const int num_keys_symbols_fr = 36;
static const char * const keycaps_symbols_fr[] = { \
"<hidden>", "\n", \
"~", "`", "|", "·", "", "π", "τ", "÷", "×", "", "\n", \
"©", "®", "£", "$", "¥", "^", "°", "*", "{", "}", "\n", \
"123", "\\", "/", "<", ">", "=", "[", "]", LV_SYMBOL_BACKSPACE, "\n", \
"abc", LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, "âÂ", LV_SYMBOL_OK, "" \
};
static const lv_btnmatrix_ctrl_t attributes_symbols_fr[] = { \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_HIDDEN | 2, \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, \
SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3, \
SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 2, 7, SQ2LV_CTRL_NON_CHAR | 2, SQ2LV_CTRL_MOD_INACTIVE | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 3 \
};
static const int num_modifiers_symbols_fr = 0;
static const int * const modifier_idxs_symbols_fr = NULL;
static const int num_switchers_symbols_fr = 3;
static const int switcher_idxs_symbols_fr[] = { \
21, 30, 34 \
};
static const int switcher_dests_symbols_fr[] = { \
2, 0, 4 \
};
/* Layer: Special characters - generated from eschars */
static const int num_keys_special_fr = 36;
static const char * const keycaps_special_fr[] = { \
"<hidden>", "\n", \
"à", "â", "ç", "é", "è", "ê", "î", "ô", "ù", "û", "\n", \
"À", "Â", "Ç", "É", "È", "Ê", "Î", "Ô", "Ù", "Û", "\n", \
"123", "æ", "œ", "ä", "ë", "ï", "ö", "ü", LV_SYMBOL_BACKSPACE, "\n", \
"abc", LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, "âÂ", LV_SYMBOL_OK, "" \
};
static const lv_btnmatrix_ctrl_t attributes_special_fr[] = { \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_HIDDEN | 2, \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, \
LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, \
SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, LV_BTNMATRIX_CTRL_POPOVER | LV_BTNMATRIX_CTRL_NO_REPEAT | 2, SQ2LV_CTRL_NON_CHAR | 3, \
SQ2LV_CTRL_NON_CHAR | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 2, 7, SQ2LV_CTRL_NON_CHAR | 2, SQ2LV_CTRL_MOD_ACTIVE | LV_BTNMATRIX_CTRL_NO_REPEAT | 3, SQ2LV_CTRL_NON_CHAR | 3 \
};
static const int num_modifiers_special_fr = 0;
static const int * const modifier_idxs_special_fr = NULL;
static const int num_switchers_special_fr = 3;
static const int switcher_idxs_special_fr[] = { \
21, 30, 34 \
};
static const int switcher_dests_special_fr[] = { \
2, 0, 0 \
};
/* Layer array */
static const int num_layers_fr = 5;
static const sq2lv_layer_t layers_fr[] = {
{
.num_keys = num_keys_lower_fr,
.keycaps = keycaps_lower_fr,
.attributes = attributes_lower_fr,
.num_modifiers = num_modifiers_lower_fr,
.modifier_idxs = modifier_idxs_lower_fr,
.num_switchers = num_switchers_lower_fr,
.switcher_idxs = switcher_idxs_lower_fr,
.switcher_dests = switcher_dests_lower_fr
},
{
.num_keys = num_keys_upper_fr,
.keycaps = keycaps_upper_fr,
.attributes = attributes_upper_fr,
.num_modifiers = num_modifiers_upper_fr,
.modifier_idxs = modifier_idxs_upper_fr,
.num_switchers = num_switchers_upper_fr,
.switcher_idxs = switcher_idxs_upper_fr,
.switcher_dests = switcher_dests_upper_fr
},
{
.num_keys = num_keys_numbers_fr,
.keycaps = keycaps_numbers_fr,
.attributes = attributes_numbers_fr,
.num_modifiers = num_modifiers_numbers_fr,
.modifier_idxs = modifier_idxs_numbers_fr,
.num_switchers = num_switchers_numbers_fr,
.switcher_idxs = switcher_idxs_numbers_fr,
.switcher_dests = switcher_dests_numbers_fr
},
{
.num_keys = num_keys_symbols_fr,
.keycaps = keycaps_symbols_fr,
.attributes = attributes_symbols_fr,
.num_modifiers = num_modifiers_symbols_fr,
.modifier_idxs = modifier_idxs_symbols_fr,
.num_switchers = num_switchers_symbols_fr,
.switcher_idxs = switcher_idxs_symbols_fr,
.switcher_dests = switcher_dests_symbols_fr
},
{
.num_keys = num_keys_special_fr,
.keycaps = keycaps_special_fr,
.attributes = attributes_special_fr,
.num_modifiers = num_modifiers_special_fr,
.modifier_idxs = modifier_idxs_special_fr,
.num_switchers = num_switchers_special_fr,
.switcher_idxs = switcher_idxs_special_fr,
.switcher_dests = switcher_dests_special_fr
}
};
/**
* Public interface
**/
const int sq2lv_num_layouts = 4;
const sq2lv_layout_t sq2lv_layouts[] = {
/* US English */
{
.name = name_us,
.short_name = short_name_us,
.num_layers = num_layers_us,
.layers = layers_us
},
/* Deutsch */
{
.name = name_de,
.short_name = short_name_de,
.num_layers = num_layers_de,
.layers = layers_de
},
/* Español */
{
.name = name_es,
.short_name = short_name_es,
.num_layers = num_layers_es,
.layers = layers_es
},
/* Français */
{
.name = name_fr,
.short_name = short_name_fr,
.num_layers = num_layers_fr,
.layers = layers_fr
}
};
const char * const sq2lv_layout_names =
"US English" "\n"
"Deutsch" "\n"
"Español" "\n"
"Français";
const char * const sq2lv_layout_short_names =
"us" "\n"
"de" "\n"
"es" "\n"
"fr";

66
sq2lv_layouts.h Normal file
View file

@ -0,0 +1,66 @@
/**
* Auto-generated with squeek2lvgl
**/
#ifndef SQ2LV_LAYOUTS_H
#define SQ2LV_LAYOUTS_H
#include "lvgl/lvgl.h"
#define SQ2LV_SCANCODES_ENABLED 0
/* Key attributes */
#define SQ2LV_CTRL_NON_CHAR (LV_BTNMATRIX_CTRL_CLICK_TRIG | LV_BTNMATRIX_CTRL_CHECKED)
#define SQ2LV_CTRL_MOD_ACTIVE (LV_BTNMATRIX_CTRL_CLICK_TRIG | LV_BTNMATRIX_CTRL_CHECKABLE)
#define SQ2LV_CTRL_MOD_INACTIVE (LV_BTNMATRIX_CTRL_CLICK_TRIG | LV_BTNMATRIX_CTRL_CHECKABLE | LV_BTNMATRIX_CTRL_CHECKED)
/* Layout IDs, values can be used as indexes into the sq2lv_layouts array */
typedef enum {
SQ2LV_LAYOUT_NONE = -1,
SQ2LV_LAYOUT_US = 0,
SQ2LV_LAYOUT_DE = 1,
SQ2LV_LAYOUT_ES = 2,
SQ2LV_LAYOUT_FR = 3
} sq2lv_layout_id_t;
/* Layer type */
typedef struct {
/* Number of keys */
const int num_keys;
/* Key caps */
const char * const * const keycaps;
/* Key attributes */
const lv_btnmatrix_ctrl_t * const attributes;
/* Number of modifier keys */
const int num_modifiers;
/* Button indexes of modifier keys */
const int * const modifier_idxs;
/* Number of buttons that trigger a layer switch */
const int num_switchers;
/* Button indexes that trigger a layer switch */
const int * const switcher_idxs;
/* Indexes of layers to jump to when triggering layer switch buttons */
const int * const switcher_dests;
} sq2lv_layer_t;
/* Layout type */
typedef struct {
/* Layout name */
const char * const name;
/* Layout short name */
const char * const short_name;
/* Total number of layers */
const int num_layers;
/* Layers array */
const sq2lv_layer_t * const layers;
} sq2lv_layout_t;
/* Layouts */
extern const int sq2lv_num_layouts;
extern const sq2lv_layout_t sq2lv_layouts[];
/* Layout names (suitable for use in lv_dropdown_t) */
extern const char * const sq2lv_layout_names;
extern const char * const sq2lv_layout_short_names;
#endif /* SQ2LV_LAYOUTS_H */

1
squeek2lvgl Submodule

@ -0,0 +1 @@
Subproject commit ffe1f5bf18a99756f1c0985e8ccc3d24a1f4a528

146
terminal.c Normal file
View file

@ -0,0 +1,146 @@
/**
* Copyright 2021 Johannes Marbach
*
* This file is part of unl0kr, hereafter referred to as the program.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "terminal.h"
#include "log.h"
#include <fcntl.h>
#include <stdbool.h>
#include <unistd.h>
#include <linux/kd.h>
#include <sys/ioctl.h>
/**
* Static variables
*/
static int current_fd = -1;
static int original_mode = -1;
static int original_kb_mode = -1;
/**
* Static prototypes
*/
/**
* Close the current file descriptor and reopen /dev/tty0.
*
* @return true if opening was successful, false otherwise
*/
static bool reopen_current_terminal(void);
/**
* Close the current file descriptor.
*/
static void close_current_terminal(void);
/**
* Static functions
*/
static bool reopen_current_terminal(void) {
close_current_terminal();
current_fd = open("/dev/tty0", O_RDWR);
if (current_fd < 0) {
ul_log(UL_LOG_LEVEL_WARNING, "Could not open /dev/tty0");
return false;
}
return true;
}
static void close_current_terminal(void) {
if (current_fd < 0) {
return;
}
close(current_fd);
current_fd = -1;
}
/**
* Public functions
*/
void ul_terminal_prepare_current_terminal(bool enable_graphics_mode, bool disable_keyboard_input) {
/* Exit early if there is nothing to do */
if (!enable_graphics_mode && !disable_keyboard_input) {
return;
}
/* Reopen the current terminal */
reopen_current_terminal();
if (current_fd < 0) {
ul_log(UL_LOG_LEVEL_WARNING, "Could not prepare current terminal");
return;
}
/* Disable terminal keyboard input (hides entered text) */
if (disable_keyboard_input) {
if (ioctl(current_fd, KDGKBMODE, &original_kb_mode) != 0) {
ul_log(UL_LOG_LEVEL_WARNING, "Could not get terminal keyboard mode");
}
if (ioctl(current_fd, KDSKBMODE, K_OFF) != 0) {
ul_log(UL_LOG_LEVEL_WARNING, "Could not set terminal keyboard mode to off");
}
}
/* Switch terminal into graphics mode (hides command prompt) */
if (enable_graphics_mode) {
if (ioctl(current_fd, KDGETMODE, &original_mode) != 0) {
ul_log(UL_LOG_LEVEL_WARNING, "Could not get terminal mode");
}
if (ioctl(current_fd, KDSETMODE, KD_GRAPHICS) != 0) {
ul_log(UL_LOG_LEVEL_WARNING, "Could not set terminal mode to graphics");
}
}
}
void ul_terminal_reset_current_terminal(void) {
/* If we haven't previously opened the current terminal, exit */
if (current_fd < 0) {
ul_log(UL_LOG_LEVEL_WARNING, "Could not reset current terminal");
return;
}
/* Reset terminal mode if needed */
if (original_mode >= 0 && ioctl(current_fd, KDSETMODE, original_mode) != 0) {
ul_log(UL_LOG_LEVEL_WARNING, "Could not reset terminal mode");
}
/* Reset terminal keyboard mode if needed */
if (original_kb_mode >= 0 && ioctl(current_fd, KDSKBMODE, original_kb_mode) != 0) {
ul_log(UL_LOG_LEVEL_WARNING, "Could not reset terminal keyboard mode");
}
close_current_terminal();
}

39
terminal.h Normal file
View file

@ -0,0 +1,39 @@
/**
* Copyright 2021 Johannes Marbach
*
* This file is part of unl0kr, hereafter referred to as the program.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef UL_TERMINAL_H
#define UL_TERMINAL_H
#include <stdbool.h>
/**
* Prepare the current TTY for graphics output.
*
* @param enable_graphics_mode if true, switch terminal into graphics mode (hides command prompt)
* @param disable_keyboard_input if true, disable terminal keyboard input (hides entered text)
*/
void ul_terminal_prepare_current_terminal(bool enable_graphics_mode, bool disable_keyboard_input);
/**
* Reset the current TTY to text output.
*/
void ul_terminal_reset_current_terminal(void);
#endif /* UL_TERMINAL_H */

392
theme.c Normal file
View file

@ -0,0 +1,392 @@
/**
* Copyright 2021 Johannes Marbach
*
* This file is part of unl0kr, hereafter referred to as the program.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "theme.h"
#include "log.h"
#include "sq2lv_layouts.h"
#include "unl0kr.h"
#include "lvgl/lvgl.h"
/**
* Static variables
*/
static ul_theme current_theme;
static lv_theme_t lv_theme;
static struct {
lv_style_t widget;
lv_style_t window;
lv_style_t header;
lv_style_t keyboard;
lv_style_t key;
lv_style_t button;
lv_style_t button_pressed;
lv_style_t textarea;
lv_style_t textarea_placeholder;
lv_style_t textarea_cursor;
lv_style_t dropdown;
lv_style_t dropdown_pressed;
lv_style_t dropdown_list;
lv_style_t dropdown_list_selected;
lv_style_t label;
lv_style_t msgbox;
lv_style_t msgbox_label;
lv_style_t msgbox_btnmatrix;
lv_style_t msgbox_background;
lv_style_t bar;
lv_style_t bar_indicator;
} styles;
static bool are_styles_initialised = false;
/**
* Static prototypes
*/
/**
* Set up the static styles for a specific theme.
*
* @param theme theme to derive the styles from
*/
static void init_styles(const ul_theme *theme);
/**
* Initialise or reset a style.
*
* @param style style to reset
*/
static void reset_style(lv_style_t *style);
/**
* Apply a theme to an object.
*
* @param theme theme to apply
* @param obj object to style
*/
static void apply_theme_cb(lv_theme_t *theme, lv_obj_t *obj);
/**
* Handle LV_EVENT_DRAW_PART_BEGIN events from the keyboard widget.
*
* @param event the event object
*/
static void keyboard_draw_part_begin_cb(lv_event_t *event);
/**
* Static functions
*/
static void init_styles(const ul_theme *theme) {
reset_style(&(styles.widget));
lv_style_set_text_font(&(styles.widget), &font_32);
reset_style(&(styles.window));
lv_style_set_bg_opa(&(styles.window), LV_OPA_COVER);
lv_style_set_bg_color(&(styles.window), lv_color_hex(theme->window.bg_color));
reset_style(&(styles.header));
lv_style_set_bg_opa(&(styles.header), LV_OPA_COVER);
lv_style_set_bg_color(&(styles.header), lv_color_hex(theme->header.bg_color));
lv_style_set_border_side(&(styles.header), LV_BORDER_SIDE_BOTTOM);
lv_style_set_border_width(&(styles.header), lv_dpx(theme->header.border_width));
lv_style_set_border_color(&(styles.header), lv_color_hex(theme->header.border_color));
lv_style_set_pad_all(&(styles.header), lv_dpx(theme->header.pad));
lv_style_set_pad_gap(&(styles.header), lv_dpx(theme->header.gap));
reset_style(&(styles.keyboard));
lv_style_set_bg_opa(&(styles.keyboard), LV_OPA_COVER);
lv_style_set_bg_color(&(styles.keyboard), lv_color_hex(theme->keyboard.bg_color));
lv_style_set_border_side(&(styles.keyboard), LV_BORDER_SIDE_TOP);
lv_style_set_border_width(&(styles.keyboard), lv_dpx(theme->keyboard.border_width));
lv_style_set_border_color(&(styles.keyboard), lv_color_hex(theme->keyboard.border_color));
lv_style_set_pad_all(&(styles.keyboard), lv_dpx(theme->keyboard.pad));
lv_style_set_pad_gap(&(styles.keyboard), lv_dpx(theme->keyboard.gap));
reset_style(&(styles.key));
lv_style_set_bg_opa(&(styles.key), LV_OPA_COVER);
lv_style_set_border_side(&(styles.key), LV_BORDER_SIDE_FULL);
lv_style_set_border_width(&(styles.key), lv_dpx(theme->keyboard.keys.border_width));
lv_style_set_radius(&(styles.key), lv_dpx(theme->keyboard.keys.corner_radius));
reset_style(&(styles.button));
lv_style_set_text_color(&(styles.button), lv_color_hex(theme->button.normal.fg_color));
lv_style_set_bg_opa(&(styles.button), LV_OPA_COVER);
lv_style_set_bg_color(&(styles.button), lv_color_hex(theme->button.normal.bg_color));
lv_style_set_border_side(&(styles.button), LV_BORDER_SIDE_FULL);
lv_style_set_border_width(&(styles.button), lv_dpx(theme->button.border_width));
lv_style_set_border_color(&(styles.button), lv_color_hex(theme->button.normal.border_color));
lv_style_set_radius(&(styles.button), lv_dpx(theme->button.corner_radius));
lv_style_set_pad_all(&(styles.button), lv_dpx(theme->button.pad));
reset_style(&(styles.button_pressed));
lv_style_set_text_color(&(styles.button_pressed), lv_color_hex(theme->button.pressed.fg_color));
lv_style_set_bg_color(&(styles.button_pressed), lv_color_hex(theme->button.pressed.bg_color));
lv_style_set_border_color(&(styles.button_pressed), lv_color_hex(theme->button.pressed.border_color));
reset_style(&(styles.textarea));
lv_style_set_text_color(&(styles.textarea), lv_color_hex(theme->textarea.fg_color));
lv_style_set_bg_opa(&(styles.textarea), LV_OPA_COVER);
lv_style_set_bg_color(&(styles.textarea), lv_color_hex(theme->textarea.bg_color));
lv_style_set_border_side(&(styles.textarea), LV_BORDER_SIDE_FULL);
lv_style_set_border_width(&(styles.textarea), lv_dpx(theme->textarea.border_width));
lv_style_set_border_color(&(styles.textarea), lv_color_hex(theme->textarea.border_color));
lv_style_set_radius(&(styles.textarea), lv_dpx(theme->textarea.corner_radius));
lv_style_set_pad_all(&(styles.textarea), lv_dpx(theme->textarea.pad));
reset_style(&(styles.textarea_placeholder));
lv_style_set_text_color(&(styles.textarea_placeholder), lv_color_hex(theme->textarea.placeholder_color));
reset_style(&(styles.textarea_cursor));
lv_style_set_border_side(&(styles.textarea_cursor), LV_BORDER_SIDE_LEFT);
lv_style_set_border_width(&(styles.textarea_cursor), lv_dpx(theme->textarea.cursor.width));
lv_style_set_border_color(&(styles.textarea_cursor), lv_color_hex(theme->textarea.cursor.color));
lv_style_set_anim_time(&(styles.textarea_cursor), theme->textarea.cursor.period);
reset_style(&(styles.dropdown));
lv_style_set_text_color(&(styles.dropdown), lv_color_hex(theme->dropdown.button.normal.fg_color));
lv_style_set_bg_opa(&(styles.dropdown), LV_OPA_COVER);
lv_style_set_bg_color(&(styles.dropdown), lv_color_hex(theme->dropdown.button.normal.bg_color));
lv_style_set_border_side(&(styles.dropdown), LV_BORDER_SIDE_FULL);
lv_style_set_border_width(&(styles.dropdown), lv_dpx(theme->dropdown.button.border_width));
lv_style_set_border_color(&(styles.dropdown), lv_color_hex(theme->dropdown.button.normal.border_color));
lv_style_set_radius(&(styles.dropdown), lv_dpx(theme->dropdown.button.corner_radius));
lv_style_set_pad_all(&(styles.dropdown), lv_dpx(theme->dropdown.button.pad));
reset_style(&(styles.dropdown_pressed));
lv_style_set_text_color(&(styles.dropdown_pressed), lv_color_hex(theme->dropdown.button.pressed.fg_color));
lv_style_set_bg_color(&(styles.dropdown_pressed), lv_color_hex(theme->dropdown.button.pressed.bg_color));
lv_style_set_border_color(&(styles.dropdown_pressed), lv_color_hex(theme->dropdown.button.pressed.border_color));
reset_style(&(styles.dropdown_list));
lv_style_set_text_color(&(styles.dropdown_list), lv_color_hex(theme->dropdown.list.fg_color));
lv_style_set_bg_opa(&(styles.dropdown_list), LV_OPA_COVER);
lv_style_set_bg_color(&(styles.dropdown_list), lv_color_hex(theme->dropdown.list.bg_color));
lv_style_set_border_side(&(styles.dropdown_list), LV_BORDER_SIDE_FULL);
lv_style_set_border_width(&(styles.dropdown_list), lv_dpx(theme->dropdown.list.border_width));
lv_style_set_border_color(&(styles.dropdown_list), lv_color_hex(theme->dropdown.list.border_color));
lv_style_set_radius(&(styles.dropdown_list), lv_dpx(theme->dropdown.list.corner_radius));
lv_style_set_pad_all(&(styles.dropdown_list), lv_dpx(theme->dropdown.list.pad));
reset_style(&(styles.dropdown_list_selected));
lv_style_set_text_color(&(styles.dropdown_list_selected), lv_color_hex(theme->dropdown.list.selection_fg_color));
lv_style_set_bg_opa(&(styles.dropdown_list_selected), LV_OPA_COVER);
lv_style_set_bg_color(&(styles.dropdown_list_selected), lv_color_hex(theme->dropdown.list.selection_bg_color));
reset_style(&(styles.label));
lv_style_set_text_color(&(styles.label), lv_color_hex(theme->label.fg_color));
reset_style(&(styles.msgbox));
lv_style_set_text_color(&(styles.msgbox), lv_color_hex(theme->msgbox.fg_color));
lv_style_set_bg_opa(&(styles.msgbox), LV_OPA_COVER);
lv_style_set_bg_color(&(styles.msgbox), lv_color_hex(theme->msgbox.bg_color));
lv_style_set_border_side(&(styles.msgbox), LV_BORDER_SIDE_FULL);
lv_style_set_border_width(&(styles.msgbox), lv_dpx(theme->msgbox.border_width));
lv_style_set_border_color(&(styles.msgbox), lv_color_hex(theme->msgbox.border_color));
lv_style_set_radius(&(styles.msgbox), lv_dpx(theme->msgbox.corner_radius));
lv_style_set_pad_all(&(styles.msgbox), lv_dpx(theme->msgbox.pad));
reset_style(&(styles.msgbox_label));
lv_style_set_text_align(&(styles.msgbox_label), LV_TEXT_ALIGN_CENTER);
lv_style_set_pad_bottom(&(styles.msgbox_label), lv_dpx(theme->msgbox.gap));
reset_style(&(styles.msgbox_btnmatrix));
lv_style_set_pad_gap(&(styles.msgbox_btnmatrix), lv_dpx(theme->msgbox.buttons.gap));
lv_style_set_min_width(&(styles.msgbox_btnmatrix), LV_PCT(100));
reset_style(&(styles.msgbox_background));
lv_style_set_bg_color(&(styles.msgbox_background), lv_color_hex(theme->msgbox.dimming.color));
lv_style_set_bg_opa(&(styles.msgbox_background), theme->msgbox.dimming.opacity);
reset_style(&(styles.bar));
lv_style_set_border_side(&(styles.bar), LV_BORDER_SIDE_FULL);
lv_style_set_border_width(&(styles.bar), lv_dpx(theme->bar.border_width));
lv_style_set_border_color(&(styles.bar), lv_color_hex(theme->bar.border_color));
lv_style_set_radius(&(styles.bar), lv_dpx(theme->bar.corner_radius));
reset_style(&(styles.bar_indicator));
lv_style_set_bg_opa(&(styles.bar_indicator), LV_OPA_COVER);
lv_style_set_bg_color(&(styles.bar_indicator), lv_color_hex(theme->bar.indicator.bg_color));
are_styles_initialised = true;
}
static void reset_style(lv_style_t *style) {
if (are_styles_initialised) {
lv_style_reset(style);
} else {
lv_style_init(style);
}
}
static void apply_theme_cb(lv_theme_t *theme, lv_obj_t *obj) {
LV_UNUSED(theme);
lv_obj_add_style(obj, &(styles.widget), 0);
if (lv_obj_get_parent(obj) == NULL) {
lv_obj_add_style(obj, &(styles.window), 0);
return;
}
if (lv_obj_has_flag(obj, UL_WIDGET_HEADER)) {
lv_obj_add_style(obj, &(styles.header), 0);
return;
}
if (lv_obj_check_type(obj, &lv_keyboard_class)) {
lv_obj_add_style(obj, &(styles.keyboard), 0);
lv_obj_add_style(obj, &(styles.key), LV_PART_ITEMS);
return;
}
if (lv_obj_check_type(obj, &lv_btn_class)) {
lv_obj_add_style(obj, &(styles.button), 0);
lv_obj_add_style(obj, &(styles.button_pressed), LV_STATE_PRESSED);
return;
}
if (lv_obj_check_type(obj, &lv_label_class) && lv_obj_check_type(lv_obj_get_parent(obj), &lv_btn_class)) {
return; /* Inherit styling from button */
}
if (lv_obj_check_type(obj, &lv_textarea_class)) {
lv_obj_add_style(obj, &(styles.textarea), 0);
lv_obj_add_style(obj, &(styles.textarea_placeholder), LV_PART_TEXTAREA_PLACEHOLDER);
lv_obj_add_style(obj, &(styles.textarea_cursor), LV_PART_CURSOR | LV_STATE_FOCUSED);
return;
}
if (lv_obj_check_type(obj, &lv_label_class) && lv_obj_check_type(lv_obj_get_parent(obj), &lv_textarea_class)) {
return; /* Inherit styling from textarea */
}
if (lv_obj_check_type(obj, &lv_dropdown_class)) {
lv_obj_add_style(obj, &(styles.dropdown), 0);
lv_obj_add_style(obj, &(styles.dropdown_pressed), LV_STATE_PRESSED);
return;
}
if (lv_obj_check_type(obj, &lv_dropdownlist_class)) {
lv_obj_add_style(obj, &(styles.dropdown_list), 0);
lv_obj_add_style(obj, &(styles.dropdown_list_selected), LV_PART_SELECTED | LV_STATE_CHECKED);
lv_obj_add_style(obj, &(styles.dropdown_list_selected), LV_PART_SELECTED | LV_STATE_PRESSED);
return;
}
if (lv_obj_check_type(obj, &lv_label_class) && lv_obj_check_type(lv_obj_get_parent(obj), &lv_dropdownlist_class)) {
return; /* Inherit styling from dropdown list */
}
if (lv_obj_check_type(obj, &lv_msgbox_class)) {
lv_obj_add_style(obj, &(styles.msgbox), 0);
return;
}
if (lv_obj_check_type(obj, &lv_label_class) && (lv_obj_check_type(lv_obj_get_parent(obj), &lv_msgbox_class) || lv_obj_check_type(lv_obj_get_parent(obj), &lv_msgbox_content_class))) {
lv_obj_add_style(obj, &(styles.msgbox_label), 0);
return; /* Inherit styling from message box */
}
if (lv_obj_check_type(obj, &lv_btnmatrix_class) && lv_obj_check_type(lv_obj_get_parent(obj), &lv_msgbox_class)) {
lv_obj_add_style(obj, &(styles.msgbox_btnmatrix), 0);
lv_obj_add_style(obj, &(styles.button), LV_PART_ITEMS);
lv_obj_add_style(obj, &(styles.button_pressed), LV_PART_ITEMS | LV_STATE_PRESSED);
return;
}
if (lv_obj_check_type(obj, &lv_msgbox_backdrop_class)) {
lv_obj_add_style(obj, &(styles.msgbox_background), 0);
return;
}
if (lv_obj_check_type(obj, &lv_label_class) || lv_obj_check_type(obj, &lv_spangroup_class)) {
lv_obj_add_style(obj, &(styles.label), 0);
return;
}
if (lv_obj_check_type(obj, &lv_bar_class)) {
lv_obj_add_style(obj, &(styles.bar), 0);
lv_obj_add_style(obj, &(styles.bar_indicator), LV_PART_INDICATOR);
return;
}
}
static void keyboard_draw_part_begin_cb(lv_event_t *event) {
lv_obj_t *obj = lv_event_get_target(event);
lv_btnmatrix_t *btnm = (lv_btnmatrix_t *)obj;
lv_obj_draw_part_dsc_t *dsc = lv_event_get_param(event);
if (dsc->part != LV_PART_ITEMS) {
return;
}
ul_theme_key *key = NULL;
if ((btnm->ctrl_bits[dsc->id] & SQ2LV_CTRL_MOD_INACTIVE) == SQ2LV_CTRL_MOD_INACTIVE) {
key = &(current_theme.keyboard.keys.key_mod_inact);
} else if ((btnm->ctrl_bits[dsc->id] & SQ2LV_CTRL_MOD_ACTIVE) == SQ2LV_CTRL_MOD_ACTIVE) {
key = &(current_theme.keyboard.keys.key_mod_act);
} else if ((btnm->ctrl_bits[dsc->id] & SQ2LV_CTRL_NON_CHAR) == SQ2LV_CTRL_NON_CHAR) {
key = &(current_theme.keyboard.keys.key_non_char);
} else {
key = &(current_theme.keyboard.keys.key_char);
}
bool pressed = lv_btnmatrix_get_selected_btn(obj) == dsc->id && lv_obj_has_state(obj, LV_STATE_PRESSED);
dsc->label_dsc->color = lv_color_hex((pressed ? key->pressed : key->normal).fg_color);
dsc->rect_dsc->bg_color = lv_color_hex((pressed ? key->pressed : key->normal).bg_color);
dsc->rect_dsc->border_color = lv_color_hex((pressed ? key->pressed : key->normal).border_color);
}
/**
* Public functions
*/
void ul_theme_prepare_keyboard(lv_obj_t *keyboard) {
lv_obj_add_event_cb(keyboard, keyboard_draw_part_begin_cb, LV_EVENT_DRAW_PART_BEGIN, NULL);
}
void ul_theme_apply(const ul_theme *theme) {
if (!theme) {
ul_log(UL_LOG_LEVEL_ERROR, "Could not apply theme from NULL pointer");
return;
}
lv_theme.disp = NULL;
lv_theme.font_small = &font_32;
lv_theme.font_normal = &font_32;
lv_theme.font_large = &font_32;
lv_theme.apply_cb = apply_theme_cb;
current_theme = *theme;
init_styles(theme);
lv_obj_report_style_change(NULL);
lv_disp_set_theme(NULL, &lv_theme);
lv_theme_apply(lv_scr_act());
}

205
theme.h Normal file
View file

@ -0,0 +1,205 @@
/**
* Copyright 2021 Johannes Marbach
*
* This file is part of unl0kr, hereafter referred to as the program.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef UL_THEME_H
#define UL_THEME_H
#include "lvgl/lvgl.h"
#include <stdbool.h>
#include <stdint.h>
#define UL_WIDGET_HEADER LV_OBJ_FLAG_USER_1
/**
* Theming structs
*/
/* Window theme */
typedef struct {
uint32_t bg_color;
} ul_theme_window;
/* Header theme */
typedef struct {
uint32_t bg_color;
lv_coord_t border_width;
uint32_t border_color;
lv_coord_t pad;
lv_coord_t gap;
} ul_theme_header;
/* Key theme for one specific key type and state */
typedef struct {
uint32_t fg_color;
uint32_t bg_color;
uint32_t border_color;
} ul_theme_key_state;
/* Key theme for one specific key type and all states */
typedef struct {
ul_theme_key_state normal;
ul_theme_key_state pressed;
} ul_theme_key;
/* Key theme */
typedef struct {
lv_coord_t border_width;
lv_coord_t corner_radius;
ul_theme_key key_char;
ul_theme_key key_non_char;
ul_theme_key key_mod_act;
ul_theme_key key_mod_inact;
} ul_theme_keys;
/* Keyboard theme */
typedef struct {
uint32_t bg_color;
lv_coord_t border_width;
uint32_t border_color;
lv_coord_t pad;
lv_coord_t gap;
ul_theme_keys keys;
} ul_theme_keyboard;
/* Button theme for one specific button state */
typedef struct {
uint32_t fg_color;
uint32_t bg_color;
uint32_t border_color;
} ul_theme_button_state;
/* Button theme */
typedef struct {
lv_coord_t border_width;
lv_coord_t corner_radius;
lv_coord_t pad;
ul_theme_button_state normal;
ul_theme_button_state pressed;
} ul_theme_button;
/* Text area cursor theme */
typedef struct {
lv_coord_t width;
uint32_t color;
int period;
} ul_theme_textarea_cursor;
/* Text area theme */
typedef struct {
uint32_t fg_color;
uint32_t bg_color;
lv_coord_t border_width;
uint32_t border_color;
lv_coord_t corner_radius;
lv_coord_t pad;
uint32_t placeholder_color;
ul_theme_textarea_cursor cursor;
} ul_theme_textarea;
/* Dropdown list theme */
typedef struct {
uint32_t fg_color;
uint32_t bg_color;
uint32_t selection_fg_color;
uint32_t selection_bg_color;
lv_coord_t border_width;
uint32_t border_color;
lv_coord_t corner_radius;
lv_coord_t pad;
} ul_theme_dropdown_list;
/* Dropdown theme */
typedef struct {
ul_theme_button button;
ul_theme_dropdown_list list;
} ul_theme_dropdown;
/* Label */
typedef struct {
uint32_t fg_color;
} ul_theme_label;
/* Message box buttons theme */
typedef struct {
lv_coord_t gap;
} ul_theme_msgbox_buttons;
/* Message box dimming theme */
typedef struct {
uint32_t color;
short opacity;
} ul_theme_msgbox_dimming;
/* Message box theme */
typedef struct {
uint32_t fg_color;
uint32_t bg_color;
lv_coord_t border_width;
uint32_t border_color;
lv_coord_t corner_radius;
lv_coord_t pad;
lv_coord_t gap;
ul_theme_msgbox_buttons buttons;
ul_theme_msgbox_dimming dimming;
} ul_theme_msgbox;
/* Progress bar indicator theme */
typedef struct {
uint32_t bg_color;
} ul_theme_bar_indicator;
/* Progress bar theme */
typedef struct {
lv_coord_t border_width;
uint32_t border_color;
lv_coord_t corner_radius;
ul_theme_bar_indicator indicator;
} ul_theme_bar;
/* Full theme */
typedef struct {
char *name;
ul_theme_window window;
ul_theme_header header;
ul_theme_keyboard keyboard;
ul_theme_button button;
ul_theme_textarea textarea;
ul_theme_dropdown dropdown;
ul_theme_label label;
ul_theme_msgbox msgbox;
ul_theme_bar bar;
} ul_theme;
/**
* Prepare a keyboard widget to be themed with a theme.
*
* @param keyboard keyboard widget
*/
void ul_theme_prepare_keyboard(lv_obj_t *keyboard);
/**
* Apply a UI theme.
*
* @param theme the theme to apply
*/
void ul_theme_apply(const ul_theme *theme);
#endif /* UL_THEME_H */

678
themes.c Normal file
View file

@ -0,0 +1,678 @@
/**
* Copyright 2021 Johannes Marbach
*
* This file is part of unl0kr, hereafter referred to as the program.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "themes.h"
/**
* Static variables
*/
/* Breezy light (based on KDE Breeze color palette, see https://develop.kde.org/hig/style/color/default/) */
static const ul_theme ul_themes_breezy_light = {
.name = "breezy-light",
.window = {
.bg_color = 0xeff0f1
},
.header = {
.bg_color = 0xfcfcfc,
.border_width = 1,
.border_color = 0xbdc3c7,
.pad = 10,
.gap = 10
},
.keyboard = {
.bg_color = 0xfcfcfc,
.border_width = 1,
.border_color = 0xbdc3c7,
.pad = 10,
.gap = 10,
.keys = {
.border_width = 1,
.corner_radius = 5,
.key_char = {
.normal = {
.fg_color = 0x232629,
.bg_color = 0xeff0f1,
.border_color = 0xbdc3c7
},
.pressed = {
.fg_color = 0x232629,
.bg_color = 0x3daee9,
.border_color = 0x2980b9
}
},
.key_non_char = {
.normal = {
.fg_color = 0x232629,
.bg_color = 0xbdc3c7,
.border_color = 0x7f8c8d
},
.pressed = {
.fg_color = 0x232629,
.bg_color = 0x3daee9,
.border_color = 0x2980b9
}
},
.key_mod_act = {
.normal = {
.fg_color = 0x232629,
.bg_color = 0x3daee9,
.border_color = 0x2980b9
},
.pressed = {
.fg_color = 0x232629,
.bg_color = 0x3daee9,
.border_color = 0x2980b9
}
},
.key_mod_inact = {
.normal = {
.fg_color = 0x232629,
.bg_color = 0xbdc3c7,
.border_color = 0x7f8c8d
},
.pressed = {
.fg_color = 0x232629,
.bg_color = 0x3daee9,
.border_color = 0x2980b9
}
}
}
},
.button = {
.border_width = 1,
.corner_radius = 5,
.pad = 5,
.normal = {
.fg_color = 0x232629,
.bg_color = 0xeff0f1,
.border_color = 0xbdc3c7
},
.pressed = {
.fg_color = 0x232629,
.bg_color = 0x3daee9,
.border_color = 0x2980b9
}
},
.textarea = {
.fg_color = 0x232629,
.bg_color = 0xfcfcfc,
.border_width = 1,
.border_color = 0xbdc3c7,
.corner_radius = 5,
.pad = 5,
.placeholder_color = 0x7f8c8d,
.cursor = {
.width = 1,
.color = 0x232629,
.period = 700
}
},
.dropdown = {
.button = {
.border_width = 1,
.corner_radius = 5,
.pad = 5,
.normal = {
.fg_color = 0x232629,
.bg_color = 0xeff0f1,
.border_color = 0xbdc3c7
},
.pressed = {
.fg_color = 0x232629,
.bg_color = 0x3daee9,
.border_color = 0x2980b9
}
},
.list = {
.fg_color = 0x232629,
.bg_color = 0xfcfcfc,
.selection_fg_color = 0x232629,
.selection_bg_color = 0x3daee9,
.border_width = 1,
.border_color = 0xbdc3c7,
.corner_radius = 0,
.pad = 0
}
},
.label = {
.fg_color = 0x232629
},
.msgbox = {
.fg_color = 0x232629,
.bg_color = 0xeff0f1,
.border_width = 1,
.border_color = 0xbdc3c7,
.corner_radius = 0,
.pad = 20,
.gap = 20,
.buttons = {
.gap = 5
},
.dimming = {
.color = 0x232629,
.opacity = 178
}
},
.bar = {
.border_width = 1,
.border_color = 0x3daee9,
.corner_radius = 5,
.indicator = {
.bg_color = 0x3daee9
}
}
};
/* Breezy dark (based on KDE Breeze Dark color palette, see https://develop.kde.org/hig/style/color/dark/) */
static const ul_theme ul_themes_breezy_dark = {
.name = "breezy-dark",
.window = {
.bg_color = 0x31363b
},
.header = {
.bg_color = 0x232629,
.border_width = 1,
.border_color = 0x7f8c8d,
.pad = 10,
.gap = 10
},
.keyboard = {
.bg_color = 0x232629,
.border_width = 1,
.border_color = 0x7f8c8d,
.pad = 10,
.gap = 10,
.keys = {
.border_width = 1,
.corner_radius = 5,
.key_char = {
.normal = {
.fg_color = 0xeff0f1,
.bg_color = 0x31363b,
.border_color = 0xbdc3c7
},
.pressed = {
.fg_color = 0xeff0f1,
.bg_color = 0x3daee9,
.border_color = 0x2980b9
}
},
.key_non_char = {
.normal = {
.fg_color = 0xeff0f1,
.bg_color = 0x232629,
.border_color = 0x7f8c8d
},
.pressed = {
.fg_color = 0xeff0f1,
.bg_color = 0x3daee9,
.border_color = 0x2980b9
}
},
.key_mod_act = {
.normal = {
.fg_color = 0xeff0f1,
.bg_color = 0x3daee9,
.border_color = 0x2980b9
},
.pressed = {
.fg_color = 0xeff0f1,
.bg_color = 0x3daee9,
.border_color = 0x2980b9
}
},
.key_mod_inact = {
.normal = {
.fg_color = 0xeff0f1,
.bg_color = 0x232629,
.border_color = 0x7f8c8d
},
.pressed = {
.fg_color = 0xeff0f1,
.bg_color = 0x3daee9,
.border_color = 0x2980b9
}
}
}
},
.button = {
.border_width = 1,
.corner_radius = 5,
.pad = 5,
.normal = {
.fg_color = 0xeff0f1,
.bg_color = 0x31363b,
.border_color = 0xbdc3c7
},
.pressed = {
.fg_color = 0xeff0f1,
.bg_color = 0x3daee9,
.border_color = 0x2980b9
}
},
.textarea = {
.fg_color = 0xeff0f1,
.bg_color = 0x232629,
.border_width = 1,
.border_color = 0x7f8c8d,
.corner_radius = 5,
.pad = 5,
.placeholder_color = 0x7f8c8d,
.cursor = {
.width = 1,
.color = 0xeff0f1,
.period = 700
}
},
.dropdown = {
.button = {
.border_width = 1,
.corner_radius = 5,
.pad = 5,
.normal = {
.fg_color = 0xeff0f1,
.bg_color = 0x31363b,
.border_color = 0xbdc3c7
},
.pressed = {
.fg_color = 0xeff0f1,
.bg_color = 0x3daee9,
.border_color = 0x2980b9
}
},
.list = {
.fg_color = 0xeff0f1,
.bg_color = 0x232629,
.selection_fg_color = 0x232629,
.selection_bg_color = 0x3daee9,
.border_width = 1,
.border_color = 0x7f8c8d,
.corner_radius = 0,
.pad = 0
}
},
.label = {
.fg_color = 0xeff0f1
},
.msgbox = {
.fg_color = 0xeff0f1,
.bg_color = 0x31363b,
.border_width = 1,
.border_color = 0x3b4045,
.corner_radius = 0,
.pad = 20,
.gap = 20,
.buttons = {
.gap = 5
},
.dimming = {
.color = 0x232629,
.opacity = 178
}
},
.bar = {
.border_width = 1,
.border_color = 0x3daee9,
.corner_radius = 5,
.indicator = {
.bg_color = 0x3daee9
}
}
};
/* pmOS light (based on palette https://coolors.co/009900-395e66-db504a-e3b505-ebf5ee) */
static const ul_theme ul_themes_pmos_light = {
.name = "pmos-light",
.window = {
.bg_color = 0xf2f7f8,
},
.header = {
.bg_color = 0xf2f7f8,
.border_width = 0,
.border_color = 0xf2f7f8,
.pad = 20,
.gap = 10
},
.keyboard = {
.bg_color = 0xd8e6e9,
.border_width = 2,
.border_color = 0x97bcc4,
.pad = 20,
.gap = 10,
.keys = {
.border_width = 1,
.corner_radius = 3,
.key_char = {
.normal = {
.fg_color = 0x070c0d,
.bg_color = 0xd8e6e9,
.border_color = 0x97bcc4
},
.pressed = {
.fg_color = 0xf2f7f8,
.bg_color = 0x009900,
.border_color = 0x009900
}
},
.key_non_char = {
.normal = {
.fg_color = 0x070c0d,
.bg_color = 0xbed5da,
.border_color = 0xb1cdd3
},
.pressed = {
.fg_color = 0xf2f7f8,
.bg_color = 0x009900,
.border_color = 0x009900
}
},
.key_mod_act = {
.normal = {
.fg_color = 0x009900,
.bg_color = 0xbed5da,
.border_color = 0x009900
},
.pressed = {
.fg_color = 0xf2f7f8,
.bg_color = 0x009900,
.border_color = 0x009900
}
},
.key_mod_inact = {
.normal = {
.fg_color = 0x070c0d,
.bg_color = 0xbed5da,
.border_color = 0xb1cdd3
},
.pressed = {
.fg_color = 0xf2f7f8,
.bg_color = 0x009900,
.border_color = 0x009900
}
}
}
},
.button = {
.border_width = 1,
.corner_radius = 3,
.pad = 8,
.normal = {
.fg_color = 0x070c0d,
.bg_color = 0xbed5da,
.border_color = 0xb1cdd3
},
.pressed = {
.fg_color = 0xf2f7f8,
.bg_color = 0x009900,
.border_color = 0x009900
}
},
.textarea = {
.fg_color = 0x070c0d,
.bg_color = 0xebffeb,
.border_width = 1,
.border_color = 0x009900,
.corner_radius = 3,
.pad = 8,
.placeholder_color = 0x009900,
.cursor = {
.width = 2,
.color = 0x009900,
.period = 700
}
},
.dropdown = {
.button = {
.border_width = 1,
.corner_radius = 3,
.pad = 8,
.normal = {
.fg_color = 0x070c0d,
.bg_color = 0xbed5da,
.border_color = 0xb1cdd3
},
.pressed = {
.fg_color = 0xf2f7f8,
.bg_color = 0x009900,
.border_color = 0x009900
}
},
.list = {
.fg_color = 0x070c0d,
.bg_color = 0xd8e6e9,
.selection_fg_color = 0xf2f7f8,
.selection_bg_color = 0x009900,
.border_width = 1,
.border_color = 0x97bcc4,
.corner_radius = 0,
.pad = 8
}
},
.label = {
.fg_color = 0x070c0d
},
.msgbox = {
.fg_color = 0x070c0d,
.bg_color = 0xd8e6e9,
.border_width = 1,
.border_color = 0x97bcc4,
.corner_radius = 3,
.pad = 20,
.gap = 20,
.buttons = {
.gap = 10
},
.dimming = {
.color = 0x070c0d,
.opacity = 225
}
},
.bar = {
.border_width = 1,
.border_color = 0x009900,
.corner_radius = 3,
.indicator = {
.bg_color = 0x009900
}
}
};
/* pmOS dark (based on palette https://coolors.co/009900-395e66-db504a-e3b505-ebf5ee) */
static const ul_theme ul_themes_pmos_dark = {
.name = "pmos-dark",
.window = {
.bg_color = 0x070c0d
},
.header = {
.bg_color = 0x070c0d,
.border_width = 0,
.border_color = 0x070c0d,
.pad = 20,
.gap = 10
},
.keyboard = {
.bg_color = 0x162427,
.border_width = 2,
.border_color = 0x395e66,
.pad = 20,
.gap = 10,
.keys = {
.border_width = 1,
.corner_radius = 3,
.key_char = {
.normal = {
.fg_color = 0xf2f7f8,
.bg_color = 0x162427,
.border_color = 0x395e66
},
.pressed = {
.fg_color = 0xf2f7f8,
.bg_color = 0x009900,
.border_color = 0x009900
}
},
.key_non_char = {
.normal = {
.fg_color = 0xf2f7f8,
.bg_color = 0x253c41,
.border_color = 0x2c484e
},
.pressed = {
.fg_color = 0xf2f7f8,
.bg_color = 0x009900,
.border_color = 0x009900
}
},
.key_mod_act = {
.normal = {
.fg_color = 0x009900,
.bg_color = 0x253c41,
.border_color = 0x009900
},
.pressed = {
.fg_color = 0xf2f7f8,
.bg_color = 0x009900,
.border_color = 0x009900
}
},
.key_mod_inact = {
.normal = {
.fg_color = 0xf2f7f8,
.bg_color = 0x253c41,
.border_color = 0x2c484e
},
.pressed = {
.fg_color = 0xf2f7f8,
.bg_color = 0x009900,
.border_color = 0x009900
}
}
}
},
.button = {
.border_width = 1,
.corner_radius = 3,
.pad = 8,
.normal = {
.fg_color = 0xf2f7f8,
.bg_color = 0x253c41,
.border_color = 0x2c484e
},
.pressed = {
.fg_color = 0xf2f7f8,
.bg_color = 0x009900,
.border_color = 0x009900
}
},
.textarea = {
.fg_color = 0xf2f7f8,
.bg_color = 0x002900,
.border_width = 1,
.border_color = 0x009900,
.corner_radius = 3,
.pad = 8,
.placeholder_color = 0x009900,
.cursor = {
.width = 2,
.color = 0x009900,
.period = 700
}
},
.dropdown = {
.button = {
.border_width = 1,
.corner_radius = 3,
.pad = 8,
.normal = {
.fg_color = 0xf2f7f8,
.bg_color = 0x253c41,
.border_color = 0x2c484e
},
.pressed = {
.fg_color = 0xf2f7f8,
.bg_color = 0x009900,
.border_color = 0x009900
}
},
.list = {
.fg_color = 0xf2f7f8,
.bg_color = 0x162427,
.selection_fg_color = 0xf2f7f8,
.selection_bg_color = 0x009900,
.border_width = 1,
.border_color = 0x395e66,
.corner_radius = 0,
.pad = 8
}
},
.label = {
.fg_color = 0xf2f7f8,
},
.msgbox = {
.fg_color = 0xf2f7f8,
.bg_color = 0x162427,
.border_width = 1,
.border_color = 0x395e66,
.corner_radius = 3,
.pad = 20,
.gap = 20,
.buttons = {
.gap = 10
},
.dimming = {
.color = 0x070c0d,
.opacity = 225
}
},
.bar = {
.border_width = 1,
.border_color = 0x009900,
.corner_radius = 3,
.indicator = {
.bg_color = 0x009900
}
}
};
/**
* Public interface
*/
const int ul_themes_num_themes = 4;
const ul_theme *ul_themes_themes[] = {
&ul_themes_breezy_light,
&ul_themes_breezy_dark,
&ul_themes_pmos_light,
&ul_themes_pmos_dark
};
ul_themes_theme_id_t ul_themes_find_theme_with_name(const char *name) {
for (int i = 0; i < ul_themes_num_themes; ++i) {
if (strcmp(ul_themes_themes[i]->name, name) == 0) {
ul_log(UL_LOG_LEVEL_VERBOSE, "Found theme: %s\n", name);
return i;
}
}
ul_log(UL_LOG_LEVEL_WARNING, "Theme %s not found\n", name);
return UL_THEMES_THEME_NONE;
}

48
themes.h Normal file
View file

@ -0,0 +1,48 @@
/**
* Copyright 2021 Johannes Marbach
*
* This file is part of unl0kr, hereafter referred to as the program.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef UL_THEMES_H
#define UL_THEMES_H
#include "theme.h"
#include "log.h"
/* Theme IDs, values can be used as indexes into the ul_themes_themes array */
typedef enum {
UL_THEMES_THEME_NONE = -1,
UL_THEMES_THEME_BREEZY_LIGHT = 0,
UL_THEMES_THEME_BREEZY_DARK = 1,
UL_THEMES_THEME_PMOS_LIGHT = 2,
UL_THEMES_THEME_PMOS_DARK = 3
} ul_themes_theme_id_t;
/* Themes */
extern const int ul_themes_num_themes;
extern const ul_theme *ul_themes_themes[];
/**
* Find the first theme with a given name.
*
* @param name theme name
* @return ID of the first matching theme or UL_THEMES_THEME_NONE if no theme matched
*/
ul_themes_theme_id_t ul_themes_find_theme_with_name(const char *name);
#endif /* UL_THEMES_H */

27
unl0kr.conf Normal file
View file

@ -0,0 +1,27 @@
[general]
animations=true
#backend=fbdev|drm
#timeout=300
[keyboard]
autohide=false
layout=us
popovers=true
[textarea]
obscured=true
#bullet=
[theme]
default=breezy-light
alternate=breezy-dark
#[input]
#keyboard=false
#pointer=false
#touchscreen=false
#[quirks]
#fbdev_force_refresh=true
#terminal_prevent_graphics_mode=true
#terminal_allow_keyboard_input=true

37
unl0kr.h Normal file
View file

@ -0,0 +1,37 @@
/**
* Copyright 2021 Johannes Marbach
*
* This file is part of unl0kr, hereafter referred to as the program.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef UL_UNL0KR_H
#define UL_UNL0KR_H
#include "lvgl/lvgl.h"
#ifndef UL_VERSION
#define UL_VERSION "?" /* Just to silence IDE warning. Real version injected by meson during build. */
#endif
/**
* Fonts
*/
#define UL_SYMBOL_ADJUST "\xef\x81\x82" // 0xF042 (https://fontawesome.com/v5.15/icons/adjust?style=solid)
#define UL_SYMBOL_CHEVRON_LEFT "\xef\x81\x93" // 0xF053 (https://fontawesome.com/v5/icons/chevron-left?style=solid&s=solid)
#endif /* UL_UNL0KR_H */