KUAL What's New

From MobileRead
Jump to: navigation, search

This document refers to the new version of the Kindle Unified Application Launcher (KUAL) as KUAL2 for Kindle 2/DX/DXg, Kindle 3, Kindle 4, and Kindle 5 (Touch/PW/PW2) devices. The version number of the current public release is 2.4.

In this document the word "page" refers to the Kindle display.

Contents

[edit] What's New

[edit] New Features For End Users

  • Improved buttons on K2/K3/K4 devices. No more rounded buttons. Now buttons are rectangular and users can configure KUAL2 to display more than 5 buttons per page. The navigation arrows now draw properly on FW 2.x.
  • Sub-menus. The KUAL2 menu can include folded sub-menus. When you press a sub-menu button KUAL2 "dives" into it and displays its contents, which can include regular items as well as other sub-menus.
  • Breadcrumbs. Located at the top of the screen, the breadcrumb line orderly displays the names of the sub-menus that lead to the current page.
  • Upward menu navigation. To return from a sub-menu to its parent menu you can press the "Up" button on the left side of the screen. Pressing the "/" button, which appears at the end of a sub-menu, jumps directly to the top menu.
  • KUAL menu. The first sub-menu of the top menu is named "KUAL" and it groups together special functions as well as error messages. Users can configure KUAL2 to hide some of the special function buttons.
  • Improved error detection and logging. KUAL2 can detect many common error conditions arising from invalid menu syntax to extension errors. No longer can a single invalid extension menu keep all other extensions from loading. KUAL2 gracefully recovers from most errors and keeps a log file. Users can save the KUAL2 log file as a text document.
  • Configuration file. Users can customize several aspects of KUAL2 including sort order, number of buttons per page, and more.
  • Speed. KUAL2 loads faster than any previous version. Users can configure KUAL2 to skip loading specific extension folders.
  • Improved navigation on devices without a touchscreen via a set a keyboard shortcuts: next/prev page do the obvious, the top row of keys (1...0 and Q...P) select the corresponding button, enter & space click the current focus, the [Aa] & [Keyboard] keys focus the top button while the [MENU] key focuses the last button (this is tailored for the K4 layout, where those buttons bracket the five-way controller).
  • User-configurable font

[edit] New Features For Menu Developers

  • Valid JSON syntax. Unlike previous versions, KUAL2 (rev 2.0 and above) insists on rejecting invalid JSON syntax.
  • Nested menus. Sub-menus are expressed as nested JSON values with a maximum nesting limit and a maximum number of items per sub-menu.
  • Menu cache. KUAL2 loads faster because it cashes preformatted menu data and loads from the cache when possible. KUAL2 detects new menu data and automatically refreshes the cache.
  • Priority items. The JSON "priority":value pair is now fully implemented for nested sub-menus and menu items.
  • "No-exit" option. Extensions can tell KUAL2 to keep running after a user presses an extension button.
  • "Refresh menu" option. Extensions can make KUAL2 re-read menu data and refresh the entire menu. Effectively this mechanism enables extensions to build dynamically loaded menus.
  • Checked button option. Developers can request KUAL2 to add a checkmark to the name of a button when the user presses that button.
  • "No status" option. Developers can stop KUAL2 from displaying the detailed action of an extension in the status line.
  • Date option. An extension can make KUAL2 display the date and time in the status line.

[edit] Configuration File

# Sample KUAL.cfg - place this file in your extensions folder
# Each block below ends with the (commented-out) default value.
# Uncomment and change as needed

# Collate menus by recursively merging together same-name sub-menus.
# Collation does not change same-name plain items, just sub-menus.
# Regular sorting rules apply when collation is enabled. In particular,
# author's order of merged sub-menus means that any two sub-menu entry
# sets do not mix with each other.
#KUAL_collate="true"

# Stop following links when looking for json files
#KUAL_nofollow="true"

# Hide the status line and re-route status messages to the breadcrumb line
#KUAL_no_show_status="true"

# Entries per page - default 10 (KT/PW), 5 (other kindles)
#KUAL_page_size="14"

# Change sorting options.
# "ABC" (default) lexicographically sorts top-level menu only and keeps
# sub-menu entries ordered as the menu author defined (author's order).
# "ABC!" (bang) sorts ALL sub-menus lexicographically.
# "123" sorts EACH sub-menu by json key "priority" (=0 when unspecified)
#KUAL_sort_mode="ABC"

# How deep to search for json files under /mnt/us/extensions/
# 1 => search inside folder /mnt/us/extensions only
# 2 => search inside folders /mnt/us/extensions/*
# etc.
#KUAL_search_depth=2

# What paths to exclude when searching for json files under /mnt/us/extensions,
# even if they are within search depth limits;
# semicolon-separated list of relative paths.
# Recommended always excluding 'system', i.e., "mydir;system"
#KUAL_search_exclude_paths="system"

# KUAL menu buttons.  Set:
#   KUAL_show_KUAL_buttons="0" to hide all menu buttons
#   KUAL_show_KUAL_buttons="" (or don't set at all) to show all buttons
#   KUAL_show_KUAL_buttons="2 3" to show buttons 1 and 2
#   Button numbers:
#     1: (not used)
#     2: Change KUAL sort order 123/ABC
#     3: Save (to documents) and reset the log file
#    99: Quit KUAL
# . When ABC (not ABC!) sorting is in effect, you can rearrange the order of
#   "KUAL" sub-menu entries by listing them in a specific order here, i.e.,
#      KUAL_show_KUAL_buttons="99 2 3"
#   shows the Quit button on top. This tweak has no effect when 123 or ABC!
#   sorting are in effect.
#KUAL_show_KUAL_buttons="2 3 99"

# KUAL font.
# Controls the font used in KUAL
# On KDK-2, the family can be the proper family name of anything in the
#   fontconfig cache, even a custom one.
# On KDK-1, you're limited to the default Java aliases:
#   serif, sansserif, monospaced, dialog, symbol, monospacedsymbol, code2000, alt, condensed
#
# On KDK-2, you'll probably need to trigger a menu refresh for the changes to take effect...
# On KDK-1, you'll also need to restart KUAL after a menu refresh...
#KUAL_font_family="Futura"
# The style must be one of Regular, Bold, Italic, or BoldItalic
#KUAL_font_style="Regular"

[edit] Extension Files

A pair of files, config.xml and menu.json, fully define an extension. KUAL scans /mnt/us/extensions and its sub-folders looking for one or more config.xml files. When it finds one it reads the value of tag <menu> to determine where to find menu.json. While config.xml is a fixed name, menu.json can be changed by specifying a different value in the <menu> tag. The tag value consists of an absolute or relative (to the location of config.xml) file path. If menu.json exists then KUAL loads its corresponding extension.

[edit] Sample config.xml

Example of config.xml file. KUAL2 only considers the value of tag <menu> when type="json".

<?xml version="1.0" encoding="UTF-8"?>
<extension>
    <information>
        <name>KUAL</name>
        <version>1.0</version>
        <author>stepk</author>
        <id>KAUL-SELF-MENU-ADD-ONS</id>
    </information>
    <menus>
        <menu type="json" dynamic="true">menu.json</menu>
    </menus>
</extension>

[edit] Sample menu.json And Template Migration

The bottom-line: Menu developers should use Template 1 and migrate to it all existing menus that are based on Template 2.

KUAL2 implements the JSON syntax diagram, including character escape sequences (but excluding the Unicode escape \uNNNN). Please note that JSON syntax does not allow control characters inside strings. In particular, a tab character (ctrl+I) is invalid and returns a parsing error; use \t instead.

Inline or block comments are not supported.

The rest of this section explains Templates 1 and 2 in some detail.

Going from KUAL1 (flat menu) to KUAL2 (nested menu) we face an issue concerning how to properly describe a menu object with JSON. Two slightly different menu templates are in common use.
Template 1 fully conforms to Yifan Lu's definition, Yifan Lu's original graphical menu for the Kindle, e.g.,
{
  "items": [
     {"name": "Main menu, Item 1", "action": "act1.sh"},
     {
       "name": "Main menu, Submenu 1",
       "items": [
         {"name": "Submenu 1, Item 1", "action": "act11.sh"},
         {"name": "Submenu 1, Item 2", "action": "act12.sh"}
       ]
     }
  ]
}

Template 1 provides no explicit way of specifying a main menu label, which suggests that the Kindle system menu button is the main menu, where Yifan Lu's launcher embeds "Main menu, Item 1" as a top level item.

On the other hand KUAL is disjoint from the system menu so we need to clarify how to properly embed a sub-menu in the top menu. Template 1 can be used for that, and so could Template 2 below. But KUAL2 deprecated template 2.

We could consider template 2 (deprecated) as a sort of application package menu:

{
  "name": "Application 1 menu"
  "items": [
     {"name": "Application 1 menu, Item 1", "action": "act1.sh"},
     {
       "name": "Application 1 menu, Submenu 1",
       "items": [
         {"name": "Application 1 menu, Submenu 1, Item 1", "action": "act11.sh"},
         {"name": "Application 1 menu, Submenu 1, Item 2", "action": "act12.sh"}
       ]
     }
  ]
}

While the two templates look almost the same, a small difference is of great import. Template 2 (mis)uses the first "name" as a structural element to insert a sub-menu - the Application menu - into the main menu. But notice that with template 2 there is no syntactically valid way to add a single item at the top level.

KUAL 1 (flat menu series) treats both templates indistinctly, because all menu items are inserted at the top menu level anyway.

KUAL2 ignores all top-level keys but "items". So it effectively interprets the second template as it interprets the first one. In KUAL2 "Application 1 menu, Item 1" displays as a single, top-level menu entry, just like "Main menu, Item 1".

[edit] Action Items

A menu action item is expressed as a list of JSON key/value pairs as follows.

"name": "The name of an item or sub-menu"

KUAL2 displays this value as the label of a button. It is not necessary for all buttons to have unique labels.

"action": "a valid /bin/ash command"

This key is mandatory for menu items. Specifying a null string value is not enough. If you need a do-nothing ash action placeholder use "action":":". /bin/ash is the default linux shell on all Kindle models.

Actions run as background processes in the working directory where file menu.json is located. So, for instance,

The KUAL2 log file /mnt/us/extensions/KUAL.log captures unredirected error output (stderr). Well-designed extensions should take their own measures to redirect error output, which typically is an indication of bugs or design issues. KUAL2 does not capture standard output (stdout).

"params": "parameters of an action"

Parameters are optional. They are appended to the "action" value to build an executable action.

"internal": "an internal KUAL command with optional arguments"

You can add an internal KUAL command to an action. The internal command augments the action without replacing it. The following internal commands are available:

"internal": "breadcrumb [text]" Display text in the breadcrumb line (screen top) then perform action.
"internal": "status [text]" Display text in the status line (screen bottom) then perform action.
"priority":number

This numeric value defines the relative order of items in a given sub-menu when sort by priority is enabled (see Configuration File). When "priority" is omitted, an item has priority 0 (zero). A negative priority, such as -2, is legal.

"if":"RPN conditional expression"

KUAL evaluates "RPN conditional expression" and discards the current menu item when the result is false. Evaluation only takes place upon loading or refreshing the menu. An invalid expression is true; KUAL2 logs an error message but no visibile indication of the error. "RPN conditional expression" is a postfix (Reverse Polish Notation) expression involving operands and operators.

Unless otherwise noted you always need to quote each operand with \\". A double backslash is necessary because operands appear inside a JSON string.

Operands

Full paths, i.e.,
"/mnt/us"
Paths refer to file system objects, like files, directories, special files, etc. Relative paths are not supported.
Patterns, i.e.,
"a.$"/
A pattern is a POSIX regular expression. If you need to include a literal double quote in pattern use [\\x22]. Notice the character class; in some cases you might get away without a character class, i.e., just \\x22, but it іsn't recommended and it could fail on certain platforms. Stick to the character class if you can.
Option names, i.e.,
"page_size"
The name of an option in file KUAL.cfg. Omit prefix KUAL_.
Option values, i.e.,
"ABC" or 14.
The value of an option in file KUAL.cfg. You do not need to, but may, quote numbers.
Extensions names, i.e.,
"explorer"
The name of the folder that actually contains the menu.json file of a given extension.
Kindle model, i.e.,
KindleTouch
The name of the Kindle model.

Operators

&& Boolean AND.
|| Boolean OR.
! Boolean NOT.
-e True if path exists, false otherwise. Preferably use -f for regular files since it is faster.
"if": "\"/mnt/us/my_extension\" -e"
-ext True if extension name is installed, false otherwise.
"if": "\"explorer\" -ext"
-f True if file path is a regular file, false otherwise.
"if": "\"/mnt/us/my_extension/run.sh\" -f" - Notice JSON escaped double quote \".
-g True if pattern matches a line in file. Logs an error if file does not exist.
"if": "\"/etc/version.txt\" \"some text\" -g" - Pattern is "some text" (without quotes).
"if": "\"/etc/version.txt\" \"\\<word\\>\" -g" - \< \> matcheѕ on a word boundary. Notice JSON escaped backslash \\.
-g! True if pattern does not match any line in file. Logs an error if file does not exist.
-gg Like -g but when file does not exist -gg evaluates to false without logging an error.
-gg! Like -g! but when file does not exist -gg! evaluates to false without logging an error.
-m True if the Kindle model is model.
"if": "\"KindlePaperWhite\" -m"
Models: KindlePaperWhite2 KindlePaperWhite KindleTouch Kindle4 Kindle3 KindleDXG KindleDX Kindle2 Unknown.
-o True if the value of KUAL.cfg option name is value.
"if": "\"page_size\" 14 -o"
"if": "\"sort_mode\" \"ABC\" -o !" - If sort mode isn't "ABC".
"exitmenu":false

Use this to keep KUAL2 from exiting after the user presses an extension button. It may makes sense to couple "exitmenu":false with "status":false and/or "date":true.

"checked":true

Use this to make KUAL2 display a checkmark after the user has pressed an extension button. It makes sense to couple "checked":true with "exitmenu":false.

"refresh":true

When KUAL finds this value it starts the action, sleeps for 1.5 seconds, then fully reloads the menu. This makes possible for an extension to write a new JSON file in /mnt/us/extensions and have KUAL2 load that file dynamically. It makes sense to couple "refresh":true with "exitmenu":false. See this example of an extension that dynamically displays a new submenu.

"status":false

Before starting an extension, by default KUAL2 displays the action value in the status line (the line at the bottom of the page). An extension may specify "status":false to keep KUAL2 from displaying the action value.

"date":true

Use this to display the current date and time in the status line after KUAL2 has started an action.

[edit] Sub-menu Items

A sub-menu item includes menu action items and/or other sub-menu items. A sub-menu is expressed as a list of JSON key/value pairs. The following keys are supported: name, priority, items. Key items specifies a child sub-menu of the current sub-menu. See Template 1 for details.

[edit] Dynamic Sub-menu Example

Path: /mnt/us/extensions/toggle-music

Files: config.xml, menu.json, menu.state0, menu.state1, toggle.sh.

This example shows how you could add a sub-menu dynamically.

  • The sub-menu name is "AAA KUAL Music".
  • The sub-menu has two states: hidden and visible.
  • When "AAA KUAL Music" is hidden, KUAL displays button "AAA add KUAL Music" which adds the sub-menu.
  • When "AAA KUAL Music" visible, KUAL displays button "AAA remove KUAL Music".

config.xml

<?xml version="1.0" encoding="UTF-8"?>
<extension>
	<information>
		<name>KUAL2 Dynamic Menu Example</name>
		<version>0.1</version>
		<author>stepk</author>
		<id>test</id>
	</information>
	<menus>
		<menu type="json" dynamic="true">menu.json</menu>
	</menus>
</extension>

menu.json

{
  "items": [
     {"name": "AAA remove KUAL Music", "action": "./toggle.sh", "refresh":true, "exitmenu":false, "priority":-10000},
     {"name": "AAA KUAL Music", "priority":-10000,
      "items": [
         {"name":"Hack Is a Four-Letter Word","action": ":", "priority":1},
         {"name":"Apologies to Bob Dylan","action": ":", "priority":2}
       ]
     }
  ]
}

menu.state0

{
  "items": [
     {"name": "AAA add KUAL Music", "action": "./toggle.sh", "refresh":true, "exitmenu":false, "priority":-10000}
  ]
}

menu.state1

{
  "items": [
     {"name": "AAA remove KUAL Music", "action": "./toggle.sh", "refresh":true, "exitmenu":false, "priority":-10000},
     {"name": "AAA KUAL Music", "priority":-10000,
      "items": [
         {"name":"Hack Is a Four-Letter Word","action": ":", "priority":1},
         {"name":"Apologies to Bob Dylan","action": ":", "priority":2}
       ]
     }
  ]
}

toggle.sh

#/bin/sh -
state=0
cmp -s menu.json menu.state${state} >/dev/null && state=1
cp menu.state${state} menu.json 2>/dev/null

[edit] Where To Get KUAL2

Get KUAL 2.4 from the Unified Application Launcher, KUAL, forum post!

Sneak previews of newer versions might be available for testing/debugging purposes. Link to test builds topic: NiLuJe's snapshots

Version 2.4 is now available.

[edit] Where To Get More Extensions

Personal tools
Namespaces

Variants
Actions
Navigation
MobileRead Networks
Toolbox