summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lulua/data/report/index.html77
-rw-r--r--lulua/data/report/style.css8
-rw-r--r--lulua/report.py7
-rw-r--r--lulua/stats.py25
4 files changed, 110 insertions, 7 deletions
diff --git a/lulua/data/report/index.html b/lulua/data/report/index.html
index a18dcb7..cae6024 100644
--- a/lulua/data/report/index.html
+++ b/lulua/data/report/index.html
@@ -268,13 +268,18 @@
$$a = \frac{b_{left}}{b_{total}} - \frac{b_{right}}{b_{total}}$$
<p>
- The layout proposed uses four layers and assumes a 102/105 key ISO
- keyboard common in Europe to accomodate the shift keys necessary.
+ The layout proposed uses four shift layers in a way inspired by <a
+ href="https://neo-layout.org/">Neo2</a>.
+ <!-- -->
+ Thus it assumes a <a
+ href="https://en.wikipedia.org/wiki/IBM_PC_keyboard#Keyboard_layouts">102/105
+ key ISO keyboard</a> common in Europe – but also available in Arab
+ countries – to accommodate for the necessary shift keys.
<!-- -->
These are in order: <span class="layer second">Shift on the left and
right</span>, <span class="layer third">caps lock on the left and the
rightmost key in the middle row</span>, <span class="layer fourth">the
- key right of the left shift key and the key labeled <em>Alt Gr</em> to
+ key right to the left shift key and the key labeled <em>Alt Gr</em> to
the right of the spacebar</span>.
<!-- -->
Symbols are assigned to the four layers by their function: <span
@@ -282,6 +287,15 @@
second">punctuation</span>, <span class="layer
third">diacritics</span>, <span class="layer fourth">other</span>.
</p>
+ <details class="remarks">
+ <summary></summary>
+ <p>Apple, for instance, provides an <a
+ href="https://www.apple.com/shop/product/MLA22AC/A/magic-keyboard-arabic">Arabic
+ hardware keyboard</a> with this physical layout. But both variants,
+ 101/104 key and 102/105 key devices, seem to exist in the Arab
+ world.</p>
+ </details>
+
<p>
The first layer was optimized using an extended reimplementation of <a
href="http://mkweb.bcgsc.ca/carpalx/?typing_effort">carpalx</a>.
@@ -299,10 +313,10 @@
</p>
<details class="remarks">
<summary></summary>
- <p>(This is <a
+ <p>This is <a
href="https://github.com/mw8/white_keyboard_layout/blob/master/README.md#finding-the-optimal-layout">a
common way</a> of arranging brackets, because most algorithms ignore
- human desire for symmetry.)</p>
+ human desire for symmetry.</p>
</details>
<p>
@@ -317,6 +331,59 @@
typing load, but naturally the left middle finger is used more
frequently due to its assignment to the letter alif.
</p>
+
+ <p>
+ The layout targets Quaranic and Modern Standard Arabic (MSA), also called Fusha
+ (<bdo lang="ar">الفصحى</bdo>), only.
+ <!-- -->
+ Dialectical Arabic (<bdo lang="ar">العامية</bdo>) is mainly a spoken
+ language, although with the rise of social media sites like Twitter and
+ Facebook this is changing.
+ <!-- -->
+ For now however it’s not an optimization target due to the lack of a
+ good, representative corpus.
+ </p>
+
+ <p>
+ Designing the layout to be compose-based has both benefits and
+ disadvantages.
+ <!-- -->
+ Compose-based mainly means the hamza <bdo lang="ar" dir="ltr">ء</bdo>
+ is treated like an optional diacritic for Alef, Waw and Yah instead of
+ viewing Alef-Hamza, Waw-Hamza and Yah-Hamza as precombined, atomic
+ units.
+ <!-- -->
+ Although <bdo lang="ar" dir="ltr">أ</bdo> and <bdo lang="ar"
+ dir="ltr">ا</bdo> are not the same, the hamza can be dropped if the
+ writer’s intention is unambigiously inferable from context.
+ <!-- -->
+ Thus it makes sense to provide hamza as a combining character on the
+ keyboard.
+ <!-- -->
+ Additionally it uses two keys less than precombining it with its stems,
+ allowing the entire alphabet plus hamza diacritic to fit on a single
+ keyboard layer.
+ <!-- -->
+ However, there is a cost to this approach:
+ All hamza variants account for {{
+ '%.1f'|format(layoutstats['ar-osx'].hamzaImpact*100) }}% of button
+ combinations.
+ <!-- -->
+ Splitting hamza and from its stem means doubling the total number of
+ button combinations and thus button presses, decreasing scores like
+ words per minute (WPM) slightly.
+ <!-- -->
+ Splitting Alef and Alef-Hamza could also reduce pressure on left middle
+ finger and allow for more even distribution, since {{
+ layoutstats['ar-osx'].hamzaOnAlef|fraction }}<sup>th</sup> of all Alef
+ uses are with Hamza.
+ </p>
+ <details class="remarks">
+ <summary></summary>
+ <p>See for example section 3.3 of <a
+ href="https://doi.org/10.1007/978-1-4020-6046-5_3">Buckwalter’s <em>Issues in Arabic Morphological Analysis</em></a>.
+ </p>
+ </details>
</div>
</div>
</div>
diff --git a/lulua/data/report/style.css b/lulua/data/report/style.css
index f62fcef..ed0d32d 100644
--- a/lulua/data/report/style.css
+++ b/lulua/data/report/style.css
@@ -240,6 +240,12 @@ details[open].remarks {
margin-bottom: 1em;
}
details.remarks summary {
- list-style-type: "+";
+ list-style-type: "↳ Remarks";
cursor: pointer;
+ opacity: 0.4;
}
+
+details.remarks p {
+ margin-top: 0;
+}
+
diff --git a/lulua/report.py b/lulua/report.py
index 8a50681..b25201d 100644
--- a/lulua/report.py
+++ b/lulua/report.py
@@ -21,6 +21,7 @@
import sys, argparse, logging, pickle, math
from gettext import GNUTranslations, NullTranslations
from decimal import Decimal
+from fractions import Fraction
import yaml
from jinja2 import Environment, PackageLoader
@@ -40,6 +41,11 @@ def approx (i, lang='en'):
units.pop (0)
return round (i, 1), units[0]
+def fraction (n, maxdenom=10):
+ """ Turn floating number n into a human-digestable fraction """
+ f = Fraction (n).limit_denominator (maxdenom)
+ return f'{f.numerator}\u2044{f.denominator}'
+
def numspace (s):
""" Replace ordinary spaces with unicode FIGURE SPACE """
return s.replace (' ', '\u2007')
@@ -83,6 +89,7 @@ def render ():
env.filters['numspace'] = numspace
env.filters['arabnum'] = arabnum
env.filters['blendn'] = blendn
+ env.filters['fraction'] = fraction
corpus = []
for x in args.corpus:
diff --git a/lulua/stats.py b/lulua/stats.py
index 9c11d10..1d051b3 100644
--- a/lulua/stats.py
+++ b/lulua/stats.py
@@ -360,7 +360,7 @@ from .text import mapChars, charMap
def layoutstats (args):
"""
- Statistics for the report
+ Various statistics for the report
"""
stats = pickle.load (sys.stdin.buffer)
@@ -384,6 +384,27 @@ def layoutstats (args):
]
sentences = [sentenceStats (keyboard, layout, mapChars (s, charMap).replace ('\r\n', '\n')) for s in sentences]
+ # Impact of hamza
+ yah = '\u064a'
+ waw = '\u0648'
+ alef = 'ا'
+ hamzaAbove = '\u0654'
+ hamzaBelow = '\u0655'
+ # list of combination counts for each match
+ combPerGroup = defaultdict (int)
+ combStats = stats['simple'].combinations
+ letterWithHamza = [alef+hamzaAbove, alef+hamzaBelow, yah+hamzaAbove, waw+hamzaAbove]
+ for letter in [alef] + letterWithHamza:
+ match, combinations = layout (letter)
+ if match != letter:
+ # not a single key or single combination
+ continue
+ combPerGroup[letter] += sum (map (lambda x: combStats[x], combinations))
+ combinations = sum (stats['simple'].combinations.values ())
+ hamzaImpact = sum (map (lambda x: combPerGroup[x], letterWithHamza))/combinations
+ x = combPerGroup[alef+hamzaAbove] + combPerGroup[alef+hamzaBelow]
+ hamzaOnAlef = x/(x+combPerGroup[alef])
+
pickle.dump (dict (
layout=args.layout,
hands=dict (hands),
@@ -391,6 +412,8 @@ def layoutstats (args):
buttonPresses=buttonPresses,
asymmetry=asymmetry,
sentences=sentences,
+ hamzaImpact=hamzaImpact,
+ hamzaOnAlef=hamzaOnAlef,
), sys.stdout.buffer)
def latinImeDict (args):