Skip to content
Snippets Groups Projects
Commit a591e9e6 authored by Daniel Schulte's avatar Daniel Schulte Committed by Christopher Spinrath
Browse files

Added screenkey as an alternative to key-mon, etc

parent 7e5e2d8c
No related branches found
No related tags found
No related merge requests found
Showing
with 1442 additions and 0 deletions
.bzr/
Copyright (c) 2010 Pablo Seminario <pabluk@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
include screenkey README LICENSE
recursive-include data *
Screenkey v0.2
http://launchpad.net/screenkey
About
=====
Screencast your keys.
A screencast tool to display your keys inspired by Screenflick
and initially based on the key-mon project code.
Usage
=====
Download the latest version from https://launchpad.net/screenkey/+download
and you need install python-xlib.
To run without installing (change x.x by current version number)
tar xvfz screenkey-x.x.tar.gz
cd screenkey-x.x/
sudo ./screenkey
To install
tar xvfz screenkey-x.x.tar.gz
cd screenkey-x.x/
sudo ./setup.py install
Or you can use dpkg (Debian and Ubuntu)
sudo dpkg -i screenkey_x.x-y_all.deb
Author
======
Pablo Seminario <pabluk@gmail.com>
Thanks to
=========
Jacob Gardner
farrer
Ivan Makfinsky
Muneeb Shaikh
License
=======
Copyright (c) 2010 Pablo Seminario <pabluk@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
APP_NAME = "Screenkey"
APP_DESC = _("Screencast your keys")
APP_URL = 'http://launchpad.net/screenkey'
VERSION = '0.2'
AUTHOR = 'Pablo Seminario'
File added
# Copyright (c) 2010 Pablo Seminario <pabluk@gmail.com>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import threading
import time
import sys
import subprocess
import modmap
import gtk
from Xlib import X, XK, display
from Xlib.ext import record
from Xlib.protocol import rq
MODE_RAW = 0
MODE_NORMAL = 1
REPLACE_KEYS = {
'XK_Escape':_('Esc '),
'XK_Tab':u'\u21B9 ',
'XK_Return':u'\u23CE ',
'XK_Space':u' ',
'XK_Caps_Lock':_('Caps '),
'XK_F1':u'F1 ',
'XK_F2':u'F2 ',
'XK_F3':u'F3 ',
'XK_F4':u'F4 ',
'XK_F5':u'F5 ',
'XK_F6':u'F6 ',
'XK_F7':u'F7 ',
'XK_F8':u'F8 ',
'XK_F9':u'F9 ',
'XK_F10':u'F10 ',
'XK_F11':u'F11 ',
'XK_F12':u'F12 ',
'XK_Home':_('Home '),
'XK_Up':u'\u2191',
'XK_Page_Up':_('PgUp '),
'XK_Left':u'\u2190',
'XK_Right':u'\u2192',
'XK_End':_('End '),
'XK_Down':u'\u2193',
'XK_Next':_('PgDn '),
'XK_Insert':_('Ins '),
'XK_Delete':_('Del '),
'XK_KP_Home':u'(7)',
'XK_KP_Up':u'(8)',
'XK_KP_Prior':u'(9)',
'XK_KP_Left':u'(4)',
'XK_KP_Right':u'(6)',
'XK_KP_End':u'(1)',
'XK_KP_Down':u'(2)',
'XK_KP_Page_Down':u'(3)',
'XK_KP_Begin':u'(5)',
'XK_KP_Insert':u'(0)',
'XK_KP_Delete':u'(.)',
'XK_KP_Add':u'(+)',
'XK_KP_Subtract':u'(-)',
'XK_KP_Multiply':u'(*)',
'XK_KP_Divide':u'(/)',
'XK_Num_Lock':u'NumLock ',
'XK_KP_Enter':u'\u23CE ',
}
class ListenKbd(threading.Thread):
def __init__(self, label, logger, mode):
threading.Thread.__init__(self)
self.mode = mode
self.logger = logger
self.label = label
self.text = ""
self.command = None
self.shift = None
self.cmd_keys = {
'shift': False,
'ctrl': False,
'alt': False,
'capslock': False,
'meta': False,
'super':False
}
self.logger.debug("Thread created")
self.keymap = modmap.get_keymap_table()
self.modifiers = modmap.get_modifier_map()
self.local_dpy = display.Display()
self.record_dpy = display.Display()
if not self.record_dpy.has_extension("RECORD"):
self.logger.error("RECORD extension not found.")
print "RECORD extension not found"
sys.exit(1)
self.ctx = self.record_dpy.record_create_context(
0,
[record.AllClients],
[{
'core_requests': (0, 0),
'core_replies': (0, 0),
'ext_requests': (0, 0, 0, 0),
'ext_replies': (0, 0, 0, 0),
'delivered_events': (0, 0),
'device_events': (X.KeyPress, X.KeyRelease),
'errors': (0, 0),
'client_started': False,
'client_died': False,
}])
def run(self):
self.logger.debug("Thread started.")
self.record_dpy.record_enable_context(self.ctx, self.key_press)
def lookup_keysym(self, keysym):
for name in dir(XK):
if name[:3] == "XK_" and getattr(XK, name) == keysym:
return name[3:]
return ""
def replace_key(self, key, keysym):
for name in dir(XK):
if name[:3] == "XK_" and getattr(XK, name) == keysym:
if name in REPLACE_KEYS:
return REPLACE_KEYS[name]
def update_text(self, string=None):
gtk.gdk.threads_enter()
if not string is None:
self.text = "%s%s" % (self.label.get_text(), string)
self.label.set_text(self.text)
else:
self.label.set_text("")
gtk.gdk.threads_leave()
self.label.emit("text-changed")
def key_press(self, reply):
# FIXME:
# This is not the most efficient way to detect the
# use of sudo/gksudo but it works.
sudo_is_running = subprocess.call(['ps', '-C', 'sudo'],
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
if not sudo_is_running:
return
if reply.category != record.FromServer:
return
if reply.client_swapped:
self.logger.warning(
"* received swapped protocol data, cowardly ignored"
)
return
if not len(reply.data) or ord(reply.data[0]) < 2:
# not an event
return
data = reply.data
key = None
while len(data):
event, data = rq.EventField(None).parse_binary_value(data,
self.record_dpy.display, None, None)
if event.type in [X.KeyPress, X.KeyRelease]:
if self.mode == MODE_NORMAL:
key = self.key_normal_mode(event)
if self.mode == MODE_RAW:
key = self.key_raw_mode(event)
if not key:
return
self.update_text(key)
def key_normal_mode(self, event):
key = ''
mod = ''
keysym = self.local_dpy.keycode_to_keysym(event.detail, 0)
if event.detail in self.keymap:
key_normal, key_shift, key_dead, key_deadshift = \
self.keymap[event.detail]
self.logger.debug("Key %s(keycode) %s. Symbols %s" %
(event.detail,
event.type == X.KeyPress and "pressed" or "released",
self.keymap[event.detail])
)
else:
self.logger.debug('No mapping for scan_code %d' % event.detail)
return
# Alt key
if event.detail in self.modifiers['mod1']:
if event.type == X.KeyPress:
self.cmd_keys['alt'] = True
else:
self.cmd_keys['alt'] = False
return
# Meta key
# Fixme: it must use self.modifiers['mod5']
# but doesn't work
if event.detail == 108:
if event.type == X.KeyPress:
self.cmd_keys['meta'] = True
else:
self.cmd_keys['meta'] = False
return
# Super key
if event.detail in self.modifiers['mod4']:
if event.type == X.KeyPress:
self.cmd_keys['super'] = True
else:
self.cmd_keys['super'] = False
return
# Ctrl keys
elif event.detail in self.modifiers['control']:
if event.type == X.KeyPress:
self.cmd_keys['ctrl'] = True
else:
self.cmd_keys['ctrl'] = False
return
# Shift keys
elif event.detail in self.modifiers['shift']:
if event.type == X.KeyPress:
self.cmd_keys['shift'] = True
else:
self.cmd_keys['shift'] = False
return
# Capslock key
elif event.detail in self.modifiers['lock']:
if event.type == X.KeyPress:
if self.cmd_keys['capslock']:
self.cmd_keys['capslock'] = False
else:
self.cmd_keys['capslock'] = True
return
# Backspace key
elif event.detail == 22 and event.type == X.KeyPress:
gtk.gdk.threads_enter()
if len(self.label.get_text()) > 0:
self.label.set_text(
unicode(self.label.get_text(), 'utf-8')[:-1]
)
key = ""
gtk.gdk.threads_leave()
else:
gtk.gdk.threads_leave()
return
else:
if event.type == X.KeyPress:
key = key_normal
if self.cmd_keys['ctrl']:
mod = mod + _("Ctrl+")
if self.cmd_keys['alt']:
mod = mod + _("Alt+")
if self.cmd_keys['super']:
mod = mod + _("Super+")
if self.cmd_keys['shift']:
key = key_shift
if self.cmd_keys['capslock'] \
and ord(key_normal) in range(97,123):
key = key_shift
if self.cmd_keys['meta']:
key = key_dead
if self.cmd_keys['shift'] and self.cmd_keys['meta']:
key = key_deadshift
string = self.replace_key(key, keysym)
if string:
key = string
if mod != '':
key = "%s%s " % (mod, key)
else:
key = "%s%s" % (mod, key)
else:
return
return key
def key_raw_mode(self, event):
key = ''
if event.type == X.KeyPress:
keysym = self.local_dpy.keycode_to_keysym(event.detail, 0)
key = self.lookup_keysym(keysym)
else:
return
return key
def stop(self):
self.local_dpy.record_disable_context(self.ctx)
self.local_dpy.flush()
self.record_dpy.record_free_context(self.ctx)
self.logger.debug("Thread stopped.")
File added
#!/usr/bin/env python
# Copyright (c) 2010 Pablo Seminario <pabluk@gmail.com>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import re
import subprocess
def cmd_keymap_table():
return subprocess.Popen(
['xmodmap','-pk'], stdout=subprocess.PIPE).communicate()[0]
def cmd_modifier_map():
return subprocess.Popen(
['xmodmap','-pm'], stdout=subprocess.PIPE).communicate()[0]
def get_keymap_table():
keymap = {}
keymap_table = cmd_keymap_table()
re_line = re.compile(r'0x\w+')
for line in keymap_table.split('\n')[1:]:
if len(line) > 0:
keycode = re.search(r'\s+(\d+).*', line)
if keycode:
new_keysyms = []
keycode = int(keycode.group(1))
keysyms = re_line.findall(line)
# When you press only one key
unicode_char = ''
try:
unicode_char = unichr(int(keysyms[0], 16))
except:
unicode_char = ''
if unicode_char == u'\x00':
unicode_char = ''
new_keysyms.append(unicode_char)
# When you press a key plus Shift key
unicode_char = ''
try:
unicode_char = unichr(int(keysyms[1], 16))
except:
unicode_char = ''
if unicode_char == u'\x00':
unicode_char = ''
new_keysyms.append(unicode_char)
# When you press a key plus meta (dead keys)
unicode_char = ''
try:
unicode_char = unichr(int(keysyms[4], 16))
except:
unicode_char = ''
if unicode_char == u'\x00':
unicode_char = ''
new_keysyms.append(unicode_char)
# When you press a key plus meta plus Shift key
unicode_char = ''
try:
unicode_char = unichr(int(keysyms[5], 16))
except:
unicode_char = ''
if unicode_char == u'\x00':
unicode_char = ''
new_keysyms.append(unicode_char)
#keymap[keycode-8] = new_keysyms
keymap[keycode] = new_keysyms
return keymap
def get_modifier_map():
modifiers = {}
modifier_map = cmd_modifier_map()
re_line = re.compile(r'(0x\w+)')
for line in modifier_map.split('\n')[1:]:
if len(line) > 0:
mod_name = re.match(r'(\w+).*', line)
if mod_name:
mod_name = mod_name.group(1)
keycodes = re_line.findall(line)
# Convert key codes from hex to dec for use them
# with the keymap table
keycodes =[ int(kc, 16) for kc in keycodes]
modifiers[mod_name] = keycodes
return modifiers
File added
# Copyright (c) 2010 Pablo Seminario <pabluk@gmail.com>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import pygtk
pygtk.require('2.0')
import gtk
import gobject
import glib
import cairo
import pango
import pickle
from threading import Timer
from Screenkey import APP_NAME, APP_DESC, APP_URL, VERSION, AUTHOR
from listenkbd import ListenKbd
POS_TOP = 0
POS_CENTER = 1
POS_BOTTOM = 2
SIZE_LARGE = 0
SIZE_MEDIUM = 1
SIZE_SMALL = 2
MODE_RAW = 0
MODE_NORMAL = 1
class Screenkey(gtk.Window):
POSITIONS = {
POS_TOP:_('Top'),
POS_CENTER:_('Center'),
POS_BOTTOM:_('Bottom'),
}
SIZES = {
SIZE_LARGE:_('Large'),
SIZE_MEDIUM:_('Medium'),
SIZE_SMALL:_('Small'),
}
MODES = {
MODE_RAW:_('Raw'),
MODE_NORMAL:_('Normal'),
}
STATE_FILE = os.path.join(glib.get_user_cache_dir(),
'screenkey.dat')
def __init__(self, logger, nodetach):
gtk.Window.__init__(self)
self.timer = None
self.logger = logger
default_options = {
'timeout': 2.5,
'position': POS_BOTTOM,
'size': SIZE_MEDIUM,
'opacity': 0.7,
'mode': MODE_NORMAL,
}
self.options = self.load_state()
for key, value in default_options.items():
if key not in self.options:
self.options[key] = value
if not nodetach:
self.logger.debug("Detach from the parent.")
self.drop_tty()
self.set_skip_taskbar_hint(True)
self.set_skip_pager_hint(True)
self.set_keep_above(True)
self.set_decorated(False)
self.stick()
self.set_property('accept-focus', False)
self.set_property('focus-on-map', False)
self.set_position(gtk.WIN_POS_CENTER)
self.bgcolor = gtk.gdk.color_parse("black")
self.modify_bg(gtk.STATE_NORMAL, self.bgcolor)
gobject.signal_new("text-changed", gtk.Label,
gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ())
self.label = gtk.Label()
self.label.set_justify(gtk.JUSTIFY_RIGHT)
self.label.set_ellipsize(pango.ELLIPSIZE_START)
self.label.connect("text-changed", self.on_label_change)
self.label.show()
self.add(self.label)
self.compositing = self.is_composited()
if self.compositing:
# Use cairo and rgba palette
self.set_app_paintable(True)
self.connect("screen_changed", self.on_screen_changed)
self.connect("expose_event", self.on_expose)
self.set_screen_colormap()
# XShape extension can be used otherwise, not implemented yet
self.screen_width = gtk.gdk.screen_width()
self.screen_height = gtk.gdk.screen_height()
self.set_window_size(self.options['size'])
self.set_gravity(gtk.gdk.GRAVITY_CENTER)
self.set_xy_position(self.options['position'])
self.listenkbd = ListenKbd(self.label, logger=self.logger,
mode=self.options['mode'])
self.listenkbd.start()
menu = gtk.Menu()
show_item = gtk.CheckMenuItem(_("Show keys"))
show_item.set_active(True)
show_item.connect("toggled", self.on_show_keys)
show_item.show()
menu.append(show_item)
preferences_item = gtk.ImageMenuItem(gtk.STOCK_PREFERENCES)
preferences_item.connect("activate", self.on_preferences_dialog)
preferences_item.show()
menu.append(preferences_item)
about_item = gtk.ImageMenuItem(gtk.STOCK_ABOUT)
about_item.connect("activate", self.on_about_dialog)
about_item.show()
menu.append(about_item)
separator_item = gtk.SeparatorMenuItem()
separator_item.show()
menu.append(separator_item)
image = gtk.ImageMenuItem(gtk.STOCK_QUIT)
image.connect("activate", self.quit)
image.show()
menu.append(image)
menu.show()
try:
import appindicator
self.systray = appindicator.Indicator(APP_NAME,
'indicator-messages',
appindicator.CATEGORY_APPLICATION_STATUS)
self.systray.set_status(appindicator.STATUS_ACTIVE)
self.systray.set_attention_icon("indicator-messages-new")
self.systray.set_icon(
"preferences-desktop-keyboard-shortcuts")
self.systray.set_menu(menu)
self.logger.debug("Using AppIndicator.")
except(ImportError):
self.systray = gtk.StatusIcon()
self.systray.set_from_icon_name(
"preferences-desktop-keyboard-shortcuts")
self.systray.connect("popup-menu",
self.on_statusicon_popup, menu)
self.logger.debug("Using StatusIcon.")
self.connect("delete-event", self.quit)
def quit(self, widget, data=None):
self.listenkbd.stop()
gtk.main_quit()
def load_state(self):
"""Load stored options"""
options = {}
try:
f = open(self.STATE_FILE, 'r')
try:
options = pickle.load(f)
self.logger.debug("Options loaded.")
except:
f.close()
except IOError:
self.logger.debug("file %s does not exists." %
self.STATE_FILE)
return options
def store_state(self, options):
"""Store options"""
try:
f = open(self.STATE_FILE, 'w')
try:
pickle.dump(options, f)
self.logger.debug("Options saved.")
except:
f.close()
except IOError:
self.logger.debug("Cannot open %s." % self.STATE_FILE)
def set_screen_colormap(self):
screen = self.get_screen()
rgba = screen.get_rgba_colormap()
if rgba is None:
self.set_colormap(screen.get_rgb_colormap())
self.compositing = False
else:
self.set_colormap(rgba)
self.compositing = True
def set_opacity(self, setting, region=None):
ctx = self.window.cairo_create()
if region:
ctx.region(region)
else:
ctx.paint()
ctx.set_operator(cairo.OPERATOR_SOURCE)
ctx.set_source_rgba(self.bgcolor.red_float,
self.bgcolor.green_float,
self.bgcolor.blue_float,
setting)
ctx.fill()
def set_window_size(self, setting):
"""Set window and label size."""
window_width = self.screen_width
window_height = -1
if setting == SIZE_LARGE:
window_height = 24 * self.screen_height / 100
if setting == SIZE_MEDIUM:
window_height = 12 * self.screen_height / 100
if setting == SIZE_SMALL:
window_height = 8 * self.screen_height / 100
attr = pango.AttrList()
attr.change(pango.AttrSize((
50 * window_height / 100) * 1000, 0, -1))
attr.change(pango.AttrFamily("Sans", 0, -1))
attr.change(pango.AttrWeight(pango.WEIGHT_BOLD, 0, -1))
attr.change(pango.AttrForeground(65535, 65535, 65535, 0, -1))
self.label.set_attributes(attr)
self.resize(window_width, window_height)
def set_xy_position(self, setting):
"""Set window position."""
window_width, window_height = self.get_size()
if setting == POS_TOP:
self.move(0, window_height * 2)
if setting == POS_CENTER:
self.move(0, self.screen_height / 2)
if setting == POS_BOTTOM:
self.move(0, self.screen_height - window_height * 2)
def on_statusicon_popup(self, widget, button, timestamp, data=None):
if button == 3:
if data:
data.show()
data.popup(None, None, gtk.status_icon_position_menu,
3, timestamp, widget)
def on_label_change(self, widget, data=None):
if not self.get_property('visible'):
gtk.gdk.threads_enter()
self.set_xy_position(self.options['position'])
self.stick()
self.show()
gtk.gdk.threads_leave()
if self.timer:
self.timer.cancel()
self.timer = Timer(self.options['timeout'], self.on_timeout)
self.timer.start()
def on_timeout(self):
gtk.gdk.threads_enter()
self.hide()
self.label.set_text("")
gtk.gdk.threads_leave()
def on_change_mode(self, mode):
self.listenkbd.stop()
self.listenkbd = ListenKbd(self.label, logger=self.logger,
mode=mode)
self.listenkbd.start()
def on_show_keys(self, widget, data=None):
if widget.get_active():
self.logger.debug("Screenkey enabled.")
self.listenkbd = ListenKbd(self.label, logger=self.logger,
mode=self.options['mode'])
self.listenkbd.start()
else:
self.logger.debug("Screenkey disabled.")
self.listenkbd.stop()
def on_screen_changed(self, widget, from_screen):
# Used only with compositing
self.set_screen_colormap()
def on_expose(self, widget, event):
# Used only with compositing
if not self.compositing:
return
self.set_opacity(self.options['opacity'], gtk.gdk.region_rectangle(event.area))
def on_preferences_dialog(self, widget, data=None):
prefs = gtk.Dialog(APP_NAME, None,
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE))
def on_sb_time_changed(widget, data=None):
self.options['timeout'] = widget.get_value()
self.logger.debug("Timeout value changed.")
def on_cbox_sizes_changed(widget, data=None):
index = widget.get_active()
if index >= 0:
self.options['size'] = index
self.set_window_size(self.options['size'])
self.logger.debug("Window size changed.")
def on_sb_opacity_changed(widget, data=None):
self.options['opacity'] = widget.get_value() / 100.0
self.logger.debug("Opacity value changed.")
def on_cbox_modes_changed(widget, data=None):
index = widget.get_active()
if index >= 0:
self.options['mode'] = index
self.on_change_mode(self.options['mode'])
self.logger.debug("Key mode changed.")
def on_cbox_changed(widget, data=None):
index = widget.get_active()
name = widget.get_name()
if index >= 0:
self.options[name] = index
self.logger.debug("Window position changed.")
frm_main = gtk.Frame(_("Preferences"))
frm_main.set_border_width(6)
vbox_main = gtk.VBox()
frm_time = gtk.Frame(_("<b>Time</b>"))
frm_time.set_border_width(4)
frm_time.get_label_widget().set_use_markup(True)
frm_time.set_shadow_type(gtk.SHADOW_NONE)
hbox_time = gtk.HBox()
lbl_time1 = gtk.Label(_("Display for"))
lbl_time2 = gtk.Label(_("seconds"))
sb_time = gtk.SpinButton(digits=1)
sb_time.set_increments(0.5, 1.0)
sb_time.set_range(0.5, 10.0)
sb_time.set_numeric(True)
sb_time.set_update_policy(gtk.UPDATE_IF_VALID)
sb_time.set_value(self.options['timeout'])
sb_time.connect("value-changed", on_sb_time_changed)
hbox_time.pack_start(lbl_time1, expand=False,
fill=False, padding=6)
hbox_time.pack_start(sb_time, expand=False,
fill=False, padding=4)
hbox_time.pack_start(lbl_time2, expand=False,
fill=False, padding=4)
frm_time.add(hbox_time)
frm_time.show_all()
frm_aspect = gtk.Frame(_("<b>Display</b>"))
frm_aspect.set_border_width(4)
frm_aspect.get_label_widget().set_use_markup(True)
frm_aspect.set_shadow_type(gtk.SHADOW_NONE)
vbox_aspect = gtk.VBox(spacing=6)
hbox1_aspect = gtk.HBox()
lbl_positions = gtk.Label(_("Position"))
cbox_positions = gtk.combo_box_new_text()
cbox_positions.set_name('position')
for key, value in self.POSITIONS.items():
cbox_positions.insert_text(key, value)
cbox_positions.set_active(self.options['position'])
cbox_positions.connect("changed", on_cbox_changed)
hbox1_aspect.pack_start(lbl_positions, expand=False,
fill=False, padding=6)
hbox1_aspect.pack_start(cbox_positions, expand=False,
fill=False, padding=4)
hbox2_aspect = gtk.HBox()
lbl_sizes = gtk.Label(_("Size"))
cbox_sizes = gtk.combo_box_new_text()
cbox_sizes.set_name('size')
for key, value in self.SIZES.items():
cbox_sizes.insert_text(key, value)
cbox_sizes.set_active(self.options['size'])
cbox_sizes.connect("changed", on_cbox_sizes_changed)
hbox2_aspect.pack_start(lbl_sizes, expand=False,
fill=False, padding=6)
hbox2_aspect.pack_start(cbox_sizes, expand=False,
fill=False, padding=4)
hbox3_aspect = gtk.HBox()
lbl_opacity1 = gtk.Label(_("Opacity"))
lbl_opacity2 = gtk.Label(_("%"))
sb_opacity = gtk.SpinButton(digits=1)
sb_opacity.set_increments(10, 25)
sb_opacity.set_range(0, 100)
sb_opacity.set_numeric(True)
sb_opacity.set_update_policy(gtk.UPDATE_IF_VALID)
sb_opacity.set_value(self.options['opacity'] * 100)
sb_opacity.connect("value-changed", on_sb_opacity_changed)
hbox3_aspect.pack_start(lbl_opacity1, expand=False,
fill=False, padding=6)
hbox3_aspect.pack_start(sb_opacity, expand=False,
fill=False, padding=4)
hbox3_aspect.pack_start(lbl_opacity2, expand=False,
fill=False, padding=4)
vbox_aspect.pack_start(hbox1_aspect)
vbox_aspect.pack_start(hbox2_aspect)
vbox_aspect.pack_start(hbox3_aspect)
frm_aspect.add(vbox_aspect)
frm_kbd = gtk.Frame(_("<b>Keys</b>"))
frm_kbd.set_border_width(4)
frm_kbd.get_label_widget().set_use_markup(True)
frm_kbd.set_shadow_type(gtk.SHADOW_NONE)
hbox_kbd = gtk.HBox()
lbl_kbd = gtk.Label(_("Mode"))
cbox_modes = gtk.combo_box_new_text()
cbox_modes.set_name('mode')
for key, value in self.MODES.items():
cbox_modes.insert_text(key, value)
cbox_modes.set_active(self.options['mode'])
cbox_modes.connect("changed", on_cbox_modes_changed)
hbox_kbd.pack_start(lbl_kbd, expand=False,
fill=False, padding=6)
hbox_kbd.pack_start(cbox_modes, expand=False,
fill=False, padding=4)
frm_kbd.add(hbox_kbd)
vbox_main.pack_start(frm_time, False, False, 6)
vbox_main.pack_start(frm_aspect, False, False, 6)
vbox_main.pack_start(frm_kbd, False, False, 6)
frm_main.add(vbox_main)
prefs.vbox.pack_start(frm_main)
prefs.set_destroy_with_parent(True)
prefs.set_resizable(False)
prefs.set_has_separator(False)
prefs.set_default_response(gtk.RESPONSE_CLOSE)
prefs.vbox.show_all()
response = prefs.run()
if response:
self.store_state(self.options)
prefs.destroy()
def on_about_dialog(self, widget, data=None):
about = gtk.AboutDialog()
about.set_program_name(APP_NAME)
about.set_version(VERSION)
about.set_copyright(u"2010 \u00a9 %s" % AUTHOR)
about.set_comments(APP_DESC)
about.set_documenters(
[u"Jos\xe9 Mar\xeda Quiroga <pepelandia@gmail.com>"]
)
about.set_website(APP_URL)
about.set_icon_name('preferences-desktop-keyboard-shortcuts')
about.set_logo_icon_name(
'preferences-desktop-keyboard-shortcuts'
)
about.run()
about.destroy()
def drop_tty(self):
# We fork and setsid so that we drop the controlling
# tty.
if os.fork() != 0:
os._exit(0)
os.setsid()
File added
[Desktop Entry]
Encoding=UTF-8
Name=Screenkey
Comment=Screencast your keys
Version=0.2
Exec=screenkey
Terminal=false
Icon=preferences-desktop-keyboard-shortcuts
Type=Application
Categories=GNOME;Utility
screenkey
Screenkey/__init__.py
Screenkey/screenkey.py
Screenkey/listenkbd.py
Screenkey/modmap.py
# Spanish translations for screenkey-i package.
# Copyright (C) 2010 THE screenkey-i'S COPYRIGHT HOLDER
# This file is distributed under the same license as the screenkey-i package.
# Pablo Seminario <pabluk@gmail.com>, 2010.
#
msgid ""
msgstr ""
"Project-Id-Version: screenkey 0.2\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-06-15 16:22+0200\n"
"PO-Revision-Date: 2010-06-15 16:27+0200\n"
"Last-Translator: Pablo Seminario <pabluk@gmail.com>\n"
"Language-Team: Spanish\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: screenkey:36
msgid "do not detach from the parent"
msgstr ""
#: screenkey:38
msgid "show debug information"
msgstr "Muestra información de depuración"
#: Screenkey/__init__.py:3
msgid "Screencast your keys"
msgstr "Screencast tus teclas"
#: Screenkey/screenkey.py:42
msgid "Top"
msgstr "Superior"
#: Screenkey/screenkey.py:43
msgid "Center"
msgstr "Centro"
#: Screenkey/screenkey.py:44
msgid "Bottom"
msgstr "Inferior"
#: Screenkey/screenkey.py:47
msgid "Large"
msgstr "Grande"
#: Screenkey/screenkey.py:48
msgid "Medium"
msgstr "Mediano"
#: Screenkey/screenkey.py:49
msgid "Small"
msgstr "Pequeño"
#: Screenkey/screenkey.py:52
msgid "Raw"
msgstr "Crudo"
#: Screenkey/screenkey.py:53
msgid "Normal"
msgstr "Normal"
#: Screenkey/screenkey.py:113
msgid "Show keys"
msgstr "Mostar teclas"
#: Screenkey/screenkey.py:295
msgid "Preferences"
msgstr "Preferencias"
#: Screenkey/screenkey.py:299
msgid "<b>Time</b>"
msgstr "<b>Tiempo</b>"
#: Screenkey/screenkey.py:304
msgid "Display for"
msgstr "Mostrar durante"
#: Screenkey/screenkey.py:305
msgid "seconds"
msgstr "segundos"
#: Screenkey/screenkey.py:322
msgid "<b>Aspect</b>"
msgstr "<b>Aspecto</b>"
#: Screenkey/screenkey.py:330
msgid "Position"
msgstr "Posición"
#: Screenkey/screenkey.py:345
msgid "Size"
msgstr "Tamaño"
#: Screenkey/screenkey.py:362
msgid "<b>Keys</b>"
msgstr "<b>Teclas</b>"
#: Screenkey/screenkey.py:367
msgid "Mode"
msgstr "Modo"
# French translations for screenkey-i package.
# Copyright (C) 2010 THE screenkey-i'S COPYRIGHT HOLDER
# This file is distributed under the same license as the screenkey-i package.
# Pablo Seminario <pabluk@gmail.com>, 2010.
#
msgid ""
msgstr ""
"Project-Id-Version: screenkey 0.2\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-06-15 16:22+0200\n"
"PO-Revision-Date: 2010-06-15 16:34+0200\n"
"Last-Translator: Pablo Seminario <pabluk@gmail.com>\n"
"Language-Team: French\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: screenkey:36
msgid "do not detach from the parent"
msgstr ""
#: screenkey:38
msgid "show debug information"
msgstr ""
#: Screenkey/__init__.py:3
msgid "Screencast your keys"
msgstr ""
#: Screenkey/screenkey.py:42
msgid "Top"
msgstr ""
#: Screenkey/screenkey.py:43
msgid "Center"
msgstr "Centre"
#: Screenkey/screenkey.py:44
msgid "Bottom"
msgstr ""
#: Screenkey/screenkey.py:47
msgid "Large"
msgstr ""
#: Screenkey/screenkey.py:48
msgid "Medium"
msgstr ""
#: Screenkey/screenkey.py:49
msgid "Small"
msgstr ""
#: Screenkey/screenkey.py:52
msgid "Raw"
msgstr ""
#: Screenkey/screenkey.py:53
msgid "Normal"
msgstr ""
#: Screenkey/screenkey.py:113
msgid "Show keys"
msgstr ""
#: Screenkey/screenkey.py:295
msgid "Preferences"
msgstr "Préférences"
#: Screenkey/screenkey.py:299
msgid "<b>Time</b>"
msgstr ""
#: Screenkey/screenkey.py:304
msgid "Display for"
msgstr ""
#: Screenkey/screenkey.py:305
msgid "seconds"
msgstr ""
#: Screenkey/screenkey.py:322
msgid "<b>Aspect</b>"
msgstr ""
#: Screenkey/screenkey.py:330
msgid "Position"
msgstr "Position"
#: Screenkey/screenkey.py:345
msgid "Size"
msgstr "Taille"
#: Screenkey/screenkey.py:362
msgid "<b>Keys</b>"
msgstr ""
#: Screenkey/screenkey.py:367
msgid "Mode"
msgstr "Mode"
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-10-07 21:38+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
#: Screenkey/listenkbd.py:29
msgid "Esc "
msgstr ""
#: Screenkey/listenkbd.py:33
msgid "Caps "
msgstr ""
#: Screenkey/listenkbd.py:46
msgid "Home "
msgstr ""
#: Screenkey/listenkbd.py:48
msgid "PgUp "
msgstr ""
#: Screenkey/listenkbd.py:51
msgid "End "
msgstr ""
#: Screenkey/listenkbd.py:53
msgid "PgDn "
msgstr ""
#: Screenkey/listenkbd.py:54
msgid "Ins "
msgstr ""
#: Screenkey/listenkbd.py:55
msgid "Del "
msgstr ""
#: Screenkey/listenkbd.py:245
msgid "Ctrl+"
msgstr ""
#: Screenkey/listenkbd.py:247
msgid "Alt+"
msgstr ""
#: Screenkey/listenkbd.py:249
msgid "Super+"
msgstr ""
#: Screenkey/__init__.py:3
msgid "Screencast your keys"
msgstr ""
#: Screenkey/screenkey.py:42
msgid "Top"
msgstr ""
#: Screenkey/screenkey.py:43
msgid "Center"
msgstr ""
#: Screenkey/screenkey.py:44
msgid "Bottom"
msgstr ""
#: Screenkey/screenkey.py:47
msgid "Large"
msgstr ""
#: Screenkey/screenkey.py:48
msgid "Medium"
msgstr ""
#: Screenkey/screenkey.py:49
msgid "Small"
msgstr ""
#: Screenkey/screenkey.py:52
msgid "Raw"
msgstr ""
#: Screenkey/screenkey.py:53
msgid "Normal"
msgstr ""
#: Screenkey/screenkey.py:114
msgid "Show keys"
msgstr ""
#: Screenkey/screenkey.py:296
msgid "Preferences"
msgstr ""
#: Screenkey/screenkey.py:300
msgid "<b>Time</b>"
msgstr ""
#: Screenkey/screenkey.py:305
msgid "Display for"
msgstr ""
#: Screenkey/screenkey.py:306
msgid "seconds"
msgstr ""
#: Screenkey/screenkey.py:323
msgid "<b>Aspect</b>"
msgstr ""
#: Screenkey/screenkey.py:331
msgid "Position"
msgstr ""
#: Screenkey/screenkey.py:346
msgid "Size"
msgstr ""
#: Screenkey/screenkey.py:363
msgid "<b>Keys</b>"
msgstr ""
#: Screenkey/screenkey.py:368
msgid "Mode"
msgstr ""
#!/usr/bin/env python
# Copyright (c) 2010 Pablo Seminario <pabluk@gmail.com>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import logging
from optparse import OptionParser
import pygtk
pygtk.require('2.0')
import gtk
import gettext
import locale
locale.setlocale(locale.LC_ALL, '')
gettext.install('screenkey', unicode=True)
from Screenkey import APP_NAME, APP_DESC, VERSION
from Screenkey.screenkey import Screenkey
gtk.gdk.threads_init()
def Main():
parser = OptionParser(description=APP_DESC, version=VERSION)
parser.add_option("--no-detach", action="store_true",
dest="nodetach", default=False,
help=_("do not detach from the parent"))
parser.add_option("-d", "--debug", action="store_true",
dest="debug", default=False, help=_("show debug information"))
(options, args) = parser.parse_args()
if options.debug:
if options.nodetach:
# Send debug messages to standard output
logfile = None
else:
logfile = os.path.join(os.path.expanduser('~'),
'.screenkey.log')
username = os.environ.get('SUDO_USER')
if username:
homedir = os.path.expanduser('~%s' % username)
if homedir != '~%s' % username:
logfile = os.path.join(homedir, '.screenkey.log')
logging.basicConfig(filename=logfile, level=logging.DEBUG)
else:
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(APP_NAME)
s = Screenkey(logger=logger, nodetach=options.nodetach)
gtk.main()
if __name__ == "__main__":
Main()
#!/usr/bin/env python
from distutils.core import setup
try:
from DistUtilsExtra.command import *
except ImportError:
import sys
print >> sys.stderr, 'To build Screenkey you need install python-distutils-extra\n' \
'https://launchpad.net/python-distutils-extra'
sys.exit(1)
setup(
name = 'screenkey',
version = '0.2',
packages = ['Screenkey'],
package_dir = {'Screenkey': 'Screenkey'},
data_files = [('/usr/share/applications', ['data/screenkey.desktop'])],
scripts=['screenkey'],
author='Pablo Seminario',
author_email='pabluk@gmail.com',
platforms=['POSIX'],
license='GPLv3',
keywords='screencast keyboard keys',
url='http://launchpad.net/screenkey',
download_url='http://launchpad.net/screenkey/+download',
description='A screencast tool to display keys',
long_description="""
Screenkey is a useful tool for presentations or screencasts.
Inspired by ScreenFlick and initially based on the key-mon project code.
""",
cmdclass = {
"build" : build_extra.build_extra,
"build_i18n" : build_i18n.build_i18n,
}
)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment