1

I had some code written in python3 using GTK3. The program waited for some inputs from the keyboard. For instance, if I pressed 'q' the program printed a specific symbol, etc. This code looks like

 keyname = Gdk.keyval_name(event.keyval)
 if keyname == 'q':
        self.textbuffer.insert_at_cursor('you've pressed q')

I want to execute a callback function, when the program captures a specific string, e.g. when I press say, 'q' and 'w' in parallel (I press 'w' without leaving the key 'q') then, the program executes a specific function. I didn't find something in GTK3, except a method called Gdk.utf8_to_string_target(event.string) but I did not manage to use it correctly. For pressing two characters such as ctrl and 'h' it's easy by using something like

ctrl = (event.state & Gdk.ModifierType.CONTROL_MASK)
if ctrl and event.keyval == Gdk.KEY_h:
        self.textbuffer.insert_at_cursor('\n') 

I checked a seemingly similar question Detect specific keypresses in GUI, but was asking about checking if a special key is pressed. Which is not my case. As a minimal code we provide the following.

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import  Gtk, Gdk

class MyWindow(Gtk.Window):
    def __init__(self):

        Gtk.Window.__init__(self, title="awesome gui")
        self.set_resizable(True)
        self.set_default_size(700,550)
        self.grid = Gtk.Grid()
        self.add(self.grid)                        
        self.create_textview()
        self.create_buttons()

    def create_textview(self):

        scrolledwindow = Gtk.ScrolledWindow()
        scrolledwindow.set_hexpand(True)
        scrolledwindow.set_vexpand(True)
        self.grid.attach(scrolledwindow, 0, 1, 50, 1)
        self.textview = Gtk.TextView()
        scrolledwindow.add(self.textview)
        self.textbuffer = self.textview.get_buffer()
        self.textview.set_editable(False)
        self.textview.set_cursor_visible(False)

    def create_buttons(self):
        self.button1 = Gtk.Button(label="Clear text")   
        self.button1.connect("clicked", self.on_button1_clicked)
        self.grid.attach(self.button1, 0,  0, 1, 1)      
        self.button2 = Gtk.Button(label="Start capturing")
        self.button2.connect("key-release-event", self.on_key_release) 
        self.grid.attach_next_to(self.button2,self.button1,\
        Gtk.PositionType.RIGHT, 1, 1)  

    def on_button1_clicked(self, widget):
        self.textbuffer.set_text('')

    def on_key_release(self, widget, event, data=None):
        keyval = event.keyval       
        keyname = Gdk.keyval_name(keyval)
        ctrl = (event.state & Gdk.ModifierType.CONTROL_MASK)

        if keyval == Gdk.KEY_space: 
            self.textbuffer.insert_at_cursor(' ') #space

        if keyname == 'q':
            self.textbuffer.insert_at_cursor('you pressed q')

       # etc..

        if ctrl and keyval == Gdk.KEY_h:
            self.textbuffer.insert_at_cursor('\n') #change line when ctrl + h is pressed

win = MyWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()

My question is, If I can have something like

#you press q and after w or w and after q or the same time you press q and w
if keyname == 'qw': 
    self.textbuffer.insert_at_cursor('you pressed qw')

Any ideas? Please, if it is possible provide some code to prove your point!

111
  • 133
  • 6

3 Answers3

1

there is a function(in gtk) which is something similar to your needs..

https://developer.gnome.org/gtk3/stable/gtk3-Keyboard-Accelerators.html#gtk-accel-group-connect

it connects a key and a key-mod (https://github.com/bstpierre/gtk-examples/blob/master/c/accel.c)

if you really want to capture a string then you could try recreating the function given in gtk_accel_group

the source can be found in git (this is the c-source code https://github.com/GNOME/gtk/blob/master/gtk/gtkaccelgroup.c)

Siva Guru
  • 694
  • 4
  • 12
1

You have to create your personal "buffer" that will "buffer" the keystrokes and check, in every step-keystroke, if these keystrokes meet wanted criteria. Remember to empty the buffer if criteria not meet...

Also mind that your code does not return the unicode characters. So be prepared to loose some audience...

To get the unicode char you must use chr(Gdk.keyval_to_unicode(event.keyval)).

ilias iliadis
  • 601
  • 8
  • 15
0

Accelerator might be a nicer solution but keeping track of keys pressed and released may be closer to what you need.

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import  Gtk, Gdk

class MyWindow(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self, title="awesome gui")
        self.set_resizable(True)
        self.set_default_size(700,550)
        self.grid = Gtk.Grid()
        self.add(self.grid)                        
        self.create_textview()
        self.create_buttons()
        self.buffer = []

    def create_textview(self):
        scrolledwindow = Gtk.ScrolledWindow()
        scrolledwindow.set_hexpand(True)
        scrolledwindow.set_vexpand(True)
        self.grid.attach(scrolledwindow, 0, 1, 50, 1)
        self.textview = Gtk.TextView()
        scrolledwindow.add(self.textview)
        self.textbuffer = self.textview.get_buffer()
        self.textview.set_editable(False)
        self.textview.set_cursor_visible(False)

    def create_buttons(self):
        self.button1 = Gtk.Button(label="Clear text")   
        self.button1.connect("clicked", self.on_button1_clicked)
        self.grid.attach(self.button1, 0,  0, 1, 1)      
        self.button2 = Gtk.Button(label="Start capturing")
        self.button2.connect("key-release-event", self.on_key_release)
        self.button2.connect("key-press-event", self.on_key_down)
        self.grid.attach_next_to(self.button2,self.button1,\
        Gtk.PositionType.RIGHT, 1, 1)  

    def on_button1_clicked(self, widget):
        self.textbuffer.set_text('')

    def on_key_release(self, widget, event, data=None):
        keyval = event.keyval       
        keyname = Gdk.keyval_name(keyval)
        ctrl = (event.state & Gdk.ModifierType.CONTROL_MASK)
        if keyname in self.buffer:
            self.buffer.remove(keyname)
            if self.buffer:
                self.textbuffer.insert_at_cursor('you released '+'+'.join(self.buffer)+'\n')

    def on_key_down(self, widget, event, data=None):
        keyval = event.keyval       
        keyname = Gdk.keyval_name(keyval)
        if keyname in 'wqs' and keyname not in self.buffer:
            self.buffer.append(keyname)
            if self.buffer:
                self.textbuffer.insert_at_cursor('you pressed '+'+'.join(self.buffer)+'\n')

win = MyWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
pan-mroku
  • 803
  • 6
  • 17