GTK+ CapsLock

ちょ、何故今まで気が付かなかったのだ?
CapsLock が掛かっていると自作アプリの Ctrl+o 等が動作しない!

GNOME 標準アプリは問題なく使えるのね。
うん、GTK+ における CapsLock について調べる必要があるな。

てなわけで調べたんだけど。
CapsLock は GTK+ では Ctrl, Shift と同じ装飾キー扱いなのね。
具体的には列挙体で

1:Shift,
2:CapsLock
4:Ctrl
8:Alt

が OR 演算で key-press-event シグナルの GdkEvent に入ってくる。
On にした状態だとずっと押されていると認識するというおまけつき。

つまり CapsLock が On の状態では、えっと。
Ctrl+o は CapsLock+Ctrl+O と認識、装飾キーが 6 で O が大文字。
なるほど、動かなくて当然だ。

CapsLock 状態を別途で調べる。
On であれば装飾キー値 gdk_event_get_state から 2 を引く。
On 又は Shift を押した状態なら gdk_event_get_keyval 値を小文字化。
という流れで CapsLock を完全に無視できるようだ。

#!/usr/bin/gjs

const Gtk = imports.gi.Gtk;
const Gdk = imports.gi.Gdk;
const Lang = imports.lang;

const KeyPressWindow = new Lang.Class({
    Name: 'KeyPressWindow',
    Extends: Gtk.ApplicationWindow,

    _init: function(app) {
        this.parent({
            application: app
        });
        this.connect("key-press-event", Lang.bind(this, function(widget, event) {
            /**
             * CapsLock
             */
            let keymap = Gdk.Keymap.get_default();
            let caps_state = keymap.get_caps_lock_state();
            let caps = caps_state ? "[CapsLock]+" : "";
            /**
             * Modifier
             */
            let [ok, state] = event.get_state();
            let mod = "";
            if (ok) {
                if (caps_state)
                    state -= 2;
                switch(state) {
                case 1:
                    mod = "Shift+";
                    break;
                //case 2:
                //    mod = "CapsLock+";
                //    break;
                case 4:
                    mod = "Ctrl+";
                    break;
                case 5:
                    mod = "Ctrl+Shift+";
                    break;
                case 8:
                    mod = "Alt+";
                    break;
                case 9:
                    mod = "Alt+Shift+";
                    break;
                case 12:
                    mod = "Alt+Ctrl+";
                    break;
                case 13:
                    mod = "Alt+Ctrl+Shift+";
                    break;
                }
                /**
                 * Key
                 */
                let [ok, keyval] = event.get_keyval();
                if (ok) {
                    // CapsLock or Shift
                    if (Gdk.keyval_is_upper(keyval))
                        keyval = Gdk.keyval_to_lower(keyval);
                    //let key = String.fromCharCode(keyval);
                    let key = Gdk.keyval_name(keyval);
                    if (key != null)
                        this.set_title(`${caps}${mod}${key}`);
                }
            }
        }));
        this.show_all();
    }
});

let app = new Gtk.Application();
app.connect("activate", function() {
    new KeyPressWindow(app);
});
app.run(null);

こんな感じ。

GNOME 標準アプリがどうやって認識しているかは調べていないけど。
もっといい手段があるかも、とりあえずは様子見かな。
やっと晴れたし名駅前でスイクンでも(関係無い!