get_modifier_state

我がアプリに矢印キーの代わりにマウスで押すボタンを付けた。
出した後で気が付いた、矢印キーの設定と連動していない。

まあ普通に GdkEvent を作って emit すれば…じゃない!
このアプリでは Ctrl 等の装飾キー状態も必要だった。

ボタンクリックのハンドラにて現在どの装飾キーが押されているかを取得。
それって手段があるのか?ってレベルの話だな。
ガチでアプリを作っている人でないと一生気にならなそうだ。

get_modifier

なんだ devhelp で get_modifier と検索したらアッサリ。
早速試してみよう。

#!/usr/bin/env python3

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk
 
class ButtonWin(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self)
        button = Gtk.Button(label="modifier = ?")
        button.connect("clicked", self.on_button_clicked)
        self.connect("delete-event", Gtk.main_quit)
        self.add(button)
        self.show_all()

    def on_button_clicked(self, button):
        kmp = Gdk.Keymap.get_default()
        state = kmp.get_modifier_state()
        if state == 0:
            button.set_label("modifier = NULL")
        elif state == 1:
            button.set_label("modifier = Shift")
        elif state == 4:
            button.set_label("modifier = Ctrl")
        elif state == 5:
            button.set_label("modifier = Shift+Ctrl")
        elif state == 8:
            button.set_label("modifier = Alt")
        elif state == 9:
            button.set_label("modifier = Shift+Alt")
        elif state == 12:
            button.set_label("modifier = Ctrl+Alt")
        elif state == 13:
            button.set_label("modifier = Shift+Ctrl+Alt")
        else:
            button.set_label("modifier = ???")

ButtonWin()
Gtk.main()

test1

これでボタンからでも装飾キーの状態が判別できるね。
後は GdkEvent を作って key-press-event に投げれば…

#!/usr/bin/env python3

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk
 
class ButtonWin(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self)
        button = Gtk.Button(label="Press Key 'A'")
        button.connect("clicked", self.on_button_clicked)
        self.connect("delete-event", Gtk.main_quit)
        self.connect("key-press-event", self.on_key_press_event)
        self.add(button)
        self.show_all()

    def on_button_clicked(self, button):
        """
            Gdk-WARNING **:
            Event with type 8 not holding a GdkDevice.
            It is most likely synthesized outside Gdk/GTK+

        """
        kmp = Gdk.Keymap.get_default()
        event = Gdk.Event()
        event.type = Gdk.EventType.KEY_PRESS
        event.state = kmp.get_modifier_state()
        event.keyval = Gdk.KEY_a
        event.window = self.props.window
        event.put()

    def on_key_press_event(self, widget, event):
        if event.state == Gdk.ModifierType.CONTROL_MASK:
            self.set_title("Ctrl+{0}".format(chr(event.keyval)))
        else:
            self.set_title("{0}".format(chr(event.keyval)))

ButtonWin()
Gtk.main()

test2

これで Ctrl を押しながらボタンクリックも Ctrl+a にはなるけど。
GdkDevice がどうのとワーニングになってしまう。

キーボードの指定か何か必要なのか?よくワカンネェYO!
よし必殺技だ、ハンドラを関数として呼び出ししてまえ。

#!/usr/bin/env python3

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk
 
class ButtonWin(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self)
        button = Gtk.Button(label="Press Key 'A'")
        button.connect("clicked", self.on_button_clicked)
        self.connect("delete-event", Gtk.main_quit)
        self.connect("key-press-event", self.on_key_press_event)
        self.add(button)
        self.show_all()

    def on_button_clicked(self, button):
        """
            call on_key_press_event
        """
        kmp = Gdk.Keymap.get_default()
        event = Gdk.Event()
        event.state = kmp.get_modifier_state()
        event.keyval = Gdk.KEY_a
        #event.put()
        self.on_key_press_event(None, event)

    def on_key_press_event(self, widget, event):
        """
            OK
        """
        if event.state == Gdk.ModifierType.CONTROL_MASK:
            self.set_title("Ctrl+{0}".format(chr(event.keyval)))
        else:
            self.set_title("{0}".format(chr(event.keyval)))

ButtonWin()
Gtk.main()

なんというアホな処理。
でもこれで Ctrl+Click でも同じハンドラという狙ったとおりになる。
実装する時はキチンと関数に分離しとこう。