Springe zum Hauptinhalt

Migrate from Evernote to Joplin

On my journey to move away from closed services I was looking for a note taking application, an Evernote replacement to be specific and stumbled across Joplin. Even though not using Evernote very frequently anymore I wanted to preserve my notebooks, some of them being well-maintained collections of particular topics.

Joplin

Advantages of choosing Joplin:

  • synchronisation capabilities (Nextcloud yay!)

  • import Evernote notebooks

  • desktop and mobile applications

  • write notes in Markdown (various plugins available, see Joplin's Markdown Guide)

This all sounded really good so I planned my further steps:

  1. install the desktop and mobile app

  2. export Evernote content

  3. set up Nextcloud sync

  4. import Evernote content

  5. evaluate results

  6. use Joplin

  7. delete Evernote account

With Joplin one can create, write and manage extensive collections of any topic. This is just one among many options, see also 12 Best Open Source Evernote Alternatives 2022.

The headache of exporting Evernote content

Getting notebooks out of Evernote became a bit tricky because one cannot just export them in the web browser interface or mobile app. The export function is exclusively available on one of the desktop applications. You can easily install the application on Windows and MacOS but this is a static blog so of course I am using Linux...

There is however the straw of a repackaged Evernote client for Windows available for Linux which is not open source:

Unfortunately you still have to export your notebooks one after the other.

Nextcloud WebDAV URL

If you follow the Nextcloud synchronisation instructions, you must input the WebDAV URL, not just the Nextcloud instance. This information is to be found in the Setting on the bottom left (see figure).

/images/joplin/webdav.png

Aaaand we are done

The Joplin desktop client has a similar application structure. It lacks fancy widgets (pro or con, you decide) and has a cleaner look.

/images/joplin/desktop.png

Switching from "setup.py install" to pip

When working on NoN I ran into the following message:

SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools

So I took a look at it, did a quick research and decided solving the problem should be doable for me.

Interesting/important links to start with:

What has setup.py ever done for us?

Among the obvious part, installing the application itself into the correct destination folder while also handling dependencies, one can specify plenty of additional files to be coped with like starter scripts, .desktop files, app icons, providing all kinds of the project's metadata.

If you are fierce enough or just don't know better you can write custom install/de-install/ruin the system routines - anything's possible.

For my personal use case the following tasks are required:

  1. install application files

  2. handle dependencies

  3. copy .desktop file

  4. copy starter script

  5. copy application icon

Converting setup.py to setup.cfg

You can however continue using setup.py with pip. setup.cfg is the TOML-formatted static configuration of the setuptools.setup function that is, according to the packaging tutorial, "simpler, easier to read, and avoids many common errors".

If you come from using $ python setup.py install like me you will already have a working setup.py script that can be easily transformed.

[metadata]

The first section of the file includes all the metadata so:

...
import info
...
with open(os.path.join(here, "README.md"), encoding="utf-8") as f:
long_description = "\n" + f.read()

setup(
    name=info.NAME,
    version=info.__version__,
    description=info.DESCRIPTION,
    long_description=long_description,
    long_description_content_type="text/markdown",
    license=info.__license__,
    ...,
)

becomes

[metadata]
name = non
version = 0.81
description = Knights Of Ni - a GTK+ manager for your Nikola powered website
long_description = file: README.md
long_description_content_type = text/markdown
license = MIT
...

For convenience and readability purposes I once put all the proper data into a separate info function so I didn't need to touch the install script which now has become dispensable.

[options]

The same applies for the remaining values that are listed in the options section.

All possible keywords/values are listed in the setuptools documentation. Some keys require a "section" data type that means these keys get their own subsection, p.e. "[options.data_files]".

So the old setup function

...
import info
...

setup(
    ...,
    python_requires=info.REQUIRES_PYTHON,
    packages=info.PACKAGES,
    package_dir=info.PACKAGE_DIR,
    install_requires=info.REQUIRED,
    include_package_data=True,
    data_files=info.DATAFILES,
    package_data=info.PACKAGE_DATA,
)

becomes

[options]
packages = non
python_requires = >=3.6
install_requires =
    Nikola
    PyGObject
    PyYAML
include_package_data = True

[options.data_files]
share/applications =
    data/non.desktop
share/icons/hicolor/scalable/apps =
    non/ui/duckyou.svg
bin =
    data/non

[options.package_data]
...

build

After plagiarizing the pyproject.toml file from the packaging tutorial we are ready to build and hopefully will end up with an installable archive.

But first make sure to have a current build package builder installed:

$ python -m pip install --upgrade build

Then run build from the project's directory:

$ python -m build
* Creating virtualenv isolated environment...
* Installing packages in isolated environment... (setuptools>=42)
* Getting dependencies for sdist...
running egg_info
writing non.egg-info/PKG-INFO
writing dependency_links to non.egg-info/dependency_links.txt
writing requirements to non.egg-info/requires.txt
[...]
Successfully built non-0.81.tar.gz and non-0.81-py3-none-any.whl

Install the archive with pip:

$ pip install dist/non-0.81-py3-none-any.whl

Now it's time to check if everything is in its place and working.

Minor adjustments & tidying up the project

Start script

The installation path is determined by the Python version so the .desktop file points to the new start script that figures out the installation path instead of directly pointing to the application:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# execution file to put in /usr/bin

import os
import non

os.chdir(os.path.dirname(non.__file__))

from non import application
setup.py

None of the (custom) commands are needed anymore, the file is obsolete.

info file

All information have been merged into setup.cfg, the file is obsolete.

README.md

Pip now handles the installation and deinstallation process, edit installation section.

Final thoughts

Making my application pip install-ready was easier than expected with an even more compliant result than before. 10/10 would use pip again.

NoN: v0.8 release

The GTK GUI tool for managing Nikola powered websites Knights of Ni (NoN) just some polishing recently and I was shocked (shocked!) to see that the last release is two years old so I drafted a release from the current status.

A major change was the removal of the application-wide draft feature (Nikola's draft mode not affected). It was a rudimental implementation of an idea that I didn't know where to go with. I figured it would go to /dev/null eventually without regrets.

The application is still completely dependent on GTK3. Installation has been tested for Archlinux and Ubuntu.

The About dialog still proclaims it is version 0.7 but the dialog is lying, the version is 0.8. Trust me.

Sportplus trampoline fix

Achtung!

This article first appeared on Mastodon.

Somebody might remember me owning a fitness trampoline (a Sportplus SP-T-110) which I use on an almost daily basis.

So it was just a matter of time that the first rubber band snaps (I'm doing quite high jumps on my HIIT routine and from the product reviews that can and will happen regardless of workout intensity/weight).

In theory you can buy a replacement rubber band set and in practice it is not in stock atm.

So I bought regular bungee cord and clips and started to macgyver around.

/images/sportplus_fix1.thumbnail.jpg

I purchased the 8 mm bungee cord that turned out to be a bit too thick but still with the power of patience and a bit force the cord fit through the hole of the plastic mount.

The chosen length resulted in an educated guess based on the original cord and the lower elasticity of the new cord.

/images/sportplus_fix2.thumbnail.jpg

This is the result. I bought the green bungee cord on purpose, the replaced rubber bands are easy to spot.

/images/sportplus_fix3.thumbnail.jpg

This has been working for over two months now to my satisfaction with two replaced cords. I'm convinced I have to replace more original rubber bands with time. So be it.

Nikola: some new colour flavours for the Hybrid theme

The Hybrid theme for Nikola is a member of the Hyde theme family. You are able to set any subtheme it provides which are the main colours from the base16 project.

I'm not really a fan of these so I added some additional strong colours to the Hybrid theme that I use. My PR to the themes' repository was accepted so this is included in the theme when downloading from the application.

Now there are plenty of subthemes to choose from:

THEME_CONFIG = {
    DEFAULT_LANG: {
        # "hyde_subtheme": "theme-custom",
        # "hyde_subtheme": "theme-hybrid-01", # petrol
        # "hyde_subtheme": "theme-hybrid-02", # dark red
        # "hyde_subtheme": "theme-hybrid-03", # forest
        # "hyde_subtheme": "theme-hybrid-04", # eggplant
        # "hyde_subtheme": "theme-hybrid-05", # dark orange
        # "hyde_subtheme": "theme-base-08", # red
        # "hyde_subtheme": "theme-base-09", # orange
        # "hyde_subtheme": "theme-base-0a", # yellow
        # "hyde_subtheme": "theme-base-0b", # green
        # "hyde_subtheme": "theme-base-0c", # cyan
        # "hyde_subtheme": "theme-base-0d", # blue
        # "hyde_subtheme": "theme-base-0e", # magenta
        # "hyde_subtheme": "theme-base-0f", # brown
        # ...
    }
}

Hyde colours

/images/hybrid-colours/base-08.png

theme-base-08

/images/hybrid-colours/base-09.png

theme-base-09

/images/hybrid-colours/base-0a.png

theme-base-0a

/images/hybrid-colours/base-0b.png

theme-base-0b

/images/hybrid-colours/base-0c.png

theme-base-0c

/images/hybrid-colours/base-0d.png

theme-base-0d

/images/hybrid-colours/base-0e.png

theme-base-0e

/images/hybrid-colours/base-0f.png

theme-base-0f

Hybrid colours

/images/hybrid-colours/hybrid-01.png
/images/hybrid-colours/hybrid-02.png

theme-hybrid-01

theme-hybrid-02

/images/hybrid-colours/hybrid-03.png
/images/hybrid-colours/hybrid-04.png

theme-hybrid-03

theme-hybrid-04

/images/hybrid-colours/hybrid-05.png
/images/hybrid-colours/custom.png

theme-hybrid-05

theme-custom

Custom colour

The custom-theme has preset colours that you can directly change in the hybrid.css or better in your custom.css. Just create the file if you haven't already and add and adapt this snippet:

/* custom subtheme for hyde/hybrid theme */
.theme-custom .hsidebar {
  background-color: #070512;
}
.theme-custom .content a,
.theme-custom .related-posts li a:hover {
  color: #1582ae;
}

Comments

You can use your Mastodon account to reply to this post.

Reply

New online presence

There is a moving process going on from my GitHub Page: Merge and Destroy.

See you soon.

Update May 17th

I imported most of the posts and pages, images and listings and so on. I will probably leave the tutorials and some posts also over at the GitHub Page but will slim the page down.

The Google+ archive is now also hosted here.

Adding Mastodon comments to your static Nikola blog

Static and comments

The neverending story. The arch enemies. Beauty and the Beast. If you want to enable comments in a static blog article you will have to come back to third party services.

Nikola already supports several comment systems like Disqus or Isso. As a frequent Mastodon user it has long been my intent to integrate Mastodon threads as a detour comment system.

I stumbled across this JavaScript solution that does the job on any static page: Adding comments to your static blog with Mastodon.

The comments listed are the replies to the corresponding toot:

Potential and restrictions

Unlike embedded Mastodon toots the loaded comments fit neatly to the blog (some CSS theme adaptation required). Adding a comment is still done via the Mastodon web UI.

If you announce an article to Mastodon and want to refer to that toot as your comment thread you will have to either edit the page because you don't know the toot id in advance and therefore build and deploy your site a second time or be quick and announce the article before deploying and then edit the toot id.

A classic comment moderation is not possible though. I personally expect spam and inappropriate contents quite unlikly as you need a Mastodon account in the first place and instance admins are usually very accurate when it comes to enforce their instance rules. This might change with time but right now I don't see a substantial danger.

Preparing Nikola

The main question is "Where put the code?" and the answer is:

/images/shortcodes.jpg

A shortcode provides a code snippet that you can call via

{{% name parameters %}}

just save the file in the shortcodes folder.

mastodon-comments.tmpl (Source)

{#
Usage:

    {{% mastodon-comments host=instance.domain username=username id=tootnr %}}

#}

<h2>Comments</h2>
<div class="article-content">
  <p>You can use your Mastodon account to reply to this <a class="link" href="https://{{ host }}/@{{ username }}/{{ id }}">post</a>.</p>
  <p><a class="button" href="https://{{ host }}/interact/{{ id }}?type=reply">Reply</a></p>
  <p id="mastodon-comments-list"><button id="load-comment">Load comments</button></p>
  <noscript><p>You need JavaScript to view the comments.</p></noscript>
  <script src="/assets/js/purify.min.js"></script>
  <script type="text/javascript">
    function escapeHtml(unsafe) {
      return unsafe
           .replace(/&/g, "&amp;")
           .replace(/</g, "&lt;")
           .replace(/>/g, "&gt;")
           .replace(/"/g, "&quot;")
           .replace(/'/g, "&#039;");
   }

    document.getElementById("load-comment").addEventListener("click", function() {
      document.getElementById("load-comment").innerHTML = "Loading";
      fetch('https://{{ host }}/api/v1/statuses/{{ id }}/context')
        .then(function(response) {
          return response.json();
        })
        .then(function(data) {
          if(data['descendants'] &&
             Array.isArray(data['descendants']) &&
            data['descendants'].length > 0) {
              document.getElementById('mastodon-comments-list').innerHTML = "";
              data['descendants'].forEach(function(reply) {
                reply.account.display_name = escapeHtml(reply.account.display_name);
                reply.account.emojis.forEach(emoji => {
                  reply.account.display_name = reply.account.display_name.replace(`:${emoji.shortcode}:`,
                    `<img src="${escapeHtml(emoji.static_url)}" alt="Emoji ${emoji.shortcode}" height="20" width="20" />`);
                });
                mastodonComment =
                  `<div class="mastodon-comment">
                     <div class="avatar">
                       <img src="${escapeHtml(reply.account.avatar_static)}" height=60 width=60 alt="">
                     </div>
                     <div class="comment">
                       <div class="author">
                         <a href="${reply.account.url}" rel="nofollow">
                           <span>${reply.account.display_name}</span>
                           <span class="disabled">${escapeHtml(reply.account.acct)}</span>
                         </a>
                         <a class="date" href="${reply.uri}" rel="nofollow">
                           ${reply.created_at.substr(0, 10)}
                         </a>
                       </div>
                       <div class="mastodon-comment-content">${reply.content}</div>
                     </div>
                   </div>`;
                document.getElementById('mastodon-comments-list').appendChild(DOMPurify.sanitize(mastodonComment, {'RETURN_DOM_FRAGMENT': true}));
              });
          } else {
            document.getElementById('mastodon-comments-list').innerHTML = "<p>Not comments found</p>";
          }
        });
      });
  </script>
</div>

The script uses DOMPurify so you have to put the purify.min.js file into the $THEME/assets/js/ folder.

There are some div classes used in the code and may require some adaptation to your theme. This should be done in the custom.css. I stole the CSS from Carl's site and this is what I use here:

custom.css (Source)

.mastodon-comment {
 background-color: azure;
 border-radius: 10px;
 padding: 5px;
 margin-bottom: 1rem;
 display: flex;
 font-size: 80%;
}
.mastodon-comment .content {
 flex-grow:2
}
.mastodon-comment .avatar img {
 margin-right:1rem;
 min-width:60px
}
.mastodon-comment .author {
 padding-top:0;
 display:flex
}
.mastodon-comment .author .date {
 margin-left:auto
}
.mastodon-comment .disabled {
 color:var(--accent-color)
}
.mastodon-comment-content p:first-child {
 margin-top:0
}

That's it.

Just add a shortcode to any article in your blog. You can even provide a regular comment system like Disqus parallely.

Comments

You can use your Mastodon account to reply to this post.

Reply

Websites that answer a single specific question

Hints are welcome. Comment here or over at Mastodon. In case of updates post gets republished.

BER - Berlin Brandenburg Airport

The first question touches a sore spot - Germany's most famous airport (BER). The construction project has been full of scandals involving mismanagement, patronage, bad planning, massive budget overrun and, of course, delay:

"Is the BER already open?" - though the answer is incorrect now

or

"Has the BER been finished yet?" with more sad details (German)

Friday?

This is an easy one:

"Is it Friday?" (Danish)

Traffic

The third site answers the question whether the avenue behind the Brandenburg Gate in Berlin is closed for traffic (which often is the case due to public events like marathon, turn of the year or national ceremonies):

"Is the 17th of June Street closed?" (German)

Tech

"Should I use threads?"

Transportation

The container ship Ever Given grounded in the Suez Canal completely blocking any traffic:

"Is that ship still stuck?"


Mastodon: Timeline beleben

Nach großem Medienrummel um den Eigentümerwechsel vom Twitter quillt das Fediverse und insbesondere Mastodon über vor neuen und neugierigen Nutzern. Willkommen an dieser Stelle!

Dieser Artikel wurde und wird immer mal wieder bearbeitet und ergänzt.


Timelines

/images/Mastodon/timelines.png
Local

Als Neuling startet man gewöhnlich mit der Registrierung bei einer bestehenden Instanz, das heißt, die lokale Timeline der Instanz ist einen regelmäßigen Besuch Wert.

Federated

Die instanzübergreifende Timeline kann je nach Instanzsetup, Tageszeit und Interesse mehr oder weniger ergiebig sein, häufig sieht man die Tröts vor lauter Spam nicht, trotzdem sollte man hier zumindest mal reinschauen.

Profilverzeichnis

Hinter dem Profile directory versteckt sich eine ganz nützliche Übersicht von aktiven Nutzern der eigenen und anderer Instanzen. Hier sieht man auch, wie nützlich es für andere ist, eine Kurzbio und ein Profilbild einzupflegen. Diese Übersicht muss nicht in jeder Instanz aktiv sein.

Bemerkung

Möchte man nicht im Profilverzeichnis gelistet werden, kann man dies in den Einstellungen unter Profile -> Appearance -> Suggest account to others deaktivieren.

Hashtags

Die Suchfunktion lässt immer noch zu wünschen übrig und so ist die Suche nach Hashtags am zielführendsten.

Entweder sucht man direkt in der Suchleiste in der linken Spalte (siehe auch den dort erscheinenden Tooltipp) oder ruft die URL <instance>/tags/<tag> auf.

Verwendet man das advanced web interface, also die Mehrspaltenansicht, kann man die Stichworte als eigene Spalte anheften.

Im Umkehrschluss heißt das natürlich, bei eigenen Beiträgen aussagekräftige und konsistente Hashtags hinzuzufügen, um auch von anderen gefunden zu werden.

Leute

Mit ein wenig Klicken und Scrollen in den Timelines findet man schnell das ein oder andere Profil, bei dem man genauer hinschaut. Falls man gar nicht weiß, wo man anfangen soll, folgt man zunächst seinem eigenen Instanzbetreiber (zu finden auf der About-Seite).

Abgesehen von den Posts/Tröts sind folgende Punkte in einem Profil interessant:

  • Wird das Profil aktuell verwendet? Mastodon hat immer mal wieder kleine Hypes erlebt, es gibt viele verwaiste (zum Teil auch mit einem Umzug auf eine andere Instanz verbunden) Profile.

  • Wem folgt diese Person?

  • Wer folgt dieser Person?

  • Welche Interessen hat die Person (Kurzbio, Featured hashtags)?

  • Gibt es noch mehr interessante Profile im Profilverzeichnis dieser Instanz (obere Leiste auf jeder Profilseite)?

Man hangelt sich also sprichwörtlich von Baum zu Baum, bringe also etwas Zeit mit...

/images/Mastodon/profiledir.png
Trunk

Für den englischsprachigen Bereich gibt es ein nach Interessen geordnetes Verzeichnis, in das man sich per Request eintragen lassen kann: Trunk.

Bots

Menschen sind ja auch nicht alles. Da das ganze Fediversum auf freier Technologie basiert und auch Mastodon einfach per API zugänglich ist, sind automatisierte Posts nicht weit. Dafür gibt es mit botsin.space eine eigene Instanz.

Bei den überwiegend sehr ernsthaften Beiträgen auf Mastodon können Botbeiträge durchaus stimmungsaufhellend wirken.

Gruppen

Sogenannte Gruppen bieten die Möglichkeit, Beiträge zu beliebigen Themen zu abonnieren. Mastodon selbst bietet keine Gruppenfunktionalität wie etwa Friendica. Auch ist es bislang nicht möglich, Hashtags direkt zu folgen (v3.5.1) und so ist der Workaround über gup.pe groups entstanden.

Dienste, die das ActivityPub-Protokoll unterstützen, können mit gup.pe groups interagieren. Sobald man einer Gruppe folgt, werden alle Beiträge, in denen die Gruppenadresse erwähnt wird, in die eigene Timeline weitergeleitet (geboostet). Auf diese Weise kann man sich zu Themen mit Leuten austauschen, die sich (noch) nicht untereinander kennen bzw. folgen.

/images/Mastodon/guppeboost.png

Was Gruppen nicht sind

Eine "Gruppe" ist kein abgegrenzter Bereich im Sinne einer Facebook-Gruppe oder eines Forums. Im Prinzip handelt es sich einfach ausgedrückt um einen Themen-Abo-Service, aber das klänge nun auch etwas dröge, wäre aber in der Tat zutreffender.

Weitere Eigenschaften der Gruppen, die keine sind:

  • es gibt keine Moderation/Moderatoren/Eigentümer

  • man kann keine Beiträge sehen, die vor dem Beitritt zur Gruppe (= folgen) gepostet wurden

  • mit Ausnahme der eigenen Instanz ist nicht ersichtlich, wer ebenfalls der Gruppe folgt

  • keine individuelle Gruppenbeschreibung

Wo und wie finde ich nun Gruppen?

Gruppen werden aktuell unter a.gup.pe und chilli.social gehostet.

Es gibt zwei Möglichkeiten, Gruppen zu finden:

  1. Webinterface der genannten Gruppen-Dienste, dort sind allerdings maximal 50 populäre Gruppen gelistet

  2. Suchfunktion im Mastodon-Webinterface

/images/Mastodon/guppesearch.png/images/Mastodon/guppeprofile.png

Aktiv werden

Bei Mastodon wird man ohne eignes Zutun nicht so einfach bespaßt, man muss sich selbst um seine Unterhaltung kümmern. Dazu muss und kann man auf verschiedene Arten aktiv werden:

  • fav, was dir gefällt

  • booste, was dir besonders gefällt

  • kommentiere, und sei es ein schlagfertiger Spruch oder einfach ein Danke, egal - was soll passieren?

  • vervollständige dein Profil, in der Reihenfolge Avatar, Kurzbio, Links, Featured hashtags, pinne einen oder wenige für dich relevante Tröts an

  • verfasse einen #introduction -Tröt (auf Deutsch auch die Hashtags #vorstellung und #neuhier verwenden) und stell dich der Gemeinde vor

  • tröte selbst, auch wenn man zunächst gefühlt ins Unbekannte sendet

Persönliche und völlig subjektive Tipps

Poste selbst

Profile, die nur oder überwiegend aus Boosts bestehen, finde ich uninteressant, dann folge ich lieber dem Original.

Alltägliches

Schreib auch mal was von dir, was Lustiges, Profanes, Alltägliches, wie wäre es mit einem Foto von draußen? Schreib lieber deine eigenen Showerthoughts auf als der Zehnte zu sein, der irgendeinen aktuellen Aufreger per Screenshot verbreitet.

Mastodon-Interessen-Bingo

Du arbeitest in Tech, interessierst dich für FLOSS, Datenschutz, bist politisch total engagiert, gegen ganz viel und empörst dich gern? Ist ja gut und schön, aber hier auch nicht sehr originell (ja okay, Mastodons sind Herdentiere), was macht dich sonst noch aus? Hast du auch andere Hobbies (Steine sammeln, (Nischen-)Sport, Handwerken/Basteln, Schnulzen gucken, whatever)? Erzähl mal!

CW

Ich möchte das Fass Content Warning hier nicht aufmachen, nur eins: es muss nicht jeder Inhalt hinter einer CW versteckt werden. Im Gegenteil, ich komme mir verarscht vor und halte es auch für den Umgang auf der Plattform hier für kontraproduktiv, diese Funktion im Übermaß zu nutzen.

Click

Comments

You can use your Mastodon account to reply to this post.

Reply

TUXEDO laptop keyboard

Recently it was finally time to replace my beloved Dell notebook. I gave TUXEDO Computers a try.

This article may in part apply to other models but I refer to the TUXEDO Book BC1510 using Archlinux.

Driver installation

This seems a no-brainer but for the sake of completeness it shall be mentioned to install the TUXEDO keyboard driver to enable backlight functions and Fn/media keys. The easiest way to do this is installing the package from the AUR.

Toggle touchpad on shortcut

Oddly enough there doesn't seem to be a Fn/media key for toggling the touchpad which is a function I personally use quite often.

The common way to assign keyboard shortcuts is using xmodmap by customizing the .Xmodmap file in the user's home.

Assign XF86TouchpadToggle to a key or shortcut.

You can find out whether the function is theoretically assigned to any key by searching for it:

$ xmodmap -pke | grep Touchpad
------------------
output for BC1510:
------------------
keycode 199 = XF86TouchpadToggle NoSymbol XF86TouchpadToggle NoSymbol XF86TouchpadToggle
keycode 200 = XF86TouchpadOn NoSymbol XF86TouchpadOn NoSymbol XF86TouchpadOn
keycode 201 = XF86TouchpadOff NoSymbol  XF86TouchpadOff NoSymbol XF86TouchpadOff

Test the functionality by executing the keystroke via xdotool:

$ xdotool key 199

This probably works except you are using...

GNOME Shell

Long story short: xmodmap does not work with GNOME Shell/Wayland. If you intend to take the red pill take this way to XKB, or take the blue pill by just assigning the function to a shortcut via gsettings.

Open dconf-editor and pilot to org.gnome.settings-daemon.plugins.media-keys/touchpad-toggle and set a custom value, p.e. ['F4'].

No touchpad symbol? F4 unoccupied.

Keyboard backlight

Now comes the fun part. You don't buy a device with keyboard backlight without making use of it.

By default on boot the backlight is white. The integrated backlight of the BC1510 model is RGB so it's playtime.

Media keys

Backlight control via shortcuts is available on numpad keys:

  • Fn + /: cycle through a preset of colors (red, lime, blue, yellow, fuchsia, aqua, white, off)

  • Fn + *: toggle backlight on/off

  • Fn + +: increase brightness

  • Fn + -: decrease brightness

Backlight keys.

TUXEDO Backlight Control

The TUXEDO Backlight Control provides a CLI and Tkinter GUI to control the keyboard backlight. The package can be installed from the AUR.

There are some shortcomings:

  1. The authentication restrictions are annoying and IMHO pointless. There is no need to require superuser rights when changing backlight colors.

  2. There is no option to adjust brightness.

  3. Custom colors can be defined but must be written in a colors.conf file (required superuser rights).

The enhanced TUXEDO Backlight Control

Achtung!

Only developed and tested with Arch.

I created a tweaked version to get rid of the negative aspects mentioned above.

First, there are no more password prompts when executing a backlight command or launching the GUI (adjusted PolicyKit permissions).

Second, there are two new functions in the CLI:

# brightness control, set a value between 0 and 255, example:
$ backlight 124

# set a custom color by passing the hex color code, example:
$ backlight color ff5900

One may want to process the backlight command in scripts, for example visualize low battery status, notifications or graduently changing colors depending on the time of day...

Download forked version from encarsia/tuxedo-backlight-control (Arch package available).

Looping through color preset