Compare commits

..

68 Commits

Author SHA1 Message Date
ce2c4ed0f4 Update to 1.0.2. 2011-08-25 10:34:11 +09:00
099ca60975 Update doc comments. 2011-08-25 10:31:41 +09:00
43ab623fac Make sure that preferences dialog is kept above. 2011-08-25 07:11:50 +09:00
bcc9a8fd60 Swap ISO_Level3_Shift with Control_L in keyboard XML. 2011-08-25 07:11:40 +09:00
6fb96ea5d6 Fix crash in key replace logic. 2011-08-25 05:39:51 +09:00
2f64b3ee13 Fix doc comments. 2011-08-24 17:59:57 +09:00
d4a78e5dc7 Suppress compile warnings. 2011-08-24 17:44:31 +09:00
71033f5739 Update gtk-doc sections. 2011-08-24 17:43:55 +09:00
17444509fe Mark some files to be translated. 2011-08-24 17:43:12 +09:00
42baa22cdc Add doc comment for libeekboard. 2011-08-24 17:43:00 +09:00
f07de8cd3b Add a button to launch preferences dialog. 2011-08-24 17:05:52 +09:00
0772898b83 Improve icon rendering. 2011-08-24 17:05:41 +09:00
828b2d66d1 Save delay/interval as uint, instead of int. 2011-08-24 17:04:50 +09:00
8ab4fb7946 Implement preferences dialog. 2011-08-24 15:24:59 +09:00
e91a059f0f Ignore some files. 2011-08-24 11:10:28 +09:00
093d83ed89 Use AM_V_GEN for generating keysym-entries headers. 2011-08-24 11:03:46 +09:00
5c0381e4f0 Fix VAPIGEN macro. 2011-08-24 11:02:13 +09:00
657c6f8e35 Use GI instead of pygtk2 in mim2remap. 2011-08-24 11:01:33 +09:00
4bb984daf3 Rewrite simple-client in python. 2011-08-23 18:08:56 +09:00
e46a3f89ed Add theme option in gsettings. 2011-08-23 17:49:43 +09:00
6843cd62dd Fix vala binding. 2011-08-23 17:10:39 +09:00
52ffc77fdd Fix make distcheck. 2011-08-23 17:10:17 +09:00
158542ec0a Replace eekboard-xml and eekboard-inscript with eekxml and mim2remap. 2011-08-23 16:29:10 +09:00
360da8a3c9 Update vala binding. 2011-08-23 14:17:07 +09:00
65d1186317 Update python binding. 2011-08-23 10:27:29 +09:00
b7b4d68a9a Fix fullscreen mode and D-Bus service entry. 2011-08-22 22:24:17 +09:00
952f70b433 Fix typo. 2011-08-22 18:05:25 +09:00
74de8e5056 Fix clutter build. 2011-08-22 16:17:58 +09:00
9d88c1c5da Fix memleaks; add doc comments. 2011-08-22 16:12:23 +09:00
a6bde78168 Highlight locked modifiers. 2011-08-22 14:44:46 +09:00
bb85885e5d Revamp server-client API. 2011-08-20 13:17:16 +09:00
dd085be73d Fix GTK2 build. 2011-08-19 07:56:25 +09:00
f576310cdf Update keyboards. 2011-08-19 07:52:46 +09:00
70e1c98987 Rescale jp-kana.xml. 2011-08-18 18:34:59 +09:00
4f03aa82fe Rename kana.xml -> jp-kana.xml. 2011-08-18 18:29:24 +09:00
383c93a415 Fix fit-size calculation. 2011-08-18 18:06:52 +09:00
860fbe8ede Add kana keyboard. 2011-08-18 17:19:38 +09:00
39900bd987 Allow non-keysym symbols in XML. 2011-08-18 17:02:39 +09:00
5c09147551 Optimize container element traversal. 2011-08-18 17:01:48 +09:00
f0929a9bd8 Add Thai keyboard. 2011-08-18 15:23:57 +09:00
786496b3c4 Fix system (xklavier) layout handling. 2011-08-18 14:32:53 +09:00
e5f5c8273e Make GTK3 default. 2011-08-18 14:25:40 +09:00
ca250699ef Remove --model/layouts/options from eekboard-xml. 2011-08-18 12:48:32 +09:00
7f41af3ee7 Change xkb: keyboard type format.
It is now "MODEL/L0(V0);L1(V1);...;Ln(Vn)/O0;O1;...;On".
2011-08-18 12:47:38 +09:00
260dc3fddd Fix example/simple-client. 2011-08-18 12:16:39 +09:00
052c40cc26 Remove serialization code for EekKey, EekSection, and EekKeyboard. 2011-08-18 12:00:54 +09:00
1b5bab9c18 Add eek_init(). 2011-08-18 11:53:44 +09:00
6a7b256676 Remove unnecessary null initialization. 2011-08-18 11:31:01 +09:00
0e135129e2 Read keyboard type from GSettings. 2011-08-18 11:18:55 +09:00
7af6bf13ed Support feedback sounds. 2011-08-18 11:18:27 +09:00
91ed49b65a Make server responsible for loading keyboard files. 2011-08-17 18:19:36 +09:00
84f614528f Use GList instead of GSList in eek-container. 2011-08-17 13:23:19 +09:00
7c0e29fc86 Allow both -l and -d to be given to eekboard-xml. 2011-08-17 13:21:49 +09:00
1f9e4bd576 Fix dock support. 2011-08-16 18:03:20 +09:00
fc0a577dfb Suggest to use ibus focus-listener rather than atspi. 2011-08-16 17:34:15 +09:00
69d16ddce5 Use org.freedesktop.IBus.Panel.Focus{In,Out} instead of InputContext. 2011-08-16 17:24:07 +09:00
984813b154 Adjust the default values of key-repeat options.
Also make "auto-hide-delay" type integer rather than double.
2011-08-16 16:30:17 +09:00
b6beeedc26 Improve key-repeat behavior. 2011-08-16 16:30:13 +09:00
55f7a0d0dc Make sure large key does not overlap with the small key. 2011-08-15 18:13:55 +09:00
7919cc191e Capture motion-notify event. 2011-08-15 18:10:57 +09:00
db0c5088b7 Apply active style to the key under the large key. 2011-08-15 17:49:02 +09:00
cc4b9a6b45 Add cursor keys to us-qwerty map. 2011-08-15 17:25:22 +09:00
f4e33a4ad4 Make sure that large key bounds do not overflow the widget allocation. 2011-08-15 16:45:11 +09:00
0e0fe9ed51 Support key repeat. 2011-08-15 15:18:52 +09:00
20c1f8cbe3 Update to 1.0.1. 2011-08-15 12:50:02 +09:00
f2ee3b4966 Add auto-hide-delay option.
Also fixes GSettings unref in client-main.c.
2011-08-15 12:17:07 +09:00
57a072746e Release dragged key when unmap. 2011-08-15 12:16:44 +09:00
497f21a5bd Remove unused local var. 2011-08-12 16:44:05 +09:00
108 changed files with 7968 additions and 4732 deletions

8
.gitignore vendored
View File

@ -4,6 +4,7 @@
*.o
*.so
*~
*.pyc
Makefile
Makefile.in
.deps
@ -41,12 +42,12 @@ eek/*.typelib
eekboard/*.pc
eekboard/*.gir
eekboard/*.typelib
eekboard/eekboard-marshalers.[ch]
tests/eek-simple-test
tests/eek-xkb-test
tests/eek-xml-test
src/eekboard
src/eekboard-server
src/eekboard-xml
docs/reference/eek/*.stamp
docs/reference/eek/*.txt
docs/reference/eek/eek.types
@ -76,7 +77,8 @@ po/.intltool-merge-cache
bindings/vala/*.vapi
py-compile
data/org.fedorahosted.eekboard.gschema.xml
data/org.fedorahosted.eekboard.gschema.valid
data/eekboard-server.service
data/*.desktop
examples/eekboard-inscript/eekboard-inscript
examples/simple-client/simple-client
examples/eekxml/eekxml

57
README
View File

@ -3,12 +3,12 @@ eekboard - an easy to use virtual keyboard toolkit -*- outline -*-
eekboard is a virtual keyboard software package, including a set of
tools to implement desktop virtual keyboards.
* How to build
* Building
** Dependencies
REQUIRED: GLib2, GTK, PangoCairo, libxklavier, libcroco
OPTIONAL: libXtst, at-spi2-core, IBus, Clutter, Clutter-Gtk, Python, Vala, gobject-introspection
OPTIONAL: libXtst, at-spi2-core, IBus, Clutter, Clutter-Gtk, Python, Vala, gobject-introspection, libcanberra
** Build from git repo
@ -24,55 +24,12 @@ OPTIONAL: libXtst, at-spi2-core, IBus, Clutter, Clutter-Gtk, Python, Vala, gobje
$ make
$ sudo make install
* Using command-line tools
eekboard currently includes 3 tools to implement your own virtual
keyboard.
** eekboard-server
eekboard-server is a D-Bus server which is responsible for drawing
interactive on-screen keyboards. Since it has a D-Bus service
activation entry, you will not need to start it manually, but you can
do that with:
$ eekboard-server &
** eekboard
eekboard is a client of eekboard-server. It listens desktop events
(keyboard change, focus in/out, and keystroke) and generates key
events when some keys are pressed on the on-screen keyboard. It can
be started with:
* Running
$ eekboard
$ eekboard -f # show/hide automatically based on focus-in/focus-out events
By default it renders current system keyboard layout. To read custom
keyboard layout, specify --keyboard option like:
Even though eekboard -f watches a11y events by default, it currently
works better with IBus. To use IBus, do:
$ eekboard --keyboard /usr/share/eekboard/keyboards/us-qwerty.xml
** eekboard-xml
eekboard-xml is a tool to manipulate XML keyboard description read by
eekboard if --keyboard option is specified.
To dump the current system keyboard layout into an XML file:
$ eekboard-xml --dump > keyboard.xml
You can display the dumped layout with:
$ eekboard-xml --load keyboard.xml
* Using library
eekboard currently includes two libraries. One is to access
eekboard-server via D-Bus and another is to manually render on-screen
keyboards.
For the former, see
file:docs/reference/eekboard/html/index.html
For the latter, see
See file:docs/reference/eek/html/index.html
$ gsettings set org.fedorahosted.eekboard focus-listener 'ibus'

View File

@ -17,5 +17,8 @@
pkgpython_PYTHON = \
__init__.py \
eekboard.py \
serializable.py \
symbol.py \
keysym.py \
client.py \
context.py

View File

@ -15,53 +15,8 @@
# along with this program. If not, see
# <http://www.gnu.org/licenses/>.
from gi.repository import Eek, EekXkl, Gio
from eekboard import Eekboard
from context import Context
Keyboard = Eek.Keyboard
Section = Eek.Section
Key = Eek.Key
Symbol = Eek.Symbol
Keysym = Eek.Keysym
SymbolMatrix = Eek.SymbolMatrix
MODIFIER_BEHAVIOR_NONE, \
MODIFIER_BEHAVIOR_LOCK, \
MODIFIER_BEHAVIOR_LATCH = \
(Eek.ModifierBehavior.NONE,
Eek.ModifierBehavior.LOCK,
Eek.ModifierBehavior.LATCH)
SymbolCategory = Eek.SymbolCategory
CSW = 640
CSH = 480
def XmlKeyboard(path, modifier_behavior=MODIFIER_BEHAVIOR_NONE):
_file = Gio.file_new_for_path(path)
layout = Eek.XmlLayout.new(_file.read())
keyboard = Eek.Keyboard.new(layout, CSW, CSH)
keyboard.set_modifier_behavior(modifier_behavior)
keyboard.set_alt_gr_mask(Eek.ModifierType.MOD5_MASK)
return keyboard
def XklKeyboard(modifier_behavior=MODIFIER_BEHAVIOR_NONE):
layout = EekXkl.Layout.new()
keyboard = Eek.Keyboard.new(layout, CSW, CSH)
keyboard.set_modifier_behavior(modifier_behavior)
return keyboard
__all__ = ['Eekboard',
'Context',
'Keyboard',
'Section',
'Key',
'Symbol',
'Keysym',
'MODIFIER_BEHAVIOR_NONE',
'MODIFIER_BEHAVIOR_LOCK',
'MODIFIER_BEHAVIOR_LATCH',
'XmlKeyboard',
'XklKeyboard']
from symbol import *
from keysym import *
from serializable import *
from client import *
from context import *

View File

@ -15,13 +15,15 @@
# along with this program. If not, see
# <http://www.gnu.org/licenses/>.
from gi.repository import Gio
import gi.repository
import dbus
import dbus.mainloop.glib
import gobject
from context import Context
class Eekboard(gobject.GObject):
__gtype_name__ = "PYEekboardEekboard"
dbus.mainloop.glib.DBusGMainLoop(set_as_default = True)
class Client(gobject.GObject):
__gtype_name__ = "PYEekboardClient"
__gsignals__ = {
'destroyed': (
gobject.SIGNAL_RUN_LAST,
@ -30,20 +32,25 @@ class Eekboard(gobject.GObject):
}
def __init__(self):
super(Eekboard, self).__init__()
self.__connection = Gio.bus_get_sync(Gio.BusType.SESSION, None)
self.__eekboard = gi.repository.Eekboard.Eekboard.new(self.__connection, None);
self.__eekboard.connect('destroyed', lambda *args: self.emit('destroyed'))
super(Client, self).__init__()
self.__bus = dbus.SessionBus()
_service = self.__bus.get_object("org.fedorahosted.Eekboard",
"/org/fedorahosted/Eekboard")
self.__service = dbus.Interface(_service, dbus_interface="org.fedorahosted.Eekboard")
self.__service.connect_to_signal("Destroyed", self.__destroyed_cb)
def __destroyed_cb(self):
self.emit("destroyed")
def create_context(self, client_name):
context = self.__eekboard.create_context(client_name, None)
return Context(context)
object_path = self.__service.CreateContext(client_name)
return Context(self.__bus, object_path)
def push_context(self, context):
self.__eekboard.push_context(context.get_giobject(), None)
self.__service.PushContext(context.object_path)
def pop_context(self):
self.__eekboard.pop_context(None)
self.__service.PopContext()
def destroy_context(self, context):
self.__eekboard.destroy_context(context.get_giobject(), None)
self.__service.DestroyContext(context.object_path)

View File

@ -15,8 +15,9 @@
# along with this program. If not, see
# <http://www.gnu.org/licenses/>.
from gi.repository import Eekboard
import dbus
import gobject
import serializable
class Context(gobject.GObject):
__gtype_name__ = "PYEekboardContext"
@ -32,11 +33,7 @@ class Context(gobject.GObject):
'key-pressed': (
gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE,
(gobject.TYPE_UINT,)),
'key-released': (
gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE,
(gobject.TYPE_UINT,)),
(gobject.TYPE_STRING, gobject.TYPE_PYOBJECT, gobject.TYPE_UINT)),
'destroyed': (
gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE,
@ -44,19 +41,59 @@ class Context(gobject.GObject):
}
__gproperties__ = {
'keyboard-visible': (bool, None, None, False, gobject.PARAM_READWRITE),
'visible': (gobject.TYPE_BOOLEAN, 'Visible', 'Visible',
False, gobject.PARAM_READWRITE),
'keyboard': (gobject.TYPE_UINT, 'Keyboard', 'Keyboard',
0, gobject.G_MAXUINT, 0, gobject.PARAM_READWRITE),
'group': (gobject.TYPE_UINT, 'Group', 'Group',
0, gobject.G_MAXUINT, 0, gobject.PARAM_READWRITE),
}
def __init__(self, giobject):
def __init__(self, bus, object_path):
super(Context, self).__init__()
self.__properties = dict()
self.__giobject = giobject
self.__giobject.connect('enabled', lambda *args: self.emit('enabled'))
self.__giobject.connect('disabled', lambda *args: self.emit('disabled'))
self.__giobject.connect('key-pressed', lambda *args: self.emit('key-pressed', args[1]))
self.__giobject.connect('key-released', lambda *args: self.emit('key-released', args[1]))
self.__giobject.connect('destroyed', lambda *args: self.emit('destroyed'))
self.__giobject.connect('notify::keyboard-visible', self.__notify_keyboard_visible_cb)
self.__bus = bus
self.__object_path = object_path
self.__properties = {}
_context = self.__bus.get_object("org.fedorahosted.Eekboard",
object_path)
self.__context = dbus.Interface(_context, dbus_interface="org.fedorahosted.Eekboard.Context")
self.__context.connect_to_signal('Enabled', self.__enabled_cb)
self.__context.connect_to_signal('Disabled', self.__disabled_cb)
self.__context.connect_to_signal('KeyPressed', self.__key_pressed_cb)
self.__context.connect_to_signal('Destroyed', self.__destroyed_cb)
self.__context.connect_to_signal('VisibilityChanged', self.__visibility_changed_cb)
self.__context.connect_to_signal('KeyboardChanged', self.__keyboard_changed_cb)
self.__context.connect_to_signal('GroupChanged', self.__group_changed_cb)
object_path = property(lambda self: self.__object_path)
def __enabled_cb(self):
self.emit('enabled')
def __disabled_cb(self):
self.emit('disabled')
def __key_pressed_cb(self, *args):
keyname = args[0]
symbol = serializable.deserialize_object(args[1])
modifiers = args[2]
self.emit('key-pressed', keyname, symbol, modifiers)
def __visibility_changed_cb(self, *args):
self.set_property('visible', args[0])
self.notify('visible')
def __keyboard_changed_cb(self, *args):
self.set_property('keyboard', args[0])
self.notify('keyboard')
def __group_changed_cb(self, *args):
self.set_property('group', args[0])
self.notify('group')
def __destroyed_cb(self):
self.emit("destroyed")
def do_set_property(self, pspec, value):
self.__properties[pspec.name] = value
@ -64,37 +101,26 @@ class Context(gobject.GObject):
def do_get_property(self, pspec):
return self.__properties[pspec.name]
def __notify_keyboard_visible_cb(self, *args):
self.set_property('keyboard-visible',
self.__giobject.get_property(args[1].name))
self.notify('keyboard-visible')
def get_giobject(self):
return self.__giobject
def add_keyboard(self, keyboard):
return self.__giobject.add_keyboard(keyboard, None)
def add_keyboard(self, keyboard_type):
return self.__context.AddKeyboard(keyboard_type)
def remove_keyboard(self, keyboard_id):
return self.__giobject.remove_keyboard(keyboard_id, None)
return self.__context.RemoveKeyboard(keyboard_id)
def set_keyboard(self, keyboard_id):
self.__giobject.set_keyboard(keyboard_id, None)
self.__context.SetKeyboard(keyboard_id)
def show_keyboard(self):
self.__giobject.show_keyboard(None)
self.__context.ShowKeyboard()
def hide_keyboard(self):
self.__giobject.hide_keyboard(None)
self.__context.HideKeyboard()
def set_group(self, group):
self.__giobject.set_group(group, None)
self.__context.SetGroup(group)
def press_key(self, keycode):
self.__giobject.press_key(keycode, None)
def press_keycode(self, keycode):
self.__context.PressKeycode(keycode)
def release_key(self, keycode):
self.__giobject.release_key(keycode, None)
def is_enabled(self):
return self.__giobject.is_enabled()
def release_keycode(self, keycode):
self.__context.ReleaseKeycode(keycode)

View File

@ -0,0 +1,35 @@
# Copyright (C) 2011 Daiki Ueno <ueno@unixuser.org>
# Copyright (C) 2011 Red Hat, Inc.
# 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 symbol
class Keysym(symbol.Symbol):
__gtype_name__ = "PYEekKeysym"
__NAME__ = "EekKeysym"
def __init__(self):
super(Keysym, self).__init__()
xkeysym = property(lambda self: self.xkeysym)
def serialize(self, struct):
super(Keysym, self).serialize(struct)
struct.append(dbus.UInt32(self.__xkeysym))
def deserialize(self, struct):
super(Keysym, self).deserialize(struct)
self.__xkeysym = struct.pop(0)

View File

@ -0,0 +1,76 @@
# vim:set et sts=4 sw=4:
#
# ibus - The Input Bus
#
# Copyright (c) 2007-2010 Peng Huang <shawn.p.huang@gmail.com>
# Copyright (c) 2007-2010 Red Hat, Inc.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this program; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
# Boston, MA 02111-1307 USA
__all__ = (
"Serializable",
"serialize_object",
"deserialize_object",
)
import dbus
import gobject
__serializable_name_dict = dict()
def serializable_register(classobj):
# if not issubclass(classobj, Serializable):
# raise "%s is not a sub-class of Serializable" % str(classobj)
__serializable_name_dict[classobj.__NAME__] = classobj
def serialize_object(o):
if isinstance(o, Serializable):
l = [o.__NAME__]
o.serialize(l)
return dbus.Struct(l)
else:
return o
def deserialize_object(v):
if isinstance(v, tuple):
struct = list(v)
type_name = struct.pop(0)
type_class = __serializable_name_dict[type_name]
o = type_class()
o.deserialize (struct)
return o
return v
class SerializableMeta(gobject.GObjectMeta):
def __init__(cls, name, bases, dict_):
super(SerializableMeta, cls).__init__(name, bases, dict_)
if "__NAME__" in cls.__dict__:
serializable_register(cls)
class Serializable(gobject.GObject):
__metaclass__ = SerializableMeta
__gtype_name__ = "PYEekSerializable"
__NAME__ = "EekSerializable"
def __init__(self):
super(Serializable, self).__init__()
def serialize(self, struct):
pass
def deserialize(self, struct):
pass
__serializable_name_dict["EekSerializable"] = Serializable

View File

@ -0,0 +1,47 @@
# Copyright (C) 2011 Daiki Ueno <ueno@unixuser.org>
# Copyright (C) 2011 Red Hat, Inc.
# 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 serializable
class Symbol(serializable.Serializable):
__gtype_name__ = "PYEekSymbol"
__NAME__ = "EekSymbol"
def __init__(self):
super(Symbol, self).__init__()
name = property(lambda self: self.__name)
label = property(lambda self: self.__label)
category = property(lambda self: self.__category)
modifier_mask = property(lambda self: self.__modifier_mask)
icon_name = property(lambda self: self.__icon_name)
def serialize(self, struct):
super(Symbol, self).serialize(struct)
struct.append(dbus.String(self.__name))
struct.append(dbus.String(self.__label))
struct.append(dbus.UInt32(self.__category))
struct.append(dbus.UInt32(self.__modifier_mask))
struct.append(dbus.String(self.__icon_name))
def deserialize(self, struct):
super(Symbol, self).deserialize(struct)
self.__name = struct.pop(0)
self.__label = struct.pop(0)
self.__category = struct.pop(0)
self.__modifier_mask = struct.pop(0)
self.__icon_name = struct.pop(0)

View File

@ -71,4 +71,4 @@ eekboard-$(EEK_API_VERSION).vapi:
# set up the verbosity rules to avoid some build noise
VAPIGEN_V = $(VAPIGEN_V_$(V))
VAPIGEN_V_ = $(VAPIGEN_V_$(AM_DEFAULT_VERBOSITY))
VAPIGEN_V_0 = @echo " VAPIG " $^;
VAPIGEN_V_0 = @echo " VAPIG " $@;

View File

@ -0,0 +1,2 @@
-DEEK_COMPILATION=1

View File

@ -15,6 +15,10 @@
<parameter name="user_data" type="gpointer"/>
</parameters>
</callback>
<struct name="EekModifierKey">
<field name="modifiers" type="EekModifierType"/>
<field name="key" type="EekKey*"/>
</struct>
<struct name="EekThemeClass">
</struct>
<struct name="EekThemeContext">
@ -500,6 +504,12 @@
<parameter name="fallback_level" type="gint"/>
</parameters>
</method>
<method name="is_locked" symbol="eek_key_is_locked">
<return-type type="gboolean"/>
<parameters>
<parameter name="key" type="EekKey*"/>
</parameters>
</method>
<method name="is_pressed" symbol="eek_key_is_pressed">
<return-type type="gboolean"/>
<parameters>
@ -540,6 +550,18 @@
<property name="oref" type="gulong" readable="1" writable="1" construct="0" construct-only="0"/>
<property name="row" type="gint" readable="1" writable="1" construct="0" construct-only="0"/>
<property name="symbol-matrix" type="EekSymbolMatrix*" readable="1" writable="1" construct="0" construct-only="0"/>
<signal name="cancelled" when="LAST">
<return-type type="void"/>
<parameters>
<parameter name="key" type="EekKey*"/>
</parameters>
</signal>
<signal name="locked" when="FIRST">
<return-type type="void"/>
<parameters>
<parameter name="key" type="EekKey*"/>
</parameters>
</signal>
<signal name="pressed" when="FIRST">
<return-type type="void"/>
<parameters>
@ -552,6 +574,12 @@
<parameter name="key" type="EekKey*"/>
</parameters>
</signal>
<signal name="unlocked" when="LAST">
<return-type type="void"/>
<parameters>
<parameter name="key" type="EekKey*"/>
</parameters>
</signal>
<vfunc name="get_index">
<return-type type="void"/>
<parameters>
@ -578,6 +606,12 @@
<parameter name="self" type="EekKey*"/>
</parameters>
</vfunc>
<vfunc name="is_locked">
<return-type type="gboolean"/>
<parameters>
<parameter name="self" type="EekKey*"/>
</parameters>
</vfunc>
<vfunc name="is_pressed">
<return-type type="gboolean"/>
<parameters>
@ -662,6 +696,12 @@
<parameter name="keyboard" type="EekKeyboard*"/>
</parameters>
</method>
<method name="get_locked_keys" symbol="eek_keyboard_get_locked_keys">
<return-type type="GList*"/>
<parameters>
<parameter name="keyboard" type="EekKeyboard*"/>
</parameters>
</method>
<method name="get_modifier_behavior" symbol="eek_keyboard_get_modifier_behavior">
<return-type type="EekModifierBehavior"/>
<parameters>
@ -687,6 +727,12 @@
<parameter name="oref" type="gulong"/>
</parameters>
</method>
<method name="get_pressed_keys" symbol="eek_keyboard_get_pressed_keys">
<return-type type="GList*"/>
<parameters>
<parameter name="keyboard" type="EekKeyboard*"/>
</parameters>
</method>
<method name="get_size" symbol="eek_keyboard_get_size">
<return-type type="void"/>
<parameters>
@ -747,6 +793,13 @@
<parameter name="modifier_behavior" type="EekModifierBehavior"/>
</parameters>
</method>
<method name="set_modifiers" symbol="eek_keyboard_set_modifiers">
<return-type type="void"/>
<parameters>
<parameter name="keyboard" type="EekKeyboard*"/>
<parameter name="modifiers" type="EekModifierType"/>
</parameters>
</method>
<method name="set_num_lock_mask" symbol="eek_keyboard_set_num_lock_mask">
<return-type type="void"/>
<parameters>
@ -772,6 +825,20 @@
</method>
<property name="layout" type="EekLayout*" readable="1" writable="1" construct="0" construct-only="1"/>
<property name="modifier-behavior" type="EekModifierBehavior" readable="1" writable="1" construct="0" construct-only="0"/>
<signal name="key-cancelled" when="LAST">
<return-type type="void"/>
<parameters>
<parameter name="self" type="EekKeyboard*"/>
<parameter name="key" type="EekKey*"/>
</parameters>
</signal>
<signal name="key-locked" when="LAST">
<return-type type="void"/>
<parameters>
<parameter name="self" type="EekKeyboard*"/>
<parameter name="key" type="EekKey*"/>
</parameters>
</signal>
<signal name="key-pressed" when="LAST">
<return-type type="void"/>
<parameters>
@ -786,6 +853,13 @@
<parameter name="key" type="EekKey*"/>
</parameters>
</signal>
<signal name="key-unlocked" when="LAST">
<return-type type="void"/>
<parameters>
<parameter name="self" type="EekKeyboard*"/>
<parameter name="key" type="EekKey*"/>
</parameters>
</signal>
<vfunc name="create_section">
<return-type type="EekSection*"/>
<parameters>
@ -896,6 +970,20 @@
</parameters>
</method>
<property name="angle" type="gint" readable="1" writable="1" construct="0" construct-only="0"/>
<signal name="key-cancelled" when="LAST">
<return-type type="void"/>
<parameters>
<parameter name="self" type="EekSection*"/>
<parameter name="key" type="EekKey*"/>
</parameters>
</signal>
<signal name="key-locked" when="LAST">
<return-type type="void"/>
<parameters>
<parameter name="self" type="EekSection*"/>
<parameter name="key" type="EekKey*"/>
</parameters>
</signal>
<signal name="key-pressed" when="LAST">
<return-type type="void"/>
<parameters>
@ -910,6 +998,13 @@
<parameter name="key" type="EekKey*"/>
</parameters>
</signal>
<signal name="key-unlocked" when="LAST">
<return-type type="void"/>
<parameters>
<parameter name="self" type="EekSection*"/>
<parameter name="key" type="EekKey*"/>
</parameters>
</signal>
<vfunc name="add_row">
<return-type type="void"/>
<parameters>

View File

@ -0,0 +1,2 @@
-DEEK_COMPILATION=1

View File

@ -0,0 +1,2 @@
-DEEK_COMPILATION=1

View File

@ -0,0 +1,2 @@
-DEEK_COMPILATION=1

View File

@ -37,7 +37,6 @@
<parameter name="keycodes" type="gchar*"/>
</parameters>
</method>
<!--
<method name="set_names" symbol="eek_xkb_layout_set_names">
<return-type type="gboolean"/>
<parameters>
@ -45,7 +44,6 @@
<parameter name="names" type="XkbComponentNamesRec*"/>
</parameters>
</method>
-->
<method name="set_names_full" symbol="eek_xkb_layout_set_names_full">
<return-type type="gboolean"/>
<parameters>

View File

@ -1 +1,2 @@
EekXkb cheader_filename="eek/eek-xkb.h"
eek_xkb_layout_set_names hidden="1"

View File

@ -0,0 +1,2 @@
-DEEK_COMPILATION=1

View File

@ -50,7 +50,6 @@
<constructor name="new" symbol="eek_xkl_layout_new">
<return-type type="EekLayout*"/>
</constructor>
<!--
<method name="set_config" symbol="eek_xkl_layout_set_config">
<return-type type="gboolean"/>
<parameters>
@ -58,7 +57,6 @@
<parameter name="config" type="XklConfigRec*"/>
</parameters>
</method>
-->
<method name="set_config_full" symbol="eek_xkl_layout_set_config_full">
<return-type type="gboolean"/>
<parameters>

View File

@ -1 +1,2 @@
EekXkl cheader_filename="eek/eek-xkl.h"
eek_xkl_layout_set_config hidden="1"

View File

@ -0,0 +1,2 @@
-DEEKBOARD_COMPILATION

View File

@ -1,6 +1,100 @@
<?xml version="1.0"?>
<api version="1.0">
<namespace name="Eekboard">
<function name="xkl_config_rec_from_string" symbol="eekboard_xkl_config_rec_from_string">
<return-type type="XklConfigRec*"/>
<parameters>
<parameter name="layouts" type="gchar*"/>
</parameters>
</function>
<function name="xkl_config_rec_to_string" symbol="eekboard_xkl_config_rec_to_string">
<return-type type="gchar*"/>
<parameters>
<parameter name="rec" type="XklConfigRec*"/>
</parameters>
</function>
<function name="xkl_list_layout_variants" symbol="eekboard_xkl_list_layout_variants">
<return-type type="GSList*"/>
<parameters>
<parameter name="registry" type="XklConfigRegistry*"/>
<parameter name="layout" type="gchar*"/>
</parameters>
</function>
<function name="xkl_list_layouts" symbol="eekboard_xkl_list_layouts">
<return-type type="GSList*"/>
<parameters>
<parameter name="registry" type="XklConfigRegistry*"/>
</parameters>
</function>
<function name="xkl_list_models" symbol="eekboard_xkl_list_models">
<return-type type="GSList*"/>
<parameters>
<parameter name="registry" type="XklConfigRegistry*"/>
</parameters>
</function>
<function name="xkl_list_option_groups" symbol="eekboard_xkl_list_option_groups">
<return-type type="GSList*"/>
<parameters>
<parameter name="registry" type="XklConfigRegistry*"/>
</parameters>
</function>
<function name="xkl_list_options" symbol="eekboard_xkl_list_options">
<return-type type="GSList*"/>
<parameters>
<parameter name="registry" type="XklConfigRegistry*"/>
<parameter name="group" type="gchar*"/>
</parameters>
</function>
<object name="EekboardClient" parent="GDBusProxy" type-name="EekboardClient" get-type="eekboard_client_get_type">
<implements>
<interface name="GInitable"/>
<interface name="GAsyncInitable"/>
</implements>
<method name="create_context" symbol="eekboard_client_create_context">
<return-type type="EekboardContext*"/>
<parameters>
<parameter name="eekboard" type="EekboardClient*"/>
<parameter name="client_name" type="gchar*"/>
<parameter name="cancellable" type="GCancellable*"/>
</parameters>
</method>
<method name="destroy_context" symbol="eekboard_client_destroy_context">
<return-type type="void"/>
<parameters>
<parameter name="eekboard" type="EekboardClient*"/>
<parameter name="context" type="EekboardContext*"/>
<parameter name="cancellable" type="GCancellable*"/>
</parameters>
</method>
<constructor name="new" symbol="eekboard_client_new">
<return-type type="EekboardClient*"/>
<parameters>
<parameter name="connection" type="GDBusConnection*"/>
<parameter name="cancellable" type="GCancellable*"/>
</parameters>
</constructor>
<method name="pop_context" symbol="eekboard_client_pop_context">
<return-type type="void"/>
<parameters>
<parameter name="eekboard" type="EekboardClient*"/>
<parameter name="cancellable" type="GCancellable*"/>
</parameters>
</method>
<method name="push_context" symbol="eekboard_client_push_context">
<return-type type="void"/>
<parameters>
<parameter name="eekboard" type="EekboardClient*"/>
<parameter name="context" type="EekboardContext*"/>
<parameter name="cancellable" type="GCancellable*"/>
</parameters>
</method>
<signal name="destroyed" when="LAST">
<return-type type="void"/>
<parameters>
<parameter name="self" type="EekboardClient*"/>
</parameters>
</signal>
</object>
<object name="EekboardContext" parent="GDBusProxy" type-name="EekboardContext" get-type="eekboard_context_get_type">
<implements>
<interface name="GInitable"/>
@ -10,7 +104,14 @@
<return-type type="guint"/>
<parameters>
<parameter name="context" type="EekboardContext*"/>
<parameter name="keyboard" type="EekKeyboard*"/>
<parameter name="keyboard" type="gchar*"/>
<parameter name="cancellable" type="GCancellable*"/>
</parameters>
</method>
<method name="get_group" symbol="eekboard_context_get_group">
<return-type type="gint"/>
<parameters>
<parameter name="context" type="EekboardContext*"/>
<parameter name="cancellable" type="GCancellable*"/>
</parameters>
</method>
@ -41,7 +142,7 @@
<parameter name="cancellable" type="GCancellable*"/>
</parameters>
</constructor>
<method name="press_key" symbol="eekboard_context_press_key">
<method name="press_keycode" symbol="eekboard_context_press_keycode">
<return-type type="void"/>
<parameters>
<parameter name="context" type="EekboardContext*"/>
@ -49,7 +150,7 @@
<parameter name="cancellable" type="GCancellable*"/>
</parameters>
</method>
<method name="release_key" symbol="eekboard_context_release_key">
<method name="release_keycode" symbol="eekboard_context_release_keycode">
<return-type type="void"/>
<parameters>
<parameter name="context" type="EekboardContext*"/>
@ -103,7 +204,7 @@
<parameter name="cancellable" type="GCancellable*"/>
</parameters>
</method>
<property name="keyboard-visible" type="gboolean" readable="1" writable="0" construct="0" construct-only="0"/>
<property name="visible" type="gboolean" readable="1" writable="0" construct="0" construct-only="0"/>
<signal name="destroyed" when="LAST">
<return-type type="void"/>
<parameters>
@ -126,69 +227,114 @@
<return-type type="void"/>
<parameters>
<parameter name="self" type="EekboardContext*"/>
<parameter name="keycode" type="guint"/>
</parameters>
</signal>
<signal name="key-released" when="LAST">
<return-type type="void"/>
<parameters>
<parameter name="self" type="EekboardContext*"/>
<parameter name="keycode" type="guint"/>
<parameter name="keyname" type="char*"/>
<parameter name="symbol" type="GObject*"/>
<parameter name="modifiers" type="guint"/>
</parameters>
</signal>
</object>
<object name="EekboardEekboard" parent="GDBusProxy" type-name="EekboardEekboard" get-type="eekboard_eekboard_get_type">
<implements>
<interface name="GInitable"/>
<interface name="GAsyncInitable"/>
</implements>
<method name="create_context" symbol="eekboard_eekboard_create_context">
<return-type type="EekboardContext*"/>
<parameters>
<parameter name="eekboard" type="EekboardEekboard*"/>
<parameter name="client_name" type="gchar*"/>
<parameter name="cancellable" type="GCancellable*"/>
</parameters>
</method>
<method name="destroy_context" symbol="eekboard_eekboard_destroy_context">
<object name="EekboardContextService" parent="GObject" type-name="EekboardContextService" get-type="eekboard_context_service_get_type">
<method name="disable" symbol="eekboard_context_service_disable">
<return-type type="void"/>
<parameters>
<parameter name="eekboard" type="EekboardEekboard*"/>
<parameter name="context" type="EekboardContext*"/>
<parameter name="cancellable" type="GCancellable*"/>
<parameter name="context" type="EekboardContextService*"/>
</parameters>
</method>
<constructor name="new" symbol="eekboard_eekboard_new">
<return-type type="EekboardEekboard*"/>
<method name="enable" symbol="eekboard_context_service_enable">
<return-type type="void"/>
<parameters>
<parameter name="context" type="EekboardContextService*"/>
</parameters>
</method>
<method name="get_client_name" symbol="eekboard_context_service_get_client_name">
<return-type type="gchar*"/>
<parameters>
<parameter name="context" type="EekboardContextService*"/>
</parameters>
</method>
<method name="get_fullscreen" symbol="eekboard_context_service_get_fullscreen">
<return-type type="gboolean"/>
<parameters>
<parameter name="context" type="EekboardContextService*"/>
</parameters>
</method>
<method name="get_keyboard" symbol="eekboard_context_service_get_keyboard">
<return-type type="EekKeyboard*"/>
<parameters>
<parameter name="context" type="EekboardContextService*"/>
</parameters>
</method>
<property name="client-name" type="char*" readable="1" writable="1" construct="0" construct-only="0"/>
<property name="connection" type="GDBusConnection*" readable="1" writable="1" construct="1" construct-only="0"/>
<property name="fullscreen" type="gboolean" readable="1" writable="1" construct="0" construct-only="0"/>
<property name="keyboard" type="EekKeyboard*" readable="1" writable="1" construct="0" construct-only="0"/>
<property name="object-path" type="char*" readable="1" writable="1" construct="1" construct-only="0"/>
<property name="visible" type="gboolean" readable="1" writable="1" construct="0" construct-only="0"/>
<signal name="disabled" when="LAST">
<return-type type="void"/>
<parameters>
<parameter name="self" type="EekboardContextService*"/>
</parameters>
</signal>
<signal name="enabled" when="LAST">
<return-type type="void"/>
<parameters>
<parameter name="self" type="EekboardContextService*"/>
</parameters>
</signal>
<vfunc name="create_keyboard">
<return-type type="EekKeyboard*"/>
<parameters>
<parameter name="self" type="EekboardContextService*"/>
<parameter name="keyboard_type" type="gchar*"/>
</parameters>
</vfunc>
<vfunc name="hide_keyboard">
<return-type type="void"/>
<parameters>
<parameter name="self" type="EekboardContextService*"/>
</parameters>
</vfunc>
<vfunc name="show_keyboard">
<return-type type="void"/>
<parameters>
<parameter name="self" type="EekboardContextService*"/>
</parameters>
</vfunc>
</object>
<object name="EekboardService" parent="GObject" type-name="EekboardService" get-type="eekboard_service_get_type">
<constructor name="new" symbol="eekboard_service_new">
<return-type type="EekboardService*"/>
<parameters>
<parameter name="object_path" type="gchar*"/>
<parameter name="connection" type="GDBusConnection*"/>
<parameter name="cancellable" type="GCancellable*"/>
</parameters>
</constructor>
<method name="pop_context" symbol="eekboard_eekboard_pop_context">
<return-type type="void"/>
<parameters>
<parameter name="eekboard" type="EekboardEekboard*"/>
<parameter name="cancellable" type="GCancellable*"/>
</parameters>
</method>
<method name="push_context" symbol="eekboard_eekboard_push_context">
<return-type type="void"/>
<parameters>
<parameter name="eekboard" type="EekboardEekboard*"/>
<parameter name="context" type="EekboardContext*"/>
<parameter name="cancellable" type="GCancellable*"/>
</parameters>
</method>
<property name="connection" type="GDBusConnection*" readable="1" writable="1" construct="1" construct-only="0"/>
<property name="object-path" type="char*" readable="1" writable="1" construct="1" construct-only="0"/>
<signal name="destroyed" when="LAST">
<return-type type="void"/>
<parameters>
<parameter name="self" type="EekboardEekboard*"/>
<parameter name="object" type="EekboardService*"/>
</parameters>
</signal>
<vfunc name="create_context">
<return-type type="EekboardContextService*"/>
<parameters>
<parameter name="self" type="EekboardService*"/>
<parameter name="client_name" type="gchar*"/>
<parameter name="object_path" type="gchar*"/>
</parameters>
</vfunc>
</object>
<constant name="EEKBOARD_CLIENT_H" type="int" value="1"/>
<constant name="EEKBOARD_CONTEXT_H" type="int" value="1"/>
<constant name="EEKBOARD_EEKBOARD_H" type="int" value="1"/>
<constant name="EEKBOARD_H" type="int" value="1"/>
<constant name="EEKBOARD_CONTEXT_SERVICE_H" type="int" value="1"/>
<constant name="EEKBOARD_CONTEXT_SERVICE_INTERFACE" type="char*" value="org.fedorahosted.Eekboard.Context"/>
<constant name="EEKBOARD_CONTEXT_SERVICE_PATH" type="char*" value="/org/fedorahosted/Eekboard/Context_%d"/>
<constant name="EEKBOARD_SERVICE_H" type="int" value="1"/>
<constant name="EEKBOARD_SERVICE_INTERFACE" type="char*" value="org.fedorahosted.Eekboard"/>
<constant name="EEKBOARD_SERVICE_PATH" type="char*" value="/org/fedorahosted/Eekboard"/>
<constant name="EEKBOARD_XKLUTIL_H" type="int" value="1"/>
</namespace>
</api>

View File

@ -20,7 +20,7 @@ AC_PREREQ(2.63)
dnl AC_CONFIG_SRCDIR([configure.ac])
AC_CONFIG_MACRO_DIR([m4])
AC_INIT([eekboard], [1.0.0], [ueno@unixuser.org])
AC_INIT([eekboard], [1.0.2], [ueno@unixuser.org])
dnl Init automake
AM_INIT_AUTOMAKE
@ -46,12 +46,12 @@ IT_PROG_INTLTOOL([0.35.0])
AC_MSG_CHECKING([which gtk+ version to compile against])
AC_ARG_WITH([gtk],
[AS_HELP_STRING([--with-gtk=2.0|3.0],[which gtk+ version to compile against (default: 2.0)])],
[AS_HELP_STRING([--with-gtk=2.0|3.0],[which gtk+ version to compile against (default: 3.0)])],
[case "$with_gtk" in
2.0|3.0) ;;
*) AC_MSG_ERROR([invalid gtk version specified]) ;;
esac],
[with_gtk=2.0])
[with_gtk=3.0])
AC_MSG_RESULT([$with_gtk])
case "$with_gtk" in
@ -130,7 +130,7 @@ AC_ARG_ENABLE(x-dock,
enable_x_dock=yes)
if test x$enable_x_dock = xyes; then
PKG_CHECK_MODULES([XDOCK], [x], , enable_x_dock=no)
PKG_CHECK_MODULES([XDOCK], [x11], , enable_x_dock=no)
if test x$enable_x_dock = xyes; then
AC_DEFINE([HAVE_XDOCK], [1], [Define if X dock is found])
fi
@ -288,6 +288,23 @@ if test x$enable_clutter = xyes; then
fi
AM_CONDITIONAL(ENABLE_CLUTTER_GTK, [test x$enable_clutter_gtk = xyes])
dnl libcanberra
AC_MSG_CHECKING([whether you enable libcanberra])
AC_ARG_ENABLE(libcanberra,
AS_HELP_STRING([--enable-libcanberra=no/yes],
[Enable clutter user interface default=no]),
enable_libcanberra=$enableval,
enable_libcanberra=yes)
if test x$enable_libcanberra = xyes; then
PKG_CHECK_MODULES([LIBCANBERRA], [libcanberra-gtk3], , enable_libcanberra=no)
if test x$enable_libcanberra = xyes; then
AC_DEFINE([HAVE_LIBCANBERRA], [1], [Define if libcanberra is found])
fi
fi
AM_CONDITIONAL(ENABLE_LIBCANBERRA, [test x$enable_libcanberra = xyes])
AC_MSG_RESULT($enable_libcanberra)
GTK_DOC_CHECK([1.14],[--flavour no-tmpl])
dnl define GETTEXT_* variables
@ -323,7 +340,7 @@ data/icons/scalable/Makefile
data/themes/Makefile
data/keyboards/Makefile
examples/Makefile
examples/eekboard-inscript/Makefile
examples/eekxml/Makefile
examples/simple-client/Makefile
eek/eek-${EEK_API_VERSION}.pc
eek/eek-clutter-${EEK_API_VERSION}.pc
@ -343,7 +360,10 @@ Build options:
Build Clutter UI $enable_clutter
Build Vala binding $enable_vala
Build Python binding $enable_python
Sound support $enable_libcanberra
Build document $enable_gtk_doc
Focus listeners $focus_listeners
Keystroke listeners $keystroke_listeners
])

View File

@ -2,5 +2,5 @@
Name=Eekboard
Exec=eekboard -f
Type=Application
AutostartCondition=GSettings org.gnome.desktop.a11y.applications screen-keyboard-enabled
#AutostartCondition=GSettings org.gnome.desktop.a11y.applications screen-keyboard-enabled
X-GNOME-AutoRestart=true

View File

@ -1,3 +1,3 @@
[D-BUS Service]
Name=org.fedorahosted.Eekboard.Server
Name=org.fedorahosted.Eekboard
Exec=@bindir@/eekboard-server

View File

@ -1,2 +1,2 @@
keyboarddir = $(pkgdatadir)/keyboards
dist_keyboard_DATA = us-qwerty.xml
dist_keyboard_DATA = us.xml th.xml jp-kana.xml

697
data/keyboards/jp-kana.xml Normal file
View File

@ -0,0 +1,697 @@
<?xml version="1.0"?>
<keyboard version="0.90">
<bounds>0.000000,0.000000,640.000000,296.585366</bounds>
<section name="LeftModifiers">
<bounds>16.000000,78.048780,94.000000,202.000000</bounds>
<angle>0</angle>
<row>
<columns>5</columns>
<orientation>0</orientation>
</row>
<row>
<columns>5</columns>
<orientation>0</orientation>
</row>
<row>
<columns>5</columns>
<orientation>0</orientation>
</row>
<key id="keycode61" name="TAB" column="1" row="0">
<bounds>4.000000,43.000000,80.000000,38.000000</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="65289">Tab</keysym>
<keysym keyval="65056">ISO_Left_Tab</keysym>
</symbols>
</key>
<key id="keycode56" name="CAPS" column="2" row="0">
<bounds>4.000000,83.000000,80.000000,38.000000</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="1">
<keysym keyval="65507">Control_L</keysym>
</symbols>
</key>
<key id="keycode57" name="LFSH" column="3" row="0">
<bounds>4.000000,122.000000,80.000000,38.000000</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="1">
<keysym keyval="65505">Shift_L</keysym>
</symbols>
</key>
<key id="keycode58" name="LCTL" column="4" row="0">
<bounds>4.000000,162.341463,57.000000,38.000000</bounds>
<oref>outline9</oref>
<symbols groups="1" levels="2">
<symbol label="⌨" icon="input-keyboard-symbolic">cycle-keyboard</symbol>
<symbol label="☺" icon="preferences-system-symbolic">preferences</symbol>
</symbols>
</key>
<key id="keycode60" name="BKSP" column="1" row="1">
<bounds>517.000000,44.000000,80.000000,38.000000</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="1">
<keysym keyval="65288">BackSpace</keysym>
</symbols>
</key>
<key id="keycode62" name="RTRN" column="1" row="1">
<bounds>517.000000,83.000000,80.000000,38.000000</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="1">
<keysym keyval="65293">Return</keysym>
</symbols>
</key>
<key id="keycode63" name="RTSH" column="2" row="1">
<bounds>517.000000,122.000000,80.000000,38.000000</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="1">
<keysym keyval="65506">Shift_R</keysym>
</symbols>
</key>
<key id="keycode65" name="keycode65" column="0" row="2">
<bounds>165.463415,162.341463,238.829268,37.463415</bounds>
<oref>outline14</oref>
<symbols groups="1" levels="1">
<keysym keyval="32">space</keysym>
</symbols>
</key>
<key id="keycode108" name="keycode108" column="1" row="2">
<bounds>407.414634,162.341463,48.390244,37.463415</bounds>
<oref>outline10</oref>
<symbols groups="1" levels="1">
<keysym keyval="65361">Left</keysym>
</symbols>
</key>
<key id="keycode134" name="keycode134" column="2" row="2">
<bounds>458.926829,162.341463,48.390244,37.463415</bounds>
<oref>outline10</oref>
<symbols groups="1" levels="1">
<keysym keyval="65362">Up</keysym>
</symbols>
</key>
<key id="keycode135" name="keycode135" column="3" row="2">
<bounds>508.878049,162.341463,48.390244,37.463415</bounds>
<oref>outline10</oref>
<symbols groups="1" levels="1">
<keysym keyval="65364">Down</keysym>
</symbols>
</key>
<key id="keycode105" name="keycode105" column="4" row="2">
<bounds>560.390244,162.341463,48.390244,37.463415</bounds>
<oref>outline10</oref>
<symbols groups="1" levels="1">
<keysym keyval="65363">Right</keysym>
</symbols>
</key>
</section>
<section name="Alpha">
<bounds>99.000000,16.000000,469.000000,202.000000</bounds>
<angle>0</angle>
<row>
<columns>5</columns>
<orientation>0</orientation>
</row>
<row>
<columns>5</columns>
<orientation>0</orientation>
</row>
<row>
<columns>5</columns>
<orientation>0</orientation>
</row>
<row>
<columns>5</columns>
<orientation>0</orientation>
</row>
<row>
<columns>5</columns>
<orientation>0</orientation>
</row>
<row>
<columns>5</columns>
<orientation>0</orientation>
</row>
<row>
<columns>5</columns>
<orientation>0</orientation>
</row>
<row>
<columns>5</columns>
<orientation>0</orientation>
</row>
<row>
<columns>5</columns>
<orientation>0</orientation>
</row>
<row>
<columns>5</columns>
<orientation>0</orientation>
</row>
<row>
<columns>5</columns>
<orientation>0</orientation>
</row>
<key id="keycode1" name="AE03" column="0" row="0">
<bounds>4.000000,4.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="2">
<keysym keyval="51" label="あ">3</keysym>
<keysym keyval="35" label="ぁ">numbersign</keysym>
<keysym keyval="51" label="ア">3</keysym>
<keysym keyval="35" label="ァ">numbersign</keysym>
</symbols>
</key>
<key id="keycode2" name="AD03" column="1" row="0">
<bounds>4.000000,43.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="2">
<keysym keyval="101" label="い">e</keysym>
<keysym keyval="69" label="ぃ">E</keysym>
<keysym keyval="101" label="イ">e</keysym>
<keysym keyval="69" label="ィ">E</keysym>
</symbols>
</key>
<key id="keycode3" name="AE04" column="2" row="0">
<bounds>4.000000,82.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="2">
<keysym keyval="52" label="う">4</keysym>
<keysym keyval="36" label="ぅ">dollar</keysym>
<keysym keyval="52" label="ウ">4</keysym>
<keysym keyval="36" label="ゥ">dollar</keysym>
</symbols>
</key>
<key id="keycode4" name="AE05" column="3" row="0">
<bounds>4.000000,121.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="2">
<keysym keyval="53" label="え">5</keysym>
<keysym keyval="37" label="ぇ">percent</keysym>
<keysym keyval="53" label="エ">5</keysym>
<keysym keyval="37" label="ェ">percent</keysym>
</symbols>
</key>
<key id="keycode5" name="AE06" column="4" row="0">
<bounds>4.000000,160.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="2">
<keysym keyval="54" label="お">6</keysym>
<keysym keyval="38" label="ぉ">ampersand</keysym>
<keysym keyval="54" label="オ">6</keysym>
<keysym keyval="38" label="ォ">ampersand</keysym>
</symbols>
</key>
<key id="keycode6" name="AE03" column="0" row="1">
<bounds>43.000000,4.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="116" label="か">t</keysym>
<keysym keyval="116" label="カ">t</keysym>
</symbols>
</key>
<key id="keycode7" name="AD03" column="1" row="1">
<bounds>43.000000,43.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="103" label="き">g</keysym>
<keysym keyval="103" label="キ">g</keysym>
</symbols>
</key>
<key id="keycode8" name="AE04" column="2" row="1">
<bounds>43.000000,82.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="104" label="く">h</keysym>
<keysym keyval="104" label="ク">h</keysym>
</symbols>
</key>
<key id="keycode9" name="AE05" column="3" row="1">
<bounds>43.000000,121.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="58" label="け">colon</keysym>
<keysym keyval="58" label="ケ">colon</keysym>
</symbols>
</key>
<key id="keycode10" name="AE06" column="4" row="1">
<bounds>43.000000,160.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="98" label="こ">b</keysym>
<keysym keyval="98" label="コ">b</keysym>
</symbols>
</key>
<key id="keycode11" name="AE03" column="0" row="2">
<bounds>82.000000,4.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="120" label="さ">x</keysym>
<keysym keyval="120" label="サ">x</keysym>
</symbols>
</key>
<key id="keycode12" name="AD03" column="1" row="2">
<bounds>82.000000,43.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="100" label="し">d</keysym>
<keysym keyval="100" label="シ">d</keysym>
</symbols>
</key>
<key id="keycode13" name="AE04" column="2" row="0">
<bounds>82.000000,82.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="114" label="す">r</keysym>
<keysym keyval="114" label="ス">r</keysym>
</symbols>
</key>
<key id="keycode14" name="AE05" column="3" row="2">
<bounds>82.000000,121.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="112" label="せ">p</keysym>
<keysym keyval="112" label="セ">p</keysym>
</symbols>
</key>
<key id="keycode15" name="AE06" column="4" row="2">
<bounds>82.000000,160.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="99" label="そ">c</keysym>
<keysym keyval="99" label="ソ">c</keysym>
</symbols>
</key>
<key id="keycode16" name="AE03" column="0" row="3">
<bounds>121.000000,4.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="113" label="た">q</keysym>
<keysym keyval="113" label="タ">q</keysym>
</symbols>
</key>
<key id="keycode17" name="AD03" column="1" row="3">
<bounds>121.000000,43.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="97" label="ち">a</keysym>
<keysym keyval="97" label="チ">a</keysym>
</symbols>
</key>
<key id="keycode18" name="AE04" column="2" row="3">
<bounds>121.000000,82.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="2">
<keysym keyval="122" label="つ">z</keysym>
<keysym keyval="90" label="っ">Z</keysym>
<keysym keyval="122" label="ツ">z</keysym>
<keysym keyval="90" label="ッ">Z</keysym>
</symbols>
</key>
<key id="keycode19" name="AE05" column="3" row="3">
<bounds>121.000000,121.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="119" label="て">w</keysym>
<keysym keyval="119" label="テ">w</keysym>
</symbols>
</key>
<key id="keycode20" name="AE06" column="4" row="3">
<bounds>121.000000,160.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="115" label="と">s</keysym>
<keysym keyval="115" label="ト">s</keysym>
</symbols>
</key>
<key id="keycode21" name="AE03" column="0" row="4">
<bounds>160.000000,4.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="117" label="な">u</keysym>
<keysym keyval="117" label="ナ">u</keysym>
</symbols>
</key>
<key id="keycode22" name="AD03" column="1" row="4">
<bounds>160.000000,43.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="105" label="に">i</keysym>
<keysym keyval="105" label="ニ">i</keysym>
</symbols>
</key>
<key id="keycode23" name="AE04" column="2" row="4">
<bounds>160.000000,82.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="33" label="ぬ">exclam</keysym>
<keysym keyval="33" label="ヌ">exclam</keysym>
</symbols>
</key>
<key id="keycode24" name="AE05" column="3" row="4">
<bounds>160.000000,121.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="44" label="ね">comma</keysym>
<keysym keyval="44" label="ネ">comma</keysym>
</symbols>
</key>
<key id="keycode25" name="AE06" column="4" row="4">
<bounds>160.000000,160.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="107" label="の">k</keysym>
<keysym keyval="107" label="">k</keysym>
</symbols>
</key>
<key id="keycode26" name="AE03" column="0" row="5">
<bounds>199.000000,4.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="102" label="は">f</keysym>
<keysym keyval="102" label="ハ">f</keysym>
</symbols>
</key>
<key id="keycode27" name="AD03" column="1" row="5">
<bounds>199.000000,43.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="118" label="ひ">v</keysym>
<keysym keyval="118" label="ヒ">v</keysym>
</symbols>
</key>
<key id="keycode28" name="AE04" column="2" row="5">
<bounds>199.000000,82.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="34" label="ふ">quotedbl</keysym>
<keysym keyval="34" label="フ">quotedbl</keysym>
</symbols>
</key>
<key id="keycode29" name="AE05" column="3" row="5">
<bounds>199.000000,121.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="94" label="へ">asciicircum</keysym>
<keysym keyval="94" label="ヘ">asciicircum</keysym>
</symbols>
</key>
<key id="keycode30" name="AE06" column="4" row="5">
<bounds>199.000000,160.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="61" label="ほ">equal</keysym>
<keysym keyval="61" label="ホ">equal</keysym>
</symbols>
</key>
<key id="keycode31" name="AE03" column="0" row="6">
<bounds>238.000000,4.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="106" label="ま">j</keysym>
<keysym keyval="106" label="マ">j</keysym>
</symbols>
</key>
<key id="keycode32" name="AD03" column="1" row="6">
<bounds>238.000000,43.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="110" label="み">n</keysym>
<keysym keyval="110" label="ミ">n</keysym>
</symbols>
</key>
<key id="keycode33" name="AE04" column="2" row="6">
<bounds>238.000000,82.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="93" label="む">bracketright</keysym>
<keysym keyval="93" label="ム">bracketright</keysym>
</symbols>
</key>
<key id="keycode34" name="AE05" column="3" row="6">
<bounds>238.000000,121.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="47" label="め">slash</keysym>
<keysym keyval="47" label="メ">slash</keysym>
</symbols>
</key>
<key id="keycode35" name="AE06" column="4" row="6">
<bounds>238.000000,160.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="109" label="も">m</keysym>
<keysym keyval="109" label="モ">m</keysym>
</symbols>
</key>
<key id="keycode36" name="AE03" column="0" row="7">
<bounds>277.000000,4.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="2">
<keysym keyval="55" label="や">7</keysym>
<keysym keyval="39" label="ゃ">quoteright</keysym>
<keysym keyval="55" label="ヤ">7</keysym>
<keysym keyval="39" label="ャ">quoteright</keysym>
</symbols>
</key>
<key id="keycode37" name="AD03" column="1" row="7">
<bounds>277.000000,43.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="2">
<keysym keyval="56" label="ゆ">8</keysym>
<keysym keyval="40" label="ゅ">parenleft</keysym>
<keysym keyval="56" label="ユ">8</keysym>
<keysym keyval="40" label="ュ">parenleft</keysym>
</symbols>
</key>
<key id="keycode38" name="AE04" column="2" row="7">
<bounds>277.000000,82.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="2">
<keysym keyval="57" label="よ">9</keysym>
<keysym keyval="41" label="ょ">parenright</keysym>
<keysym keyval="57" label="ヨ">9</keysym>
<keysym keyval="41" label="ョ">parenright</keysym>
</symbols>
</key>
<key id="keycode41" name="AE03" column="0" row="8">
<bounds>316.000000,4.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="111" label="ら">o</keysym>
<keysym keyval="111" label="ラ">o</keysym>
</symbols>
</key>
<key id="keycode42" name="AD03" column="1" row="8">
<bounds>316.000000,43.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="108" label="り">l</keysym>
<keysym keyval="108" label="リ">l</keysym>
</symbols>
</key>
<key id="keycode43" name="AE04" column="2" row="8">
<bounds>316.000000,82.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="46" label="る">period</keysym>
<keysym keyval="46" label="ル">period</keysym>
</symbols>
</key>
<key id="keycode44" name="AE05" column="3" row="8">
<bounds>316.000000,121.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="59" label="れ">semicolon</keysym>
<keysym keyval="59" label="レ">semicolon</keysym>
</symbols>
</key>
<key id="keycode45" name="AE06" column="4" row="8">
<bounds>316.000000,160.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="92" label="ろ">backslash</keysym>
<keysym keyval="92" label="ロ">backslash</keysym>
</symbols>
</key>
<key id="keycode46" name="AE03" column="0" row="9">
<bounds>355.000000,4.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="48" label="わ">0</keysym>
<keysym keyval="48" label="ワ">0</keysym>
</symbols>
</key>
<key id="keycode47" name="AD03" column="1" row="9">
<bounds>355.000000,43.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="126" label="を">asciitilde</keysym>
<keysym keyval="126" label="ヲ">asciitilde</keysym>
</symbols>
</key>
<key id="keycode48" name="AE04" column="2" row="9">
<bounds>355.000000,82.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="121" label="ん">y</keysym>
<keysym keyval="121" label="ン">y</keysym>
</symbols>
</key>
<key id="keycode49" name="AE05" column="3" row="9">
<bounds>355.000000,121.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="2">
<keysym keyval="123" label="「">braceleft</keysym>
<keysym keyval="48" label="ゐ">0</keysym>
<keysym keyval="123" label="「">braceleft</keysym>
<keysym keyval="48" label="ヰ">0</keysym>
</symbols>
</key>
<key id="keycode50" name="AE06" column="4" row="9">
<bounds>355.000000,160.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="2">
<keysym keyval="125" label="」">braceright</keysym>
<keysym keyval="48" label="ゑ">0</keysym>
<keysym keyval="125" label="」">braceright</keysym>
<keysym keyval="48" label="ヱ">0</keysym>
</symbols>
</key>
<key id="keycode51" name="AE03" column="0" row="10">
<bounds>394.000000,4.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="64" label="゛">at</keysym>
<keysym keyval="64" label="゛">at</keysym>
</symbols>
</key>
<key id="keycode52" name="AD03" column="1" row="10">
<bounds>394.000000,43.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="91" label="゜">bracketleft</keysym>
<keysym keyval="91" label="゜">bracketleft</keysym>
</symbols>
</key>
<key id="keycode53" name="AE04" column="2" row="10">
<bounds>394.000000,82.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="124" label="ー">bar</keysym>
<keysym keyval="124" label="ー">bar</keysym>
</symbols>
</key>
<key id="keycode54" name="AE05" column="3" row="10">
<bounds>394.000000,121.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="1">
<keysym keyval="60" label="、">less</keysym>
<keysym keyval="60" label="、">less</keysym>
</symbols>
</key>
<key id="keycode55" name="AE06" column="4" row="10">
<bounds>394.000000,160.000000,38.000000,38.000000</bounds>
<oref>outline1</oref>
<symbols groups="2" levels="2">
<keysym keyval="62" label="。">greater</keysym>
<keysym keyval="63" label="・">question</keysym>
<keysym keyval="62" label="。">greater</keysym>
<keysym keyval="63" label="・">question</keysym>
</symbols>
</key>
</section>
<outline id="outline1">
<point>0.000000,0.000000</point>
<point>38.000000,0.000000</point>
<point>38.000000,38.000000</point>
<point>0.000000,38.000000</point>
</outline>
<outline id="outline3">
<point>0.000000,0.000000</point>
<point>60.000000,0.000000</point>
<point>60.000000,38.000000</point>
<point>0.000000,38.000000</point>
</outline>
<outline id="outline4">
<point>0.000000,0.000000</point>
<point>60.000000,0.000000</point>
<point>60.000000,38.000000</point>
<point>0.000000,38.000000</point>
</outline>
<outline id="outline5">
<point>0.000000,0.000000</point>
<point>69.000000,0.000000</point>
<point>69.000000,38.000000</point>
<point>0.000000,38.000000</point>
</outline>
<outline id="outline6">
<point>0.000000,0.000000</point>
<point>89.000000,0.000000</point>
<point>89.000000,38.000000</point>
<point>0.000000,38.000000</point>
</outline>
<outline id="outline7">
<point>0.000000,0.000000</point>
<point>89.000000,0.000000</point>
<point>89.000000,38.000000</point>
<point>0.000000,38.000000</point>
</outline>
<outline id="outline8">
<point>0.000000,0.000000</point>
<point>110.000000,0.000000</point>
<point>110.000000,38.000000</point>
<point>0.000000,38.000000</point>
</outline>
<outline id="outline9">
<point>0.000000,0.000000</point>
<point>57.000000,0.000000</point>
<point>57.000000,38.000000</point>
<point>0.000000,38.000000</point>
</outline>
<outline id="outline10">
<point>0.000000,0.000000</point>
<point>49.000000,0.000000</point>
<point>49.000000,38.000000</point>
<point>0.000000,38.000000</point>
</outline>
<outline id="outline11">
<point>0.000000,0.000000</point>
<point>239.000000,0.000000</point>
<point>239.000000,38.000000</point>
<point>0.000000,38.000000</point>
</outline>
<outline id="outline12">
<point>0.000000,0.000000</point>
<point>38.000000,0.000000</point>
<point>38.000000,79.000000</point>
<point>0.000000,79.000000</point>
</outline>
<outline id="outline13">
<point>0.000000,0.000000</point>
<point>79.000000,0.000000</point>
<point>79.000000,38.000000</point>
<point>0.000000,38.000000</point>
</outline>
<outline id="outline2">
<point>0.000000,0.000000</point>
<point>80.000000,0.000000</point>
<point>80.000000,38.000000</point>
<point>0.000000,38.000000</point>
</outline>
<outline id="outline14">
<corner-radius>1.000000</corner-radius>
<point>0.000000,0.000000</point>
<point>238.829268,0.000000</point>
<point>238.829268,37.463415</point>
<point>0.000000,37.463415</point>
</outline>
</keyboard>

681
data/keyboards/th.xml Normal file
View File

@ -0,0 +1,681 @@
<?xml version="1.0"?>
<keyboard version="0.90">
<bounds>0.000000,0.000000,640.000000,296.585366</bounds>
<section>
<bounds>15.609756,15.609756,640.000000,39.024390</bounds>
<angle>0</angle>
<row>
<columns>16</columns>
<orientation>1</orientation>
</row>
<key id="keycode9" name="keycode9" column="0" row="0">
<bounds>3.121951,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="1">
<keysym keyval="65307">Escape</keysym>
</symbols>
</key>
<key id="keycode67" name="keycode67" column="1" row="0">
<bounds>84.292683,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="1">
<keysym keyval="65470">F1</keysym>
</symbols>
</key>
<key id="keycode68" name="keycode68" column="2" row="0">
<bounds>124.878049,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="1">
<keysym keyval="65471">F2</keysym>
</symbols>
</key>
<key id="keycode69" name="keycode69" column="3" row="0">
<bounds>165.463415,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="1">
<keysym keyval="65472">F3</keysym>
</symbols>
</key>
<key id="keycode70" name="keycode70" column="4" row="0">
<bounds>206.048780,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="1">
<keysym keyval="65473">F4</keysym>
</symbols>
</key>
<key id="keycode71" name="keycode71" column="5" row="0">
<bounds>266.926829,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="1">
<keysym keyval="65474">F5</keysym>
</symbols>
</key>
<key id="keycode72" name="keycode72" column="6" row="0">
<bounds>307.512195,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="1">
<keysym keyval="65475">F6</keysym>
</symbols>
</key>
<key id="keycode73" name="keycode73" column="7" row="0">
<bounds>348.097561,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="1">
<keysym keyval="65476">F7</keysym>
</symbols>
</key>
<key id="keycode74" name="keycode74" column="8" row="0">
<bounds>388.682927,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="1">
<keysym keyval="65477">F8</keysym>
</symbols>
</key>
<key id="keycode75" name="keycode75" column="9" row="0">
<bounds>449.560976,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="1">
<keysym keyval="65478">F9</keysym>
</symbols>
</key>
<key id="keycode76" name="keycode76" column="10" row="0">
<bounds>490.146341,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="1">
<keysym keyval="65479">F10</keysym>
</symbols>
</key>
<key id="keycode95" name="keycode95" column="11" row="0">
<bounds>530.731707,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="1">
<keysym keyval="65480">F11</keysym>
</symbols>
</key>
<key id="keycode96" name="keycode96" column="12" row="0">
<bounds>571.317073,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="1">
<keysym keyval="65481">F12</keysym>
</symbols>
</key>
</section>
<section>
<bounds>15.609756,78.048780,608.780488,201.365854</bounds>
<angle>0</angle>
<row>
<columns>14</columns>
<orientation>1</orientation>
</row>
<row>
<columns>14</columns>
<orientation>1</orientation>
</row>
<row>
<columns>13</columns>
<orientation>1</orientation>
</row>
<row>
<columns>12</columns>
<orientation>1</orientation>
</row>
<row>
<columns>8</columns>
<orientation>1</orientation>
</row>
<key id="keycode49" name="keycode49" column="0" row="0">
<bounds>3.121951,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="95">underscore</keysym>
<keysym keyval="37">percent</keysym>
</symbols>
</key>
<key id="keycode10" name="keycode10" column="1" row="0">
<bounds>43.707317,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3557">Thai_lakkhangyao</keysym>
<keysym keyval="43">plus</keysym>
</symbols>
</key>
<key id="keycode11" name="keycode11" column="2" row="0">
<bounds>84.292683,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="47">slash</keysym>
<keysym keyval="3569">Thai_leknung</keysym>
</symbols>
</key>
<key id="keycode12" name="keycode12" column="3" row="0">
<bounds>124.878049,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="1">
<keysym keyval="45">minus</keysym>
<keysym keyval="3570">Thai_leksong</keysym>
</symbols>
</key>
<key id="keycode13" name="keycode13" column="4" row="0">
<bounds>165.463415,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3520">Thai_phosamphao</keysym>
<keysym keyval="3571">Thai_leksam</keysym>
</symbols>
</key>
<key id="keycode14" name="keycode14" column="5" row="0">
<bounds>206.048780,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3510">Thai_thothung</keysym>
<keysym keyval="3572">Thai_leksi</keysym>
</symbols>
</key>
<key id="keycode15" name="keycode15" column="6" row="0">
<bounds>245.073171,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3544">Thai_sarau</keysym>
<keysym keyval="3545">Thai_sarauu</keysym>
</symbols>
</key>
<key id="keycode16" name="keycode16" column="7" row="0">
<bounds>285.658537,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3542">Thai_saraue</keysym>
<keysym keyval="3551">Thai_baht</keysym>
</symbols>
</key>
<key id="keycode17" name="keycode17" column="8" row="0">
<bounds>326.243902,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3492">Thai_khokhwai</keysym>
<keysym keyval="3573">Thai_lekha</keysym>
</symbols>
</key>
<key id="keycode18" name="keycode18" column="9" row="0">
<bounds>366.829268,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3509">Thai_totao</keysym>
<keysym keyval="3574">Thai_lekhok</keysym>
</symbols>
</key>
<key id="keycode19" name="keycode19" column="10" row="0">
<bounds>407.414634,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3496">Thai_chochan</keysym>
<keysym keyval="3575">Thai_lekchet</keysym>
</symbols>
</key>
<key id="keycode20" name="keycode20" column="11" row="0">
<bounds>448.000000,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3490">Thai_khokhai</keysym>
<keysym keyval="3576">Thai_lekpaet</keysym>
</symbols>
</key>
<key id="keycode21" name="keycode21" column="12" row="0">
<bounds>488.585366,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3498">Thai_chochang</keysym>
<keysym keyval="3577">Thai_lekkao</keysym>
</symbols>
</key>
<key id="keycode22" name="keycode22" column="13" row="0">
<bounds>529.170732,1.560976,79.609756,37.463415</bounds>
<oref>outline13</oref>
<symbols groups="1" levels="1">
<keysym keyval="65288">BackSpace</keysym>
</symbols>
</key>
<key id="keycode23" name="keycode23" column="0" row="1">
<bounds>3.121951,42.146341,59.317073,37.463415</bounds>
<oref>outline4</oref>
<symbols groups="1" levels="2">
<keysym keyval="65289">Tab</keysym>
<keysym keyval="65056">ISO_Left_Tab</keysym>
</symbols>
</key>
<key id="keycode24" name="keycode24" column="1" row="1">
<bounds>65.560976,42.146341,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3558">Thai_maiyamok</keysym>
<keysym keyval="3568">Thai_leksun</keysym>
</symbols>
</key>
<key id="keycode25" name="keycode25" column="2" row="1">
<bounds>106.146341,42.146341,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3556">Thai_saraaimaimalai</keysym>
<keysym keyval="34">quotedbl</keysym>
</symbols>
</key>
<key id="keycode26" name="keycode26" column="3" row="1">
<bounds>145.170732,42.146341,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3539">Thai_saraam</keysym>
<keysym keyval="3502">Thai_dochada</keysym>
</symbols>
</key>
<key id="keycode27" name="keycode27" column="4" row="1">
<bounds>185.756098,42.146341,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3518">Thai_phophan</keysym>
<keysym keyval="3505">Thai_thonangmontho</keysym>
</symbols>
</key>
<key id="keycode28" name="keycode28" column="5" row="1">
<bounds>226.341463,42.146341,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3536">Thai_saraa</keysym>
<keysym keyval="3512">Thai_thothong</keysym>
</symbols>
</key>
<key id="keycode29" name="keycode29" column="6" row="1">
<bounds>266.926829,42.146341,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3537">Thai_maihanakat</keysym>
<keysym keyval="3565">Thai_nikhahit</keysym>
</symbols>
</key>
<key id="keycode30" name="keycode30" column="7" row="1">
<bounds>307.512195,42.146341,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3541">Thai_saraii</keysym>
<keysym keyval="3562">Thai_maitri</keysym>
</symbols>
</key>
<key id="keycode31" name="keycode31" column="8" row="1">
<bounds>348.097561,42.146341,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3523">Thai_rorua</keysym>
<keysym keyval="3507">Thai_nonen</keysym>
</symbols>
</key>
<key id="keycode32" name="keycode32" column="9" row="1">
<bounds>388.682927,42.146341,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3513">Thai_nonu</keysym>
<keysym keyval="3535">Thai_paiyannoi</keysym>
</symbols>
</key>
<key id="keycode33" name="keycode33" column="10" row="1">
<bounds>429.268293,42.146341,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3522">Thai_yoyak</keysym>
<keysym keyval="3501">Thai_yoying</keysym>
</symbols>
</key>
<key id="keycode34" name="keycode34" column="11" row="1">
<bounds>468.292683,42.146341,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3514">Thai_bobaimai</keysym>
<keysym keyval="3504">Thai_thothan</keysym>
</symbols>
</key>
<key id="keycode35" name="keycode35" column="12" row="1">
<bounds>508.878049,42.146341,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3525">Thai_loling</keysym>
<keysym keyval="44">comma</keysym>
</symbols>
</key>
<key id="keycode51" name="keycode51" column="13" row="1">
<bounds>549.463415,42.146341,59.317073,37.463415</bounds>
<oref>outline5</oref>
<symbols groups="1" levels="2">
<keysym keyval="3491">Thai_khokhuat</keysym>
<keysym keyval="3493">Thai_khokhon</keysym>
</symbols>
</key>
<key id="keycode66" name="keycode66" column="0" row="2">
<bounds>3.121951,82.731707,68.682927,37.463415</bounds>
<oref>outline6</oref>
<symbols groups="1" levels="1">
<keysym keyval="65027">ISO_Level3_Shift</keysym>
</symbols>
</key>
<key id="keycode38" name="keycode38" column="1" row="2">
<bounds>76.487805,82.731707,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3519">Thai_fofan</keysym>
<keysym keyval="3524">Thai_ru</keysym>
</symbols>
</key>
<key id="keycode39" name="keycode39" column="2" row="2">
<bounds>115.512195,82.731707,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3531">Thai_hohip</keysym>
<keysym keyval="3494">Thai_khorakhang</keysym>
</symbols>
</key>
<key id="keycode40" name="keycode40" column="3" row="2">
<bounds>156.097561,82.731707,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3489">Thai_kokai</keysym>
<keysym keyval="3503">Thai_topatak</keysym>
</symbols>
</key>
<key id="keycode41" name="keycode41" column="4" row="2">
<bounds>196.682927,82.731707,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3508">Thai_dodek</keysym>
<keysym keyval="3554">Thai_sarao</keysym>
</symbols>
</key>
<key id="keycode42" name="keycode42" column="5" row="2">
<bounds>237.268293,82.731707,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3552">Thai_sarae</keysym>
<keysym keyval="3500">Thai_chochoe</keysym>
</symbols>
</key>
<key id="keycode43" name="keycode43" column="6" row="2">
<bounds>277.853659,82.731707,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3561">Thai_maitho</keysym>
<keysym keyval="3559">Thai_maitaikhu</keysym>
</symbols>
</key>
<key id="keycode44" name="keycode44" column="7" row="2">
<bounds>318.439024,82.731707,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3560">Thai_maiek</keysym>
<keysym keyval="3563">Thai_maichattawa</keysym>
</symbols>
</key>
<key id="keycode45" name="keycode45" column="8" row="2">
<bounds>359.024390,82.731707,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3538">Thai_saraaa</keysym>
<keysym keyval="3529">Thai_sorusi</keysym>
</symbols>
</key>
<key id="keycode46" name="keycode46" column="9" row="2">
<bounds>399.609756,82.731707,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3530">Thai_sosua</keysym>
<keysym keyval="3528">Thai_sosala</keysym>
</symbols>
</key>
<key id="keycode47" name="keycode47" column="10" row="2">
<bounds>438.634146,82.731707,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3527">Thai_wowaen</keysym>
<keysym keyval="3499">Thai_soso</keysym>
</symbols>
</key>
<key id="keycode48" name="keycode48" column="11" row="2">
<bounds>479.219512,82.731707,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3495">Thai_ngongu</keysym>
<keysym keyval="46">period</keysym>
</symbols>
</key>
<key id="keycode36" name="keycode36" column="12" row="2">
<bounds>519.804878,82.731707,88.975610,37.463415</bounds>
<oref>outline7</oref>
<symbols groups="1" levels="1">
<keysym keyval="65293">Return</keysym>
</symbols>
</key>
<key id="keycode50" name="keycode50" column="0" row="3">
<bounds>3.121951,121.756098,88.975610,37.463415</bounds>
<oref>outline8</oref>
<symbols groups="1" levels="1">
<keysym keyval="65505">Shift_L</keysym>
</symbols>
</key>
<key id="keycode52" name="keycode52" column="1" row="3">
<bounds>95.219512,121.756098,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3516">Thai_phophung</keysym>
<keysym keyval="40">parenleft</keysym>
</symbols>
</key>
<key id="keycode53" name="keycode53" column="2" row="3">
<bounds>135.804878,121.756098,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3515">Thai_popla</keysym>
<keysym keyval="41">parenright</keysym>
</symbols>
</key>
<key id="keycode54" name="keycode54" column="3" row="3">
<bounds>176.390244,121.756098,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3553">Thai_saraae</keysym>
<keysym keyval="3497">Thai_choching</keysym>
</symbols>
</key>
<key id="keycode55" name="keycode55" column="4" row="3">
<bounds>215.414634,121.756098,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3533">Thai_oang</keysym>
<keysym keyval="3534">Thai_honokhuk</keysym>
</symbols>
</key>
<key id="keycode56" name="keycode56" column="5" row="3">
<bounds>256.000000,121.756098,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3540">Thai_sarai</keysym>
<keysym keyval="3546">Thai_phinthu</keysym>
</symbols>
</key>
<key id="keycode57" name="keycode57" column="6" row="3">
<bounds>296.585366,121.756098,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3543">Thai_sarauee</keysym>
<keysym keyval="3564">Thai_thanthakhat</keysym>
</symbols>
</key>
<key id="keycode58" name="keycode58" column="7" row="3">
<bounds>337.170732,121.756098,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3511">Thai_thothahan</keysym>
<keysym keyval="63">question</keysym>
</symbols>
</key>
<key id="keycode59" name="keycode59" column="8" row="3">
<bounds>377.756098,121.756098,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3521">Thai_moma</keysym>
<keysym keyval="3506">Thai_thophuthao</keysym>
</symbols>
</key>
<key id="keycode60" name="keycode60" column="9" row="3">
<bounds>418.341463,121.756098,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3555">Thai_saraaimaimuan</keysym>
<keysym keyval="3532">Thai_lochula</keysym>
</symbols>
</key>
<key id="keycode61" name="keycode61" column="10" row="3">
<bounds>458.926829,121.756098,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="3517">Thai_fofa</keysym>
<keysym keyval="3526">Thai_lu</keysym>
</symbols>
</key>
<key id="keycode62" name="keycode62" column="11" row="3">
<bounds>499.512195,121.756098,109.268293,37.463415</bounds>
<oref>outline9</oref>
<symbols groups="1" levels="1">
<keysym keyval="65506">Shift_R</keysym>
</symbols>
</key>
<key id="keycode37" name="keycode37" column="0" row="4">
<bounds>3.121951,162.341463,56.195122,37.463415</bounds>
<oref>outline10</oref>
<symbols groups="1" levels="2">
<symbol label="⌨" icon="input-keyboard-symbolic">cycle-keyboard</symbol>
<symbol label="☺" icon="preferences-system-symbolic">preferences</symbol>
</symbols>
</key>
<key id="keycode133" name="keycode133" column="1" row="4">
<bounds>62.439024,162.341463,48.390244,37.463415</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="1">
<keysym keyval="65507">Control_L</keysym>
</symbols>
</key>
<key id="keycode64" name="keycode64" column="2" row="4">
<bounds>113.951220,162.341463,48.390244,37.463415</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="65513">Alt_L</keysym>
<keysym keyval="65511">Meta_L</keysym>
</symbols>
</key>
<key id="keycode65" name="keycode65" column="3" row="4">
<bounds>165.463415,162.341463,238.829268,37.463415</bounds>
<oref>outline3</oref>
<symbols groups="1" levels="1">
<keysym keyval="32">space</keysym>
</symbols>
</key>
<key id="keycode108" name="keycode108" column="4" row="4">
<bounds>407.414634,162.341463,48.390244,37.463415</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="1">
<keysym keyval="65361">Left</keysym>
</symbols>
</key>
<key id="keycode134" name="keycode134" column="5" row="4">
<bounds>458.926829,162.341463,48.390244,37.463415</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="1">
<keysym keyval="65362">Up</keysym>
</symbols>
</key>
<key id="keycode135" name="keycode135" column="6" row="4">
<bounds>508.878049,162.341463,48.390244,37.463415</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="1">
<keysym keyval="65364">Down</keysym>
</symbols>
</key>
<key id="keycode105" name="keycode105" column="7" row="4">
<bounds>560.390244,162.341463,48.390244,37.463415</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="1">
<keysym keyval="65363">Right</keysym>
</symbols>
</key>
</section>
<outline id="outline2">
<corner-radius>1.000000</corner-radius>
<point>0.000000,0.000000</point>
<point>37.463415,0.000000</point>
<point>37.463415,37.463415</point>
<point>0.000000,37.463415</point>
</outline>
<outline id="outline1">
<corner-radius>1.000000</corner-radius>
<point>0.000000,0.000000</point>
<point>48.390244,0.000000</point>
<point>48.390244,37.463415</point>
<point>0.000000,37.463415</point>
</outline>
<outline id="outline4">
<corner-radius>1.000000</corner-radius>
<point>0.000000,0.000000</point>
<point>59.317073,0.000000</point>
<point>59.317073,37.463415</point>
<point>0.000000,37.463415</point>
</outline>
<outline id="outline5">
<corner-radius>1.000000</corner-radius>
<point>0.000000,0.000000</point>
<point>59.317073,0.000000</point>
<point>59.317073,37.463415</point>
<point>0.000000,37.463415</point>
</outline>
<outline id="outline6">
<corner-radius>1.000000</corner-radius>
<point>0.000000,0.000000</point>
<point>68.682927,0.000000</point>
<point>68.682927,37.463415</point>
<point>0.000000,37.463415</point>
</outline>
<outline id="outline7">
<corner-radius>1.000000</corner-radius>
<point>0.000000,0.000000</point>
<point>88.975610,0.000000</point>
<point>88.975610,37.463415</point>
<point>0.000000,37.463415</point>
</outline>
<outline id="outline8">
<corner-radius>1.000000</corner-radius>
<point>0.000000,0.000000</point>
<point>88.975610,0.000000</point>
<point>88.975610,37.463415</point>
<point>0.000000,37.463415</point>
</outline>
<outline id="outline9">
<corner-radius>1.000000</corner-radius>
<point>0.000000,0.000000</point>
<point>109.268293,0.000000</point>
<point>109.268293,37.463415</point>
<point>0.000000,37.463415</point>
</outline>
<outline id="outline10">
<corner-radius>1.000000</corner-radius>
<point>0.000000,0.000000</point>
<point>56.195122,0.000000</point>
<point>56.195122,37.463415</point>
<point>0.000000,37.463415</point>
</outline>
<outline id="outline13">
<corner-radius>1.000000</corner-radius>
<point>0.000000,0.000000</point>
<point>79.609756,0.000000</point>
<point>79.609756,37.463415</point>
<point>0.000000,37.463415</point>
</outline>
<outline id="outline3">
<corner-radius>1.000000</corner-radius>
<point>0.000000,0.000000</point>
<point>238.829268,0.000000</point>
<point>238.829268,37.463415</point>
<point>0.000000,37.463415</point>
</outline>
</keyboard>

View File

@ -1,707 +0,0 @@
<?xml version="1.0"?>
<keyboard version="0.90">
<bounds>0.000000,0.000000,410.000000,190.000000</bounds>
<section name="Alpha">
<bounds>10.000000,50.000000,390.000000,129.000000</bounds>
<angle>0</angle>
<row>
<columns>14</columns>
<orientation>1</orientation>
</row>
<row>
<columns>14</columns>
<orientation>1</orientation>
</row>
<row>
<columns>13</columns>
<orientation>1</orientation>
</row>
<row>
<columns>12</columns>
<orientation>1</orientation>
</row>
<row>
<columns>8</columns>
<orientation>1</orientation>
</row>
<key id="keycode105" name="RCTL" column="7" row="4">
<bounds>359.000000,104.000000,31.000000,24.000000</bounds>
<oref>outline10</oref>
<symbols groups="1" levels="1">
<keysym keyval="65508">Control_R</keysym>
</symbols>
</key>
<key id="keycode135" name="MENU" column="6" row="4">
<bounds>326.000000,104.000000,31.000000,24.000000</bounds>
<oref>outline10</oref>
<symbols groups="1" levels="1">
<keysym keyval="65383">Menu</keysym>
</symbols>
</key>
<key id="keycode134" name="RWIN" column="5" row="4">
<bounds>294.000000,104.000000,31.000000,24.000000</bounds>
<oref>outline10</oref>
<symbols groups="1" levels="1">
<keysym keyval="65516">Super_R</keysym>
</symbols>
</key>
<key id="keycode108" name="RALT" column="4" row="4">
<bounds>261.000000,104.000000,31.000000,24.000000</bounds>
<oref>outline10</oref>
<symbols groups="1" levels="1">
<keysym keyval="65027">ISO_Level3_Shift</keysym>
</symbols>
</key>
<key id="keycode65" name="SPCE" column="3" row="4">
<bounds>106.000000,104.000000,153.000000,24.000000</bounds>
<oref>outline11</oref>
<symbols groups="1" levels="1">
<keysym keyval="32">space</keysym>
</symbols>
</key>
<key id="keycode64" name="LALT" column="2" row="4">
<bounds>73.000000,104.000000,31.000000,24.000000</bounds>
<oref>outline10</oref>
<symbols groups="1" levels="2">
<keysym keyval="65513">Alt_L</keysym>
<keysym keyval="65511">Meta_L</keysym>
</symbols>
</key>
<key id="keycode133" name="LWIN" column="1" row="4">
<bounds>40.000000,104.000000,31.000000,24.000000</bounds>
<oref>outline10</oref>
<symbols groups="1" levels="1">
<keysym keyval="65515">Super_L</keysym>
</symbols>
</key>
<key id="keycode37" name="LCTL" column="0" row="4">
<bounds>2.000000,104.000000,36.000000,24.000000</bounds>
<oref>outline9</oref>
<symbols groups="1" levels="1">
<keysym keyval="65507">Control_L</keysym>
</symbols>
</key>
<key id="keycode62" name="RTSH" column="11" row="3">
<bounds>320.000000,78.000000,70.000000,24.000000</bounds>
<oref>outline8</oref>
<symbols groups="1" levels="1">
<keysym keyval="65506">Shift_R</keysym>
</symbols>
</key>
<key id="keycode61" name="AB10" column="10" row="3">
<bounds>294.000000,78.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="47">slash</keysym>
<keysym keyval="63">question</keysym>
</symbols>
</key>
<key id="keycode60" name="AB09" column="9" row="3">
<bounds>268.000000,78.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="46">period</keysym>
<keysym keyval="62">greater</keysym>
</symbols>
</key>
<key id="keycode59" name="AB08" column="8" row="3">
<bounds>242.000000,78.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="44">comma</keysym>
<keysym keyval="60">less</keysym>
</symbols>
</key>
<key id="keycode58" name="AB07" column="7" row="3">
<bounds>216.000000,78.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="109">m</keysym>
<keysym keyval="77">M</keysym>
</symbols>
</key>
<key id="keycode57" name="AB06" column="6" row="3">
<bounds>190.000000,78.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="110">n</keysym>
<keysym keyval="78">N</keysym>
</symbols>
</key>
<key id="keycode56" name="AB05" column="5" row="3">
<bounds>164.000000,78.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="98">b</keysym>
<keysym keyval="66">B</keysym>
</symbols>
</key>
<key id="keycode55" name="AB04" column="4" row="3">
<bounds>138.000000,78.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="118">v</keysym>
<keysym keyval="86">V</keysym>
</symbols>
</key>
<key id="keycode54" name="AB03" column="3" row="3">
<bounds>113.000000,78.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="99">c</keysym>
<keysym keyval="67">C</keysym>
</symbols>
</key>
<key id="keycode53" name="AB02" column="2" row="3">
<bounds>87.000000,78.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="120">x</keysym>
<keysym keyval="88">X</keysym>
</symbols>
</key>
<key id="keycode52" name="AB01" column="1" row="3">
<bounds>61.000000,78.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="122">z</keysym>
<keysym keyval="90">Z</keysym>
</symbols>
</key>
<key id="keycode50" name="LFSH" column="0" row="3">
<bounds>2.000000,78.000000,57.000000,24.000000</bounds>
<oref>outline7</oref>
<symbols groups="1" levels="1">
<keysym keyval="65505">Shift_L</keysym>
</symbols>
</key>
<key id="keycode36" name="RTRN" column="12" row="2">
<bounds>333.000000,53.000000,57.000000,24.000000</bounds>
<oref>outline6</oref>
<symbols groups="1" levels="1">
<keysym keyval="65293">Return</keysym>
</symbols>
</key>
<key id="keycode48" name="AC11" column="11" row="2">
<bounds>307.000000,53.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="39">quoteright</keysym>
<keysym keyval="34">quotedbl</keysym>
</symbols>
</key>
<key id="keycode47" name="AC10" column="10" row="2">
<bounds>281.000000,53.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="59">semicolon</keysym>
<keysym keyval="58">colon</keysym>
</symbols>
</key>
<key id="keycode46" name="AC09" column="9" row="2">
<bounds>256.000000,53.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="108">l</keysym>
<keysym keyval="76">L</keysym>
</symbols>
</key>
<key id="keycode45" name="AC08" column="8" row="2">
<bounds>230.000000,53.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="107">k</keysym>
<keysym keyval="75">K</keysym>
</symbols>
</key>
<key id="keycode44" name="AC07" column="7" row="2">
<bounds>204.000000,53.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="106">j</keysym>
<keysym keyval="74">J</keysym>
</symbols>
</key>
<key id="keycode43" name="AC06" column="6" row="2">
<bounds>178.000000,53.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="104">h</keysym>
<keysym keyval="72">H</keysym>
</symbols>
</key>
<key id="keycode42" name="AC05" column="5" row="2">
<bounds>152.000000,53.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="103">g</keysym>
<keysym keyval="71">G</keysym>
</symbols>
</key>
<key id="keycode41" name="AC04" column="4" row="2">
<bounds>126.000000,53.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="102">f</keysym>
<keysym keyval="70">F</keysym>
</symbols>
</key>
<key id="keycode40" name="AC03" column="3" row="2">
<bounds>100.000000,53.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="100">d</keysym>
<keysym keyval="68">D</keysym>
</symbols>
</key>
<key id="keycode39" name="AC02" column="2" row="2">
<bounds>74.000000,53.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="115">s</keysym>
<keysym keyval="83">S</keysym>
</symbols>
</key>
<key id="keycode38" name="AC01" column="1" row="2">
<bounds>49.000000,53.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="97">a</keysym>
<keysym keyval="65">A</keysym>
</symbols>
</key>
<key id="keycode66" name="CAPS" column="0" row="2">
<bounds>2.000000,53.000000,44.000000,24.000000</bounds>
<oref>outline5</oref>
<symbols groups="1" levels="2">
<keysym keyval="65507">Control_L</keysym>
<keysym keyval="65507">Control_L</keysym>
</symbols>
</key>
<key id="keycode51" name="BKSL" column="13" row="1">
<bounds>352.000000,27.000000,38.000000,24.000000</bounds>
<oref>outline4</oref>
<symbols groups="1" levels="2">
<keysym keyval="92">backslash</keysym>
<keysym keyval="124">bar</keysym>
</symbols>
</key>
<key id="keycode35" name="AD12" column="12" row="1">
<bounds>326.000000,27.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="93">bracketright</keysym>
<keysym keyval="125">braceright</keysym>
</symbols>
</key>
<key id="keycode34" name="AD11" column="11" row="1">
<bounds>300.000000,27.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="91">bracketleft</keysym>
<keysym keyval="123">braceleft</keysym>
</symbols>
</key>
<key id="keycode33" name="AD10" column="10" row="1">
<bounds>275.000000,27.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="112">p</keysym>
<keysym keyval="80">P</keysym>
</symbols>
</key>
<key id="keycode32" name="AD09" column="9" row="1">
<bounds>249.000000,27.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="111">o</keysym>
<keysym keyval="79">O</keysym>
</symbols>
</key>
<key id="keycode31" name="AD08" column="8" row="1">
<bounds>223.000000,27.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="105">i</keysym>
<keysym keyval="73">I</keysym>
</symbols>
</key>
<key id="keycode30" name="AD07" column="7" row="1">
<bounds>197.000000,27.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="117">u</keysym>
<keysym keyval="85">U</keysym>
</symbols>
</key>
<key id="keycode29" name="AD06" column="6" row="1">
<bounds>171.000000,27.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="121">y</keysym>
<keysym keyval="89">Y</keysym>
</symbols>
</key>
<key id="keycode28" name="AD05" column="5" row="1">
<bounds>145.000000,27.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="116">t</keysym>
<keysym keyval="84">T</keysym>
</symbols>
</key>
<key id="keycode27" name="AD04" column="4" row="1">
<bounds>119.000000,27.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="114">r</keysym>
<keysym keyval="82">R</keysym>
</symbols>
</key>
<key id="keycode26" name="AD03" column="3" row="1">
<bounds>93.000000,27.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="101">e</keysym>
<keysym keyval="69">E</keysym>
</symbols>
</key>
<key id="keycode25" name="AD02" column="2" row="1">
<bounds>68.000000,27.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="119">w</keysym>
<keysym keyval="87">W</keysym>
</symbols>
</key>
<key id="keycode24" name="AD01" column="1" row="1">
<bounds>42.000000,27.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="113">q</keysym>
<keysym keyval="81">Q</keysym>
</symbols>
</key>
<key id="keycode23" name="TAB" column="0" row="1">
<bounds>2.000000,27.000000,38.000000,24.000000</bounds>
<oref>outline3</oref>
<symbols groups="1" levels="2">
<keysym keyval="65289">Tab</keysym>
<keysym keyval="65056">ISO_Left_Tab</keysym>
</symbols>
</key>
<key id="keycode22" name="BKSP" column="13" row="0">
<bounds>339.000000,1.000000,51.000000,24.000000</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="1">
<keysym keyval="65288">BackSpace</keysym>
</symbols>
</key>
<key id="keycode21" name="AE12" column="12" row="0">
<bounds>313.000000,1.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="61">equal</keysym>
<keysym keyval="43">plus</keysym>
</symbols>
</key>
<key id="keycode20" name="AE11" column="11" row="0">
<bounds>287.000000,1.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="45">minus</keysym>
<keysym keyval="95">underscore</keysym>
</symbols>
</key>
<key id="keycode19" name="AE10" column="10" row="0">
<bounds>261.000000,1.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="48">0</keysym>
<keysym keyval="41">parenright</keysym>
</symbols>
</key>
<key id="keycode18" name="AE09" column="9" row="0">
<bounds>235.000000,1.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="57">9</keysym>
<keysym keyval="40">parenleft</keysym>
</symbols>
</key>
<key id="keycode17" name="AE08" column="8" row="0">
<bounds>209.000000,1.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="56">8</keysym>
<keysym keyval="42">asterisk</keysym>
</symbols>
</key>
<key id="keycode16" name="AE07" column="7" row="0">
<bounds>183.000000,1.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="55">7</keysym>
<keysym keyval="38">ampersand</keysym>
</symbols>
</key>
<key id="keycode15" name="AE06" column="6" row="0">
<bounds>157.000000,1.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="54">6</keysym>
<keysym keyval="94">asciicircum</keysym>
</symbols>
</key>
<key id="keycode14" name="AE05" column="5" row="0">
<bounds>132.000000,1.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="53">5</keysym>
<keysym keyval="37">percent</keysym>
</symbols>
</key>
<key id="keycode13" name="AE04" column="4" row="0">
<bounds>106.000000,1.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="52">4</keysym>
<keysym keyval="36">dollar</keysym>
</symbols>
</key>
<key id="keycode12" name="AE03" column="3" row="0">
<bounds>80.000000,1.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="51">3</keysym>
<keysym keyval="35">numbersign</keysym>
</symbols>
</key>
<key id="keycode11" name="AE02" column="2" row="0">
<bounds>54.000000,1.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="50">2</keysym>
<keysym keyval="64">at</keysym>
</symbols>
</key>
<key id="keycode10" name="AE01" column="1" row="0">
<bounds>28.000000,1.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="49">1</keysym>
<keysym keyval="33">exclam</keysym>
</symbols>
</key>
<key id="keycode49" name="TLDE" column="0" row="0">
<bounds>2.000000,1.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="96">quoteleft</keysym>
<keysym keyval="126">asciitilde</keysym>
</symbols>
</key>
</section>
<section name="Function">
<bounds>10.000000,10.000000,410.000000,25.000000</bounds>
<angle>0</angle>
<row>
<columns>16</columns>
<orientation>1</orientation>
</row>
<key id="keycode96" name="FK12" column="12" row="0">
<bounds>366.000000,1.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="65481">F12</keysym>
<keysym keyval="269024780">(null)</keysym>
</symbols>
</key>
<key id="keycode95" name="FK11" column="11" row="0">
<bounds>340.000000,1.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="65480">F11</keysym>
<keysym keyval="269024779">(null)</keysym>
</symbols>
</key>
<key id="keycode76" name="FK10" column="10" row="0">
<bounds>314.000000,1.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="65479">F10</keysym>
<keysym keyval="269024778">(null)</keysym>
</symbols>
</key>
<key id="keycode75" name="FK09" column="9" row="0">
<bounds>288.000000,1.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="65478">F9</keysym>
<keysym keyval="269024777">(null)</keysym>
</symbols>
</key>
<key id="keycode74" name="FK08" column="8" row="0">
<bounds>249.000000,1.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="65477">F8</keysym>
<keysym keyval="269024776">(null)</keysym>
</symbols>
</key>
<key id="keycode73" name="FK07" column="7" row="0">
<bounds>223.000000,1.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="65476">F7</keysym>
<keysym keyval="269024775">(null)</keysym>
</symbols>
</key>
<key id="keycode72" name="FK06" column="6" row="0">
<bounds>197.000000,1.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="65475">F6</keysym>
<keysym keyval="269024774">(null)</keysym>
</symbols>
</key>
<key id="keycode71" name="FK05" column="5" row="0">
<bounds>171.000000,1.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="65474">F5</keysym>
<keysym keyval="269024773">(null)</keysym>
</symbols>
</key>
<key id="keycode70" name="FK04" column="4" row="0">
<bounds>132.000000,1.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="65473">F4</keysym>
<keysym keyval="269024772">(null)</keysym>
</symbols>
</key>
<key id="keycode69" name="FK03" column="3" row="0">
<bounds>106.000000,1.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="65472">F3</keysym>
<keysym keyval="269024771">(null)</keysym>
</symbols>
</key>
<key id="keycode68" name="FK02" column="2" row="0">
<bounds>80.000000,1.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="65471">F2</keysym>
<keysym keyval="269024770">(null)</keysym>
</symbols>
</key>
<key id="keycode67" name="FK01" column="1" row="0">
<bounds>54.000000,1.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="65470">F1</keysym>
<keysym keyval="269024769">(null)</keysym>
</symbols>
</key>
<key id="keycode9" name="ESC" column="0" row="0">
<bounds>2.000000,1.000000,24.000000,24.000000</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="1">
<keysym keyval="65307">Escape</keysym>
</symbols>
</key>
</section>
<outline id="outline1">
<corner-radius>1.000000</corner-radius>
<point>0.000000,0.000000</point>
<point>24.000000,0.000000</point>
<point>24.000000,24.000000</point>
<point>0.000000,24.000000</point>
</outline>
<outline id="outline3">
<corner-radius>1.000000</corner-radius>
<point>0.000000,0.000000</point>
<point>38.000000,0.000000</point>
<point>38.000000,24.000000</point>
<point>0.000000,24.000000</point>
</outline>
<outline id="outline4">
<corner-radius>1.000000</corner-radius>
<point>0.000000,0.000000</point>
<point>38.000000,0.000000</point>
<point>38.000000,24.000000</point>
<point>0.000000,24.000000</point>
</outline>
<outline id="outline5">
<corner-radius>1.000000</corner-radius>
<point>0.000000,0.000000</point>
<point>44.000000,0.000000</point>
<point>44.000000,24.000000</point>
<point>0.000000,24.000000</point>
</outline>
<outline id="outline6">
<corner-radius>1.000000</corner-radius>
<point>0.000000,0.000000</point>
<point>57.000000,0.000000</point>
<point>57.000000,24.000000</point>
<point>0.000000,24.000000</point>
</outline>
<outline id="outline7">
<corner-radius>1.000000</corner-radius>
<point>0.000000,0.000000</point>
<point>57.000000,0.000000</point>
<point>57.000000,24.000000</point>
<point>0.000000,24.000000</point>
</outline>
<outline id="outline8">
<corner-radius>1.000000</corner-radius>
<point>0.000000,0.000000</point>
<point>70.000000,0.000000</point>
<point>70.000000,24.000000</point>
<point>0.000000,24.000000</point>
</outline>
<outline id="outline9">
<corner-radius>1.000000</corner-radius>
<point>0.000000,0.000000</point>
<point>36.000000,0.000000</point>
<point>36.000000,24.000000</point>
<point>0.000000,24.000000</point>
</outline>
<outline id="outline10">
<corner-radius>1.000000</corner-radius>
<point>0.000000,0.000000</point>
<point>31.000000,0.000000</point>
<point>31.000000,24.000000</point>
<point>0.000000,24.000000</point>
</outline>
<outline id="outline11">
<corner-radius>1.000000</corner-radius>
<point>0.000000,0.000000</point>
<point>153.000000,0.000000</point>
<point>153.000000,24.000000</point>
<point>0.000000,24.000000</point>
</outline>
<outline id="outline12">
<corner-radius>1.000000</corner-radius>
<point>0.000000,0.000000</point>
<point>24.000000,0.000000</point>
<point>24.000000,50.000000</point>
<point>0.000000,50.000000</point>
</outline>
<outline id="outline13">
<corner-radius>1.000000</corner-radius>
<point>0.000000,0.000000</point>
<point>50.000000,0.000000</point>
<point>50.000000,24.000000</point>
<point>0.000000,24.000000</point>
</outline>
<outline id="outline2">
<corner-radius>1.000000</corner-radius>
<point>0.000000,0.000000</point>
<point>51.000000,0.000000</point>
<point>51.000000,24.000000</point>
<point>0.000000,24.000000</point>
</outline>
</keyboard>

682
data/keyboards/us.xml Normal file
View File

@ -0,0 +1,682 @@
<?xml version="1.0"?>
<keyboard version="0.90">
<bounds>0.000000,0.000000,640.000000,296.585366</bounds>
<section>
<bounds>15.609756,15.609756,640.000000,39.024390</bounds>
<angle>0</angle>
<row>
<columns>16</columns>
<orientation>1</orientation>
</row>
<key id="keycode9" name="keycode9" column="0" row="0">
<bounds>3.121951,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="1">
<keysym keyval="65307">Escape</keysym>
</symbols>
</key>
<key id="keycode67" name="keycode67" column="1" row="0">
<bounds>84.292683,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="1">
<keysym keyval="65470">F1</keysym>
</symbols>
</key>
<key id="keycode68" name="keycode68" column="2" row="0">
<bounds>124.878049,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="1">
<keysym keyval="65471">F2</keysym>
</symbols>
</key>
<key id="keycode69" name="keycode69" column="3" row="0">
<bounds>165.463415,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="1">
<keysym keyval="65472">F3</keysym>
</symbols>
</key>
<key id="keycode70" name="keycode70" column="4" row="0">
<bounds>206.048780,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="1">
<keysym keyval="65473">F4</keysym>
</symbols>
</key>
<key id="keycode71" name="keycode71" column="5" row="0">
<bounds>266.926829,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="1">
<keysym keyval="65474">F5</keysym>
</symbols>
</key>
<key id="keycode72" name="keycode72" column="6" row="0">
<bounds>307.512195,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="1">
<keysym keyval="65475">F6</keysym>
</symbols>
</key>
<key id="keycode73" name="keycode73" column="7" row="0">
<bounds>348.097561,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="1">
<keysym keyval="65476">F7</keysym>
</symbols>
</key>
<key id="keycode74" name="keycode74" column="8" row="0">
<bounds>388.682927,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="1">
<keysym keyval="65477">F8</keysym>
</symbols>
</key>
<key id="keycode75" name="keycode75" column="9" row="0">
<bounds>449.560976,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="1">
<keysym keyval="65478">F9</keysym>
</symbols>
</key>
<key id="keycode76" name="keycode76" column="10" row="0">
<bounds>490.146341,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="1">
<keysym keyval="65479">F10</keysym>
</symbols>
</key>
<key id="keycode95" name="keycode95" column="11" row="0">
<bounds>530.731707,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="1">
<keysym keyval="65480">F11</keysym>
</symbols>
</key>
<key id="keycode96" name="keycode96" column="12" row="0">
<bounds>571.317073,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="1">
<keysym keyval="65481">F12</keysym>
</symbols>
</key>
</section>
<section>
<bounds>15.609756,78.048780,608.780488,201.365854</bounds>
<angle>0</angle>
<row>
<columns>14</columns>
<orientation>1</orientation>
</row>
<row>
<columns>14</columns>
<orientation>1</orientation>
</row>
<row>
<columns>13</columns>
<orientation>1</orientation>
</row>
<row>
<columns>12</columns>
<orientation>1</orientation>
</row>
<row>
<columns>8</columns>
<orientation>1</orientation>
</row>
<key id="keycode49" name="keycode49" column="0" row="0">
<bounds>3.121951,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="96">quoteleft</keysym>
<keysym keyval="126">asciitilde</keysym>
</symbols>
</key>
<key id="keycode10" name="keycode10" column="1" row="0">
<bounds>43.707317,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="49">1</keysym>
<keysym keyval="33">exclam</keysym>
</symbols>
</key>
<key id="keycode11" name="keycode11" column="2" row="0">
<bounds>84.292683,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="50">2</keysym>
<keysym keyval="64">at</keysym>
</symbols>
</key>
<key id="keycode12" name="keycode12" column="3" row="0">
<bounds>124.878049,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="51">3</keysym>
<keysym keyval="35">numbersign</keysym>
</symbols>
</key>
<key id="keycode13" name="keycode13" column="4" row="0">
<bounds>165.463415,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="52">4</keysym>
<keysym keyval="36">dollar</keysym>
</symbols>
</key>
<key id="keycode14" name="keycode14" column="5" row="0">
<bounds>206.048780,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="3">
<keysym keyval="53">5</keysym>
<keysym keyval="37">percent</keysym>
<keysym keyval="8364">EuroSign</keysym>
</symbols>
</key>
<key id="keycode15" name="keycode15" column="6" row="0">
<bounds>245.073171,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="54">6</keysym>
<keysym keyval="94">asciicircum</keysym>
</symbols>
</key>
<key id="keycode16" name="keycode16" column="7" row="0">
<bounds>285.658537,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="55">7</keysym>
<keysym keyval="38">ampersand</keysym>
</symbols>
</key>
<key id="keycode17" name="keycode17" column="8" row="0">
<bounds>326.243902,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="56">8</keysym>
<keysym keyval="42">asterisk</keysym>
</symbols>
</key>
<key id="keycode18" name="keycode18" column="9" row="0">
<bounds>366.829268,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="57">9</keysym>
<keysym keyval="40">parenleft</keysym>
</symbols>
</key>
<key id="keycode19" name="keycode19" column="10" row="0">
<bounds>407.414634,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="48">0</keysym>
<keysym keyval="41">parenright</keysym>
</symbols>
</key>
<key id="keycode20" name="keycode20" column="11" row="0">
<bounds>448.000000,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="45">minus</keysym>
<keysym keyval="95">underscore</keysym>
</symbols>
</key>
<key id="keycode21" name="keycode21" column="12" row="0">
<bounds>488.585366,1.560976,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="61">equal</keysym>
<keysym keyval="43">plus</keysym>
</symbols>
</key>
<key id="keycode22" name="keycode22" column="13" row="0">
<bounds>529.170732,1.560976,79.609756,37.463415</bounds>
<oref>outline13</oref>
<symbols groups="1" levels="1">
<keysym keyval="65288">BackSpace</keysym>
</symbols>
</key>
<key id="keycode23" name="keycode23" column="0" row="1">
<bounds>3.121951,42.146341,59.317073,37.463415</bounds>
<oref>outline4</oref>
<symbols groups="1" levels="2">
<keysym keyval="65289">Tab</keysym>
<keysym keyval="65056">ISO_Left_Tab</keysym>
</symbols>
</key>
<key id="keycode24" name="keycode24" column="1" row="1">
<bounds>65.560976,42.146341,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="113">q</keysym>
<keysym keyval="81">Q</keysym>
</symbols>
</key>
<key id="keycode25" name="keycode25" column="2" row="1">
<bounds>106.146341,42.146341,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="119">w</keysym>
<keysym keyval="87">W</keysym>
</symbols>
</key>
<key id="keycode26" name="keycode26" column="3" row="1">
<bounds>145.170732,42.146341,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="101">e</keysym>
<keysym keyval="69">E</keysym>
</symbols>
</key>
<key id="keycode27" name="keycode27" column="4" row="1">
<bounds>185.756098,42.146341,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="114">r</keysym>
<keysym keyval="82">R</keysym>
</symbols>
</key>
<key id="keycode28" name="keycode28" column="5" row="1">
<bounds>226.341463,42.146341,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="116">t</keysym>
<keysym keyval="84">T</keysym>
</symbols>
</key>
<key id="keycode29" name="keycode29" column="6" row="1">
<bounds>266.926829,42.146341,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="121">y</keysym>
<keysym keyval="89">Y</keysym>
</symbols>
</key>
<key id="keycode30" name="keycode30" column="7" row="1">
<bounds>307.512195,42.146341,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="117">u</keysym>
<keysym keyval="85">U</keysym>
</symbols>
</key>
<key id="keycode31" name="keycode31" column="8" row="1">
<bounds>348.097561,42.146341,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="105">i</keysym>
<keysym keyval="73">I</keysym>
</symbols>
</key>
<key id="keycode32" name="keycode32" column="9" row="1">
<bounds>388.682927,42.146341,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="111">o</keysym>
<keysym keyval="79">O</keysym>
</symbols>
</key>
<key id="keycode33" name="keycode33" column="10" row="1">
<bounds>429.268293,42.146341,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="112">p</keysym>
<keysym keyval="80">P</keysym>
</symbols>
</key>
<key id="keycode34" name="keycode34" column="11" row="1">
<bounds>468.292683,42.146341,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="91">bracketleft</keysym>
<keysym keyval="123">braceleft</keysym>
</symbols>
</key>
<key id="keycode35" name="keycode35" column="12" row="1">
<bounds>508.878049,42.146341,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="93">bracketright</keysym>
<keysym keyval="125">braceright</keysym>
</symbols>
</key>
<key id="keycode51" name="keycode51" column="13" row="1">
<bounds>549.463415,42.146341,59.317073,37.463415</bounds>
<oref>outline5</oref>
<symbols groups="1" levels="2">
<keysym keyval="92">backslash</keysym>
<keysym keyval="124">bar</keysym>
</symbols>
</key>
<key id="keycode66" name="keycode66" column="0" row="2">
<bounds>3.121951,82.731707,68.682927,37.463415</bounds>
<oref>outline6</oref>
<symbols groups="1" levels="1">
<keysym keyval="65027">ISO_Level3_Shift</keysym>
</symbols>
</key>
<key id="keycode38" name="keycode38" column="1" row="2">
<bounds>76.487805,82.731707,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="97">a</keysym>
<keysym keyval="65">A</keysym>
</symbols>
</key>
<key id="keycode39" name="keycode39" column="2" row="2">
<bounds>115.512195,82.731707,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="115">s</keysym>
<keysym keyval="83">S</keysym>
</symbols>
</key>
<key id="keycode40" name="keycode40" column="3" row="2">
<bounds>156.097561,82.731707,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="100">d</keysym>
<keysym keyval="68">D</keysym>
</symbols>
</key>
<key id="keycode41" name="keycode41" column="4" row="2">
<bounds>196.682927,82.731707,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="102">f</keysym>
<keysym keyval="70">F</keysym>
</symbols>
</key>
<key id="keycode42" name="keycode42" column="5" row="2">
<bounds>237.268293,82.731707,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="103">g</keysym>
<keysym keyval="71">G</keysym>
</symbols>
</key>
<key id="keycode43" name="keycode43" column="6" row="2">
<bounds>277.853659,82.731707,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="104">h</keysym>
<keysym keyval="72">H</keysym>
</symbols>
</key>
<key id="keycode44" name="keycode44" column="7" row="2">
<bounds>318.439024,82.731707,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="106">j</keysym>
<keysym keyval="74">J</keysym>
</symbols>
</key>
<key id="keycode45" name="keycode45" column="8" row="2">
<bounds>359.024390,82.731707,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="107">k</keysym>
<keysym keyval="75">K</keysym>
</symbols>
</key>
<key id="keycode46" name="keycode46" column="9" row="2">
<bounds>399.609756,82.731707,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="108">l</keysym>
<keysym keyval="76">L</keysym>
</symbols>
</key>
<key id="keycode47" name="keycode47" column="10" row="2">
<bounds>438.634146,82.731707,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="59">semicolon</keysym>
<keysym keyval="58">colon</keysym>
</symbols>
</key>
<key id="keycode48" name="keycode48" column="11" row="2">
<bounds>479.219512,82.731707,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="39">quoteright</keysym>
<keysym keyval="34">quotedbl</keysym>
</symbols>
</key>
<key id="keycode36" name="keycode36" column="12" row="2">
<bounds>519.804878,82.731707,88.975610,37.463415</bounds>
<oref>outline7</oref>
<symbols groups="1" levels="1">
<keysym keyval="65293">Return</keysym>
</symbols>
</key>
<key id="keycode50" name="keycode50" column="0" row="3">
<bounds>3.121951,121.756098,88.975610,37.463415</bounds>
<oref>outline8</oref>
<symbols groups="1" levels="1">
<keysym keyval="65505">Shift_L</keysym>
</symbols>
</key>
<key id="keycode52" name="keycode52" column="1" row="3">
<bounds>95.219512,121.756098,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="122">z</keysym>
<keysym keyval="90">Z</keysym>
</symbols>
</key>
<key id="keycode53" name="keycode53" column="2" row="3">
<bounds>135.804878,121.756098,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="120">x</keysym>
<keysym keyval="88">X</keysym>
</symbols>
</key>
<key id="keycode54" name="keycode54" column="3" row="3">
<bounds>176.390244,121.756098,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="99">c</keysym>
<keysym keyval="67">C</keysym>
</symbols>
</key>
<key id="keycode55" name="keycode55" column="4" row="3">
<bounds>215.414634,121.756098,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="118">v</keysym>
<keysym keyval="86">V</keysym>
</symbols>
</key>
<key id="keycode56" name="keycode56" column="5" row="3">
<bounds>256.000000,121.756098,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="98">b</keysym>
<keysym keyval="66">B</keysym>
</symbols>
</key>
<key id="keycode57" name="keycode57" column="6" row="3">
<bounds>296.585366,121.756098,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="110">n</keysym>
<keysym keyval="78">N</keysym>
</symbols>
</key>
<key id="keycode58" name="keycode58" column="7" row="3">
<bounds>337.170732,121.756098,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="109">m</keysym>
<keysym keyval="77">M</keysym>
</symbols>
</key>
<key id="keycode59" name="keycode59" column="8" row="3">
<bounds>377.756098,121.756098,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="44">comma</keysym>
<keysym keyval="60">less</keysym>
</symbols>
</key>
<key id="keycode60" name="keycode60" column="9" row="3">
<bounds>418.341463,121.756098,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="46">period</keysym>
<keysym keyval="62">greater</keysym>
</symbols>
</key>
<key id="keycode61" name="keycode61" column="10" row="3">
<bounds>458.926829,121.756098,37.463415,37.463415</bounds>
<oref>outline2</oref>
<symbols groups="1" levels="2">
<keysym keyval="47">slash</keysym>
<keysym keyval="63">question</keysym>
</symbols>
</key>
<key id="keycode62" name="keycode62" column="11" row="3">
<bounds>499.512195,121.756098,109.268293,37.463415</bounds>
<oref>outline9</oref>
<symbols groups="1" levels="1">
<keysym keyval="65506">Shift_R</keysym>
</symbols>
</key>
<key id="keycode37" name="keycode37" column="0" row="4">
<bounds>3.121951,162.341463,56.195122,37.463415</bounds>
<oref>outline10</oref>
<symbols groups="1" levels="2">
<symbol label="⌨" icon="input-keyboard-symbolic">cycle-keyboard</symbol>
<symbol label="☺" icon="preferences-system-symbolic">preferences</symbol>
</symbols>
</key>
<key id="keycode133" name="keycode133" column="1" row="4">
<bounds>62.439024,162.341463,48.390244,37.463415</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="1">
<keysym keyval="65507">Control_L</keysym>
</symbols>
</key>
<key id="keycode64" name="keycode64" column="2" row="4">
<bounds>113.951220,162.341463,48.390244,37.463415</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="2">
<keysym keyval="65513">Alt_L</keysym>
<keysym keyval="65511">Meta_L</keysym>
</symbols>
</key>
<key id="keycode65" name="keycode65" column="3" row="4">
<bounds>165.463415,162.341463,238.829268,37.463415</bounds>
<oref>outline3</oref>
<symbols groups="1" levels="1">
<keysym keyval="32">space</keysym>
</symbols>
</key>
<key id="keycode108" name="keycode108" column="4" row="4">
<bounds>407.414634,162.341463,48.390244,37.463415</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="1">
<keysym keyval="65361">Left</keysym>
</symbols>
</key>
<key id="keycode134" name="keycode134" column="5" row="4">
<bounds>458.926829,162.341463,48.390244,37.463415</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="1">
<keysym keyval="65362">Up</keysym>
</symbols>
</key>
<key id="keycode135" name="keycode135" column="6" row="4">
<bounds>508.878049,162.341463,48.390244,37.463415</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="1">
<keysym keyval="65364">Down</keysym>
</symbols>
</key>
<key id="keycode105" name="keycode105" column="7" row="4">
<bounds>560.390244,162.341463,48.390244,37.463415</bounds>
<oref>outline1</oref>
<symbols groups="1" levels="1">
<keysym keyval="65363">Right</keysym>
</symbols>
</key>
</section>
<outline id="outline2">
<corner-radius>1.000000</corner-radius>
<point>0.000000,0.000000</point>
<point>37.463415,0.000000</point>
<point>37.463415,37.463415</point>
<point>0.000000,37.463415</point>
</outline>
<outline id="outline1">
<corner-radius>1.000000</corner-radius>
<point>0.000000,0.000000</point>
<point>48.390244,0.000000</point>
<point>48.390244,37.463415</point>
<point>0.000000,37.463415</point>
</outline>
<outline id="outline4">
<corner-radius>1.000000</corner-radius>
<point>0.000000,0.000000</point>
<point>59.317073,0.000000</point>
<point>59.317073,37.463415</point>
<point>0.000000,37.463415</point>
</outline>
<outline id="outline5">
<corner-radius>1.000000</corner-radius>
<point>0.000000,0.000000</point>
<point>59.317073,0.000000</point>
<point>59.317073,37.463415</point>
<point>0.000000,37.463415</point>
</outline>
<outline id="outline6">
<corner-radius>1.000000</corner-radius>
<point>0.000000,0.000000</point>
<point>68.682927,0.000000</point>
<point>68.682927,37.463415</point>
<point>0.000000,37.463415</point>
</outline>
<outline id="outline7">
<corner-radius>1.000000</corner-radius>
<point>0.000000,0.000000</point>
<point>88.975610,0.000000</point>
<point>88.975610,37.463415</point>
<point>0.000000,37.463415</point>
</outline>
<outline id="outline8">
<corner-radius>1.000000</corner-radius>
<point>0.000000,0.000000</point>
<point>88.975610,0.000000</point>
<point>88.975610,37.463415</point>
<point>0.000000,37.463415</point>
</outline>
<outline id="outline9">
<corner-radius>1.000000</corner-radius>
<point>0.000000,0.000000</point>
<point>109.268293,0.000000</point>
<point>109.268293,37.463415</point>
<point>0.000000,37.463415</point>
</outline>
<outline id="outline10">
<corner-radius>1.000000</corner-radius>
<point>0.000000,0.000000</point>
<point>56.195122,0.000000</point>
<point>56.195122,37.463415</point>
<point>0.000000,37.463415</point>
</outline>
<outline id="outline13">
<corner-radius>1.000000</corner-radius>
<point>0.000000,0.000000</point>
<point>79.609756,0.000000</point>
<point>79.609756,37.463415</point>
<point>0.000000,37.463415</point>
</outline>
<outline id="outline3">
<corner-radius>1.000000</corner-radius>
<point>0.000000,0.000000</point>
<point>238.829268,0.000000</point>
<point>238.829268,37.463415</point>
<point>0.000000,37.463415</point>
</outline>
</keyboard>

View File

@ -1,6 +1,11 @@
<?xml version="1.0"?>
<schemalist>
<schema id="org.fedorahosted.eekboard" path="/org/fedorahosted/eekboard/">
<key name="keyboard" type="s">
<default>'us'</default>
<summary>Keyboard types</summary>
<description>keyboard types (comma separated).</description>
</key>
<key name="ui-toolkit" type="s">
<default>'gtk'</default>
<summary>GUI toolkit used to render keyboard</summary>
@ -16,10 +21,35 @@
<summary>Hide keyboard automatically when focus is out</summary>
<description>If true, hide keyboard automatically when focus is out.</description>
</key>
<key name="auto-hide-delay" type="u">
<default>500</default>
<summary>Delay before hiding keyboard</summary>
<description>Delay before hiding keyboard in milliseconds. This is useful when focus listener is enabled.</description>
</key>
<key type="b" name="repeat">
<default>true</default>
<summary>Key repeat</summary>
<description>Generate key-press/release event repeatedly while a key is held down</description>
</key>
<key type="u" name="repeat-interval">
<default>100</default>
<summary>Key repeat interval</summary>
<description>Delay between repeats in milliseconds.</description>
</key>
<key type="u" name="repeat-delay">
<default>1000</default>
<summary>Initial key repeat delay</summary>
<description>Initial key repeat delay in milliseconds.</description>
</key>
<key name="start-fullscreen" type="b">
<default>false</default>
<summary>Switch to fullscreen mode when startup</summary>
<description>If true, switch to fullscreen mode when startup.</description>
</key>
<key name="theme" type="s">
<default>'default'</default>
<summary>Theme</summary>
<description>Base name of the theme to apply.</description>
</key>
</schema>
</schemalist>

View File

@ -83,6 +83,8 @@ IGNORE_HFILES = \
eek-clutter-section.h \
eek-clutter-key.h \
eek-gtk-renderer.h \
eek-theme.h \
eek-theme-node.h \
eek-enumtypes.h
if !ENABLE_CLUTTER
IGNORE_HFILES += eek-clutter-keyboard.h eek-clutter.h

View File

@ -37,6 +37,7 @@
<title>API Manual</title>
<chapter>
<title>Base Classes, Interfaces, and Utilities</title>
<xi:include href="xml/eek.xml"/>
<xi:include href="xml/eek-serializable.xml"/>
<xi:include href="xml/eek-element.xml"/>
<xi:include href="xml/eek-container.xml"/>
@ -49,12 +50,12 @@
<xi:include href="xml/eek-types.xml"/>
</chapter>
<chapter>
<title>Clutter Keyboard</title>
<xi:include href="xml/eek-clutter-keyboard.xml"/>
<title>GTK Adapter</title>
<xi:include href="xml/eek-gtk-keyboard.xml"/>
</chapter>
<chapter>
<title>GTK Keyboard</title>
<xi:include href="xml/eek-gtk-keyboard.xml"/>
<title>Clutter Adapter</title>
<xi:include href="xml/eek-clutter-keyboard.xml"/>
</chapter>
<chapter>
<title>Libxklavier Layout Engine</title>

View File

@ -3,6 +3,7 @@
<TITLE>EekKeyboard</TITLE>
EekKeyboard
EekKeyboardClass
EekModifierKey
eek_keyboard_new
eek_keyboard_get_layout
eek_keyboard_get_size
@ -15,6 +16,7 @@ eek_keyboard_get_group
eek_keyboard_get_level
eek_keyboard_set_modifier_behavior
eek_keyboard_get_modifier_behavior
eek_keyboard_set_modifiers
eek_keyboard_get_modifiers
eek_keyboard_create_section
eek_keyboard_find_key_by_keycode
@ -24,6 +26,8 @@ eek_keyboard_set_num_lock_mask
eek_keyboard_get_num_lock_mask
eek_keyboard_set_alt_gr_mask
eek_keyboard_get_alt_gr_mask
eek_keyboard_get_pressed_keys
eek_keyboard_get_locked_keys
EekKeyboardPrivate
<SUBSECTION Standard>
EEK_KEYBOARD
@ -68,37 +72,6 @@ EEK_IS_GTK_KEYBOARD_CLASS
EEK_GTK_KEYBOARD_GET_CLASS
</SECTION>
<SECTION>
<FILE>eek-theme-node</FILE>
EekSide
EekCorner
eek_theme_node_new
eek_theme_node_get_parent
eek_theme_node_get_theme
eek_theme_node_get_element_type
eek_theme_node_get_element_id
eek_theme_node_get_element_class
eek_theme_node_get_pseudo_class
eek_theme_node_get_color
eek_theme_node_get_background_color
eek_theme_node_get_foreground_color
eek_theme_node_get_background_gradient
eek_theme_node_get_border_width
eek_theme_node_get_border_radius
eek_theme_node_get_border_color
eek_theme_node_get_font
EekThemeNodePrivate
EekThemeNodeClass
<SUBSECTION Standard>
EEK_THEME_NODE
EEK_IS_THEME_NODE
EEK_TYPE_THEME_NODE
eek_theme_node_get_type
EEK_THEME_NODE_CLASS
EEK_IS_THEME_NODE_CLASS
EEK_THEME_NODE_GET_CLASS
</SECTION>
<SECTION>
<FILE>eek-section</FILE>
<TITLE>EekSection</TITLE>
@ -285,6 +258,7 @@ eek_key_get_index
eek_key_set_oref
eek_key_get_oref
eek_key_is_pressed
eek_key_is_locked
EekKeyPrivate
<SUBSECTION Standard>
EEK_KEY
@ -360,22 +334,6 @@ EEK_IS_XML_LAYOUT_CLASS
EEK_XML_LAYOUT_GET_CLASS
</SECTION>
<SECTION>
<FILE>eek-theme</FILE>
eek_theme_new
eek_theme_load_stylesheet
eek_theme_unload_stylesheet
EekThemeClass
<SUBSECTION Standard>
EEK_THEME
EEK_IS_THEME
EEK_TYPE_THEME
eek_theme_get_type
EEK_THEME_CLASS
EEK_IS_THEME_CLASS
EEK_THEME_GET_CLASS
</SECTION>
<SECTION>
<FILE>eek-keysym</FILE>
<TITLE>EekKeysym</TITLE>
@ -434,9 +392,11 @@ eek_color_new
eek_color_copy
eek_color_free
EekGradientType
EekThemeNode
EekThemeContext
EekTheme
</SECTION>
<SECTION>
<FILE>eek</FILE>
eek_init
</SECTION>
<SECTION>

View File

@ -35,10 +35,15 @@
<part id="apireference">
<title>API Manual</title>
<chapter>
<title>D-Bus client interface to eekboard-server</title>
<xi:include href="xml/eekboard-eekboard.xml"/>
<title>Client interface to eekboard-server</title>
<xi:include href="xml/eekboard-client.xml"/>
<xi:include href="xml/eekboard-context.xml"/>
</chapter>
<chapter>
<title>Server interface to implement custom eekboard-server</title>
<xi:include href="xml/eekboard-service.xml"/>
<xi:include href="xml/eekboard-context-service.xml"/>
</chapter>
<chapter id="object-tree">
<title>Object Hierarchy</title>
<xi:include href="xml/tree_index.sgml"/>

View File

@ -1,22 +1,41 @@
<SECTION>
<FILE>eekboard-eekboard</FILE>
<TITLE>EekboardEekboard</TITLE>
EekboardEekboard
EekboardEekboardClass
EekboardEekboardPrivate
eekboard_eekboard_new
eekboard_eekboard_create_context
eekboard_eekboard_push_context
eekboard_eekboard_pop_context
eekboard_eekboard_destroy_context
<FILE>eekboard-client</FILE>
<TITLE>EekboardClient</TITLE>
EekboardClient
EekboardClientClass
eekboard_client_new
eekboard_client_create_context
eekboard_client_push_context
eekboard_client_pop_context
eekboard_client_destroy_context
EekboardClientPrivate
<SUBSECTION Standard>
EEKBOARD_EEKBOARD
EEKBOARD_IS_EEKBOARD
EEKBOARD_TYPE_EEKBOARD
eekboard_eekboard_get_type
EEKBOARD_EEKBOARD_CLASS
EEKBOARD_IS_EEKBOARD_CLASS
EEKBOARD_EEKBOARD_GET_CLASS
EEKBOARD_CLIENT
EEKBOARD_IS_CLIENT
EEKBOARD_TYPE_CLIENT
eekboard_client_get_type
EEKBOARD_CLIENT_CLASS
EEKBOARD_IS_CLIENT_CLASS
EEKBOARD_CLIENT_GET_CLASS
</SECTION>
<SECTION>
<FILE>eekboard-service</FILE>
<TITLE>EekboardService</TITLE>
EEKBOARD_SERVICE_PATH
EEKBOARD_SERVICE_INTERFACE
EekboardService
EekboardServiceClass
eekboard_service_new
EekboardServicePrivate
<SUBSECTION Standard>
EEKBOARD_SERVICE
EEKBOARD_IS_SERVICE
EEKBOARD_TYPE_SERVICE
eekboard_service_get_type
EEKBOARD_SERVICE_CLASS
EEKBOARD_IS_SERVICE_CLASS
EEKBOARD_SERVICE_GET_CLASS
</SECTION>
<SECTION>
@ -24,17 +43,21 @@ EEKBOARD_EEKBOARD_GET_CLASS
<TITLE>EekboardContext</TITLE>
EekboardContext
EekboardContextClass
EekboardContextPrivate
eekboard_context_new
eekboard_context_add_keyboard
eekboard_context_remove_keyboard
eekboard_context_set_keyboard
eekboard_context_show_keyboard
eekboard_context_hide_keyboard
eekboard_context_set_group
eekboard_context_press_key
eekboard_context_release_key
eekboard_context_get_group
eekboard_context_press_keycode
eekboard_context_release_keycode
eekboard_context_is_keyboard_visible
eekboard_context_set_enabled
eekboard_context_is_enabled
eekboard_context_set_fullscreen
EekboardContextPrivate
<SUBSECTION Standard>
EEKBOARD_CONTEXT
EEKBOARD_IS_CONTEXT
@ -45,3 +68,37 @@ EEKBOARD_IS_CONTEXT_CLASS
EEKBOARD_CONTEXT_GET_CLASS
</SECTION>
<SECTION>
<FILE>eekboard-context-service</FILE>
<TITLE>EekboardContextService</TITLE>
EEKBOARD_CONTEXT_SERVICE_PATH
EEKBOARD_CONTEXT_SERVICE_INTERFACE
EekboardContextService
EekboardContextServiceClass
eekboard_context_service_enable
eekboard_context_service_disable
eekboard_context_service_get_keyboard
eekboard_context_service_get_fullscreen
eekboard_context_service_get_client_name
EekboardContextServicePrivate
<SUBSECTION Standard>
EEKBOARD_CONTEXT_SERVICE
EEKBOARD_IS_CONTEXT_SERVICE
EEKBOARD_TYPE_CONTEXT_SERVICE
eekboard_context_service_get_type
EEKBOARD_CONTEXT_SERVICE_CLASS
EEKBOARD_IS_CONTEXT_SERVICE_CLASS
EEKBOARD_CONTEXT_SERVICE_GET_CLASS
</SECTION>
<SECTION>
<FILE>eekboard-xklutil</FILE>
eekboard_xkl_config_rec_from_string
eekboard_xkl_config_rec_to_string
eekboard_xkl_list_models
eekboard_xkl_list_layouts
eekboard_xkl_list_option_groups
eekboard_xkl_list_layout_variants
eekboard_xkl_list_options
</SECTION>

View File

@ -1,2 +1,4 @@
eekboard_client_get_type
eekboard_context_get_type
eekboard_eekboard_get_type
eekboard_context_service_get_type
eekboard_service_get_type

View File

@ -54,6 +54,7 @@ libeek_private_headers = \
$(srcdir)/eek-theme-node.h
libeek_sources = \
$(srcdir)/eek.c \
$(srcdir)/eek-layout.c \
$(srcdir)/eek-element.c \
$(srcdir)/eek-container.c \
@ -130,8 +131,8 @@ libeek_gtk_sources = \
$(srcdir)/eek-gtk-renderer.c
libeek_gtk_la_SOURCES = $(libeek_gtk_sources)
libeek_gtk_la_CFLAGS = -DEEK_COMPILATION=1 $(GTK_CFLAGS)
libeek_gtk_la_LIBADD = libeek.la $(GTK_LIBS)
libeek_gtk_la_CFLAGS = -DEEK_COMPILATION=1 $(GTK_CFLAGS) $(LIBCANBERRA_CFLAGS)
libeek_gtk_la_LIBADD = libeek.la $(GTK_LIBS) $(LIBCANBERRA_LIBS)
libeek_xkb_public_headers = \
$(srcdir)/eek-xkb-layout.h \
@ -172,11 +173,14 @@ noinst_HEADERS = \
$(libeek_xkl_private_headers)
eek-special-keysym-entries.h: special-keysym-entries.txt
$(PYTHON) ./gen-keysym-entries.py special_keysym_entries < $< > $@
$(AM_V_GEN) $(PYTHON) ./gen-keysym-entries.py special_keysym_entries \
< $< > $@
eek-unicode-keysym-entries.h: unicode-keysym-entries.txt
$(PYTHON) ./gen-keysym-entries.py unicode_keysym_entries < $< > $@
$(AM_V_GEN) $(PYTHON) ./gen-keysym-entries.py unicode_keysym_entries \
< $< > $@
eek-xkeysym-keysym-entries.h: xkeysym-keysym-entries.txt
$(PYTHON) ./gen-keysym-entries.py xkeysym_keysym_entries < $< > $@
$(AM_V_GEN) $(PYTHON) ./gen-keysym-entries.py xkeysym_keysym_entries \
< $< > $@
eek-enumtypes.h: $(libeek_public_headers) eek-enumtypes.h.template
$(AM_V_GEN) $(GLIB_MKENUMS) --template eek-enumtypes.h.template \

View File

@ -53,7 +53,8 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (EekContainer, eek_container, EEK_TYPE_ELEMENT,
struct _EekContainerPrivate
{
GSList *children;
GList *head;
GList *last;
};
static EekSerializableIface *eek_container_parent_serializable_iface;
@ -63,13 +64,13 @@ eek_container_real_serialize (EekSerializable *self,
GVariantBuilder *builder)
{
EekContainerPrivate *priv = EEK_CONTAINER_GET_PRIVATE(self);
GSList *head;
GList *head;
GVariantBuilder array;
eek_container_parent_serializable_iface->serialize (self, builder);
g_variant_builder_init (&array, G_VARIANT_TYPE("av"));
for (head = priv->children; head; head = g_slist_next (head)) {
for (head = priv->head; head; head = g_list_next (head)) {
GVariant *variant =
eek_serializable_serialize (EEK_SERIALIZABLE(head->data));
g_variant_builder_add (&array, "v", variant);
@ -119,7 +120,12 @@ eek_container_real_add_child (EekContainer *self,
g_return_if_fail (EEK_IS_ELEMENT(child));
g_object_ref (child);
priv->children = g_slist_prepend (priv->children, child);
if (!priv->head) {
priv->head = priv->last = g_list_prepend (priv->head, child);
} else {
priv->last->next = g_list_prepend (priv->last->next, child);
priv->last = priv->last->next;
}
eek_element_set_parent (child, EEK_ELEMENT(self));
g_signal_emit_by_name (self, "child-added", child);
}
@ -129,13 +135,15 @@ eek_container_real_remove_child (EekContainer *self,
EekElement *child)
{
EekContainerPrivate *priv = EEK_CONTAINER_GET_PRIVATE(self);
GSList *head;
GList *head;
g_return_if_fail (EEK_IS_ELEMENT(child));
head = g_slist_find (priv->children, child);
head = g_list_find (priv->head, child);
g_return_if_fail (head);
g_object_unref (child);
priv->children = g_slist_remove_link (priv->children, head);
if (head == priv->last)
priv->last = g_list_previous (priv->last);
priv->head = g_list_remove_link (priv->head, head);
eek_element_set_parent (child, NULL);
g_signal_emit_by_name (self, "child-removed", child);
}
@ -146,9 +154,9 @@ eek_container_real_foreach_child (EekContainer *self,
gpointer user_data)
{
EekContainerPrivate *priv = EEK_CONTAINER_GET_PRIVATE(self);
GSList *head;
GList *head;
for (head = priv->children; head; head = g_slist_next (head))
for (head = priv->head; head; head = g_list_next (head))
(*callback) (EEK_ELEMENT(head->data), user_data);
}
@ -158,9 +166,9 @@ eek_container_real_find (EekContainer *self,
gpointer user_data)
{
EekContainerPrivate *priv = EEK_CONTAINER_GET_PRIVATE(self);
GSList *head;
GList *head;
head = g_slist_find_custom (priv->children, user_data, (GCompareFunc)func);
head = g_list_find_custom (priv->head, user_data, (GCompareFunc)func);
if (head)
return head->data;
return NULL;
@ -170,12 +178,12 @@ static void
eek_container_dispose (GObject *object)
{
EekContainerPrivate *priv = EEK_CONTAINER_GET_PRIVATE(object);
GSList *head;
GList *head;
for (head = priv->children; head; head = priv->children) {
for (head = priv->head; head; head = priv->head) {
g_object_unref (head->data);
priv->children = g_slist_next (head);
g_slist_free1 (head);
priv->head = g_list_next (head);
g_list_free1 (head);
}
G_OBJECT_CLASS(eek_container_parent_class)->dispose (object);
}
@ -240,10 +248,7 @@ eek_container_class_init (EekContainerClass *klass)
static void
eek_container_init (EekContainer *self)
{
EekContainerPrivate *priv;
priv = self->priv = EEK_CONTAINER_GET_PRIVATE(self);
priv->children = NULL;
self->priv = EEK_CONTAINER_GET_PRIVATE(self);
}
/**

View File

@ -404,8 +404,6 @@ eek_element_init (EekElement *self)
EekElementPrivate *priv;
priv = self->priv = EEK_ELEMENT_GET_PRIVATE(self);
priv->name = NULL;
memset (&priv->bounds, 0, sizeof priv->bounds);
priv->group = -1;
priv->level = -1;
}
@ -489,7 +487,7 @@ eek_element_set_bounds (EekElement *element,
/**
* eek_element_get_bounds:
* @element: an #EekElement
* @bounds: pointer where bounding box of @element will be stored
* @bounds: (out): pointer where bounding box of @element will be stored
*
* Get the bounding box of @element. Note that if @element has
* parent, position of @bounds are relative to the parent. To obtain

View File

@ -27,6 +27,10 @@
#include "config.h"
#endif /* HAVE_CONFIG_H */
#ifdef HAVE_LIBCANBERRA
#include <canberra-gtk.h>
#endif
#include <string.h>
#include "eek-gtk-keyboard.h"
@ -57,9 +61,11 @@ struct _EekGtkKeyboardPrivate
{
EekRenderer *renderer;
EekKeyboard *keyboard;
EekKey *dragged_key;
gulong key_pressed_handler;
gulong key_released_handler;
gulong key_locked_handler;
gulong key_unlocked_handler;
gulong key_cancelled_handler;
gulong symbol_index_changed_handler;
EekTheme *theme;
};
@ -71,12 +77,25 @@ static void on_key_pressed (EekKeyboard *keyboard,
static void on_key_released (EekKeyboard *keyboard,
EekKey *key,
gpointer user_data);
static void on_key_locked (EekKeyboard *keyboard,
EekKey *key,
gpointer user_data);
static void on_key_unlocked (EekKeyboard *keyboard,
EekKey *key,
gpointer user_data);
static void on_key_cancelled (EekKeyboard *keyboard,
EekKey *key,
gpointer user_data);
static void on_symbol_index_changed (EekKeyboard *keyboard,
gint group,
gint level,
gpointer user_data);
static void render_pressed_key (GtkWidget *widget,
EekKey *key);
static void render_locked_key (GtkWidget *widget,
EekKey *key);
static void render_released_key (GtkWidget *widget,
EekKey *key);
static void
eek_gtk_keyboard_real_realize (GtkWidget *self)
@ -87,7 +106,8 @@ eek_gtk_keyboard_real_realize (GtkWidget *self)
GDK_KEY_PRESS_MASK |
GDK_KEY_RELEASE_MASK |
GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK);
GDK_BUTTON_RELEASE_MASK |
GDK_BUTTON_MOTION_MASK);
GTK_WIDGET_CLASS (eek_gtk_keyboard_parent_class)->realize (self);
}
@ -99,6 +119,7 @@ eek_gtk_keyboard_real_draw (GtkWidget *self,
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self);
GtkAllocation allocation;
EekColor background;
GList *head;
gtk_widget_get_allocation (self, &allocation);
@ -142,9 +163,17 @@ eek_gtk_keyboard_real_draw (GtkWidget *self,
eek_renderer_render_keyboard (priv->renderer, cr);
/* redraw dragged key */
if (priv->dragged_key)
render_pressed_key (self, priv->dragged_key);
/* redraw pressed key */
head = eek_keyboard_get_pressed_keys (priv->keyboard);
for (; head; head = g_list_next (head)) {
render_pressed_key (self, head->data);
}
/* redraw locked key */
head = eek_keyboard_get_locked_keys (priv->keyboard);
for (; head; head = g_list_next (head)) {
render_locked_key (self, ((EekModifierKey *)head->data)->key);
}
return FALSE;
}
@ -190,14 +219,8 @@ eek_gtk_keyboard_real_button_press_event (GtkWidget *self,
key = eek_renderer_find_key_by_position (priv->renderer,
(gdouble)event->x,
(gdouble)event->y);
if (priv->dragged_key && priv->dragged_key != key)
g_signal_emit_by_name (priv->dragged_key, "released", priv->keyboard);
if (key && !eek_key_is_pressed (key)) {
priv->dragged_key = key;
if (key)
g_signal_emit_by_name (key, "pressed", priv->keyboard);
}
return TRUE;
}
@ -206,13 +229,55 @@ eek_gtk_keyboard_real_button_release_event (GtkWidget *self,
GdkEventButton *event)
{
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self);
GList *head;
if (priv->dragged_key) {
g_signal_emit_by_name (priv->dragged_key, "released", priv->keyboard);
priv->dragged_key = NULL;
head = eek_keyboard_get_pressed_keys (priv->keyboard);
for (; head; head = g_list_next (head)) {
g_signal_emit_by_name (head->data, "released", priv->keyboard);
}
return TRUE;
}
static gboolean
eek_gtk_keyboard_real_motion_notify_event (GtkWidget *self,
GdkEventMotion *event)
{
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self);
EekKey *key;
key = eek_renderer_find_key_by_position (priv->renderer,
(gdouble)event->x,
(gdouble)event->y);
if (key) {
GList *head = eek_keyboard_get_pressed_keys (priv->keyboard);
gboolean found = FALSE;
for (; head; head = g_list_next (head)) {
if (head->data == key)
found = TRUE;
else
g_signal_emit_by_name (head->data, "cancelled", priv->keyboard);
}
if (!found)
g_signal_emit_by_name (key, "pressed", priv->keyboard);
}
return TRUE;
}
static void
eek_gtk_keyboard_real_unmap (GtkWidget *self)
{
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self);
if (priv->keyboard) {
GList *head;
head = eek_keyboard_get_pressed_keys (priv->keyboard);
for (; head; head = g_list_next (head)) {
g_signal_emit_by_name (head->data, "released", priv->keyboard);
}
}
return TRUE;
GTK_WIDGET_CLASS (eek_gtk_keyboard_parent_class)->unmap (self);
}
static void
@ -228,6 +293,15 @@ eek_gtk_keyboard_set_keyboard (EekGtkKeyboard *self,
priv->key_released_handler =
g_signal_connect (priv->keyboard, "key-released",
G_CALLBACK(on_key_released), self);
priv->key_locked_handler =
g_signal_connect (priv->keyboard, "key-locked",
G_CALLBACK(on_key_locked), self);
priv->key_unlocked_handler =
g_signal_connect (priv->keyboard, "key-unlocked",
G_CALLBACK(on_key_unlocked), self);
priv->key_cancelled_handler =
g_signal_connect (priv->keyboard, "key-cancelled",
G_CALLBACK(on_key_cancelled), self);
priv->symbol_index_changed_handler =
g_signal_connect (priv->keyboard, "symbol-index-changed",
G_CALLBACK(on_symbol_index_changed), self);
@ -273,16 +347,28 @@ eek_gtk_keyboard_dispose (GObject *object)
priv->key_released_handler))
g_signal_handler_disconnect (priv->keyboard,
priv->key_released_handler);
if (g_signal_handler_is_connected (priv->keyboard,
priv->key_locked_handler))
g_signal_handler_disconnect (priv->keyboard,
priv->key_locked_handler);
if (g_signal_handler_is_connected (priv->keyboard,
priv->key_unlocked_handler))
g_signal_handler_disconnect (priv->keyboard,
priv->key_unlocked_handler);
if (g_signal_handler_is_connected (priv->keyboard,
priv->key_cancelled_handler))
g_signal_handler_disconnect (priv->keyboard,
priv->key_cancelled_handler);
if (g_signal_handler_is_connected (priv->keyboard,
priv->symbol_index_changed_handler))
g_signal_handler_disconnect (priv->keyboard,
priv->symbol_index_changed_handler);
if (priv->dragged_key) {
g_signal_emit_by_name (priv->dragged_key,
"released",
priv->keyboard);
priv->dragged_key = NULL;
GList *head;
head = eek_keyboard_get_pressed_keys (priv->keyboard);
for (; head; head = g_list_next (head)) {
g_signal_emit_by_name (head->data, "released", priv->keyboard);
}
g_object_unref (priv->keyboard);
@ -308,6 +394,7 @@ eek_gtk_keyboard_class_init (EekGtkKeyboardClass *klass)
sizeof (EekGtkKeyboardPrivate));
widget_class->realize = eek_gtk_keyboard_real_realize;
widget_class->unmap = eek_gtk_keyboard_real_unmap;
#if GTK_CHECK_VERSION (2, 91, 2)
widget_class->draw = eek_gtk_keyboard_real_draw;
#else /* GTK_CHECK_VERSION (2, 91, 2) */
@ -318,6 +405,8 @@ eek_gtk_keyboard_class_init (EekGtkKeyboardClass *klass)
eek_gtk_keyboard_real_button_press_event;
widget_class->button_release_event =
eek_gtk_keyboard_real_button_release_event;
widget_class->motion_notify_event =
eek_gtk_keyboard_real_motion_notify_event;
gobject_class->set_property = eek_gtk_keyboard_set_property;
gobject_class->dispose = eek_gtk_keyboard_dispose;
@ -335,12 +424,7 @@ eek_gtk_keyboard_class_init (EekGtkKeyboardClass *klass)
static void
eek_gtk_keyboard_init (EekGtkKeyboard *self)
{
EekGtkKeyboardPrivate *priv;
priv = self->priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self);
priv->renderer = NULL;
priv->keyboard = NULL;
priv->dragged_key = NULL;
self->priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self);
}
/**
@ -366,15 +450,26 @@ color_from_gdk_color (GdkColor *gdk_color)
}
static void
magnify_bounds (EekBounds *bounds, EekBounds *large_bounds, gdouble scale)
magnify_bounds (GtkWidget *self,
EekBounds *bounds,
EekBounds *large_bounds,
gdouble scale)
{
GtkAllocation allocation;
gdouble x, y;
g_assert (scale >= 1.0);
gtk_widget_get_allocation (self, &allocation);
large_bounds->width = bounds->width * scale;
large_bounds->height = bounds->height * scale;
large_bounds->x = bounds->x - (large_bounds->width - bounds->width) / 2;
large_bounds->y = bounds->y - (large_bounds->height - bounds->height) / 2;
x = bounds->x - (large_bounds->width - bounds->width) / 2;
y = bounds->y - large_bounds->height;
large_bounds->x = CLAMP(x, 0, allocation.width - large_bounds->width);
large_bounds->y = CLAMP(y, 0, allocation.height - large_bounds->height);
}
static void
@ -388,10 +483,63 @@ render_pressed_key (GtkWidget *widget,
cr = gdk_cairo_create (GDK_DRAWABLE (gtk_widget_get_window (widget)));
eek_renderer_get_key_bounds (priv->renderer, key, &bounds, TRUE);
magnify_bounds (&bounds, &large_bounds, 1.5);
magnify_bounds (widget, &bounds, &large_bounds, 1.5);
cairo_save (cr);
cairo_translate (cr, bounds.x, bounds.y);
eek_renderer_render_key (priv->renderer, cr, key, 1.0, TRUE);
cairo_restore (cr);
cairo_save (cr);
cairo_translate (cr, large_bounds.x, large_bounds.y);
eek_renderer_render_key (priv->renderer, cr, key, 1.5, TRUE);
cairo_restore (cr);
cairo_destroy (cr);
}
static void
render_locked_key (GtkWidget *widget,
EekKey *key)
{
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(widget);
EekBounds bounds;
cairo_t *cr;
cr = gdk_cairo_create (GDK_DRAWABLE (gtk_widget_get_window (widget)));
eek_renderer_get_key_bounds (priv->renderer, key, &bounds, TRUE);
cairo_translate (cr, bounds.x, bounds.y);
eek_renderer_render_key (priv->renderer, cr, key, 1.0, TRUE);
cairo_destroy (cr);
}
static void
render_released_key (GtkWidget *widget,
EekKey *key)
{
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(widget);
EekBounds bounds, large_bounds;
cairo_t *cr;
cr = gdk_cairo_create (GDK_DRAWABLE (gtk_widget_get_window (widget)));
eek_renderer_get_key_bounds (priv->renderer, key, &bounds, TRUE);
magnify_bounds (widget, &bounds, &large_bounds, 2.0);
cairo_rectangle (cr,
large_bounds.x,
large_bounds.y,
large_bounds.width,
large_bounds.height);
cairo_rectangle (cr,
bounds.x,
bounds.y,
bounds.width,
bounds.height);
cairo_clip (cr);
eek_renderer_render_keyboard (priv->renderer, cr);
cairo_destroy (cr);
}
@ -408,6 +556,14 @@ on_key_pressed (EekKeyboard *keyboard,
return;
render_pressed_key (widget, key);
#if HAVE_LIBCANBERRA
ca_gtk_play_for_widget (widget, 0,
CA_PROP_EVENT_ID, "button-pressed",
CA_PROP_EVENT_DESCRIPTION, "virtual key pressed",
CA_PROP_APPLICATION_ID, "org.fedorahosted.Eekboard",
NULL);
#endif
}
static void
@ -417,27 +573,65 @@ on_key_released (EekKeyboard *keyboard,
{
GtkWidget *widget = user_data;
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(widget);
cairo_t *cr;
EekBounds bounds, large_bounds;
/* renderer may have not been set yet if the widget is a popup */
if (!priv->renderer)
return;
cr = gdk_cairo_create (GDK_DRAWABLE (gtk_widget_get_window (widget)));
render_released_key (widget, key);
eek_renderer_get_key_bounds (priv->renderer, key, &bounds, TRUE);
magnify_bounds (&bounds, &large_bounds, 2.0);
cairo_rectangle (cr,
large_bounds.x,
large_bounds.y,
large_bounds.width,
large_bounds.height);
cairo_clip (cr);
#if HAVE_LIBCANBERRA
ca_gtk_play_for_widget (widget, 0,
CA_PROP_EVENT_ID, "button-released",
CA_PROP_EVENT_DESCRIPTION, "virtual key pressed",
CA_PROP_APPLICATION_ID, "org.fedorahosted.Eekboard",
NULL);
#endif
}
eek_renderer_render_keyboard (priv->renderer, cr);
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
cairo_destroy (cr);
static void
on_key_cancelled (EekKeyboard *keyboard,
EekKey *key,
gpointer user_data)
{
GtkWidget *widget = user_data;
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(widget);
/* renderer may have not been set yet if the widget is a popup */
if (!priv->renderer)
return;
render_released_key (widget, key);
}
static void
on_key_locked (EekKeyboard *keyboard,
EekKey *key,
gpointer user_data)
{
GtkWidget *widget = user_data;
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(widget);
/* renderer may have not been set yet if the widget is a popup */
if (!priv->renderer)
return;
render_locked_key (widget, key);
}
static void
on_key_unlocked (EekKeyboard *keyboard,
EekKey *key,
gpointer user_data)
{
GtkWidget *widget = user_data;
EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(widget);
/* renderer may have not been set yet if the widget is a popup */
if (!priv->renderer)
return;
render_released_key (widget, key);
}
static void

View File

@ -51,58 +51,27 @@ pixbuf_to_cairo_surface (GdkPixbuf *pixbuf)
return surface;
}
static void
eek_gtk_renderer_real_render_key_icon (EekRenderer *self,
cairo_t *cr,
EekKey *key,
gdouble scale,
gboolean rotate)
static cairo_surface_t *
eek_gtk_renderer_real_get_icon_surface (EekRenderer *self,
const gchar *icon_name,
gint size)
{
EekBounds bounds;
EekSymbol *symbol;
const gchar *icon_name;
GdkPixbuf *pixbuf;
cairo_surface_t *surface;
GError *error;
gint width, height;
symbol = eek_key_get_symbol_with_fallback (key, 0, 0);
g_return_if_fail (symbol);
icon_name = eek_symbol_get_icon_name (symbol);
g_return_if_fail (icon_name);
eek_element_get_bounds (EEK_ELEMENT(key), &bounds);
bounds.width *= scale;
bounds.height *= scale;
cairo_surface_t *surface;
error = NULL;
pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
icon_name,
MIN(bounds.width, bounds.height),
size,
0,
&error);
g_return_if_fail (pixbuf);
if (pixbuf == NULL)
return NULL;
width = gdk_pixbuf_get_width (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
if (bounds.width * height < bounds.height * width)
scale = bounds.width / width;
else
scale = bounds.height / height;
cairo_save (cr);
cairo_translate (cr,
(bounds.width - width * scale) / 2,
(bounds.height - height * scale) / 2);
eek_renderer_apply_transformation_for_key (self, cr, key, scale, rotate);
surface = pixbuf_to_cairo_surface (pixbuf);
g_object_unref (pixbuf);
cairo_set_source_surface (cr, surface, 0.0, 0.0);
cairo_paint (cr);
cairo_restore (cr);
return surface;
}
static void
@ -110,7 +79,7 @@ eek_gtk_renderer_class_init (EekGtkRendererClass *klass)
{
EekRendererClass *renderer_class = EEK_RENDERER_CLASS (klass);
renderer_class->render_key_icon = eek_gtk_renderer_real_render_key_icon;
renderer_class->get_icon_surface = eek_gtk_renderer_real_get_icon_surface;
}
static void

View File

@ -39,7 +39,6 @@
#include "eek-section.h"
#include "eek-keyboard.h"
#include "eek-symbol.h"
#include "eek-serializable.h"
enum {
PROP_0,
@ -54,16 +53,15 @@ enum {
enum {
PRESSED,
RELEASED,
LOCKED,
UNLOCKED,
CANCELLED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0, };
static void eek_serializable_iface_init (EekSerializableIface *iface);
G_DEFINE_TYPE_WITH_CODE (EekKey, eek_key, EEK_TYPE_ELEMENT,
G_IMPLEMENT_INTERFACE (EEK_TYPE_SERIALIZABLE,
eek_serializable_iface_init));
G_DEFINE_TYPE (EekKey, eek_key, EEK_TYPE_ELEMENT);
#define EEK_KEY_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEK_TYPE_KEY, EekKeyPrivate))
@ -77,106 +75,9 @@ struct _EekKeyPrivate
gint row;
gulong oref;
gboolean is_pressed;
gboolean is_locked;
};
static EekSerializableIface *eek_key_parent_serializable_iface;
static GVariant *
_g_variant_new_symbol_matrix (EekSymbolMatrix *symbol_matrix)
{
GVariantBuilder builder, array;
gint i, num_symbols = symbol_matrix->num_groups * symbol_matrix->num_levels;
g_variant_builder_init (&builder, G_VARIANT_TYPE ("(iiv)"));
g_variant_builder_add (&builder, "i", symbol_matrix->num_groups);
g_variant_builder_add (&builder, "i", symbol_matrix->num_levels);
g_variant_builder_init (&array, G_VARIANT_TYPE ("av"));
for (i = 0; i < num_symbols; i++) {
GVariant *symbol = eek_serializable_serialize
(EEK_SERIALIZABLE(symbol_matrix->data[i]));
g_variant_builder_add (&array, "v", symbol);
}
g_variant_builder_add (&builder, "v", g_variant_builder_end (&array));
return g_variant_builder_end (&builder);
}
static EekSymbolMatrix *
_g_variant_get_symbol_matrix (GVariant *variant)
{
gint num_groups, num_levels, i;
EekSymbolMatrix *symbol_matrix;
GVariant *array, *child;
GVariantIter iter;
g_variant_get_child (variant, 0, "i", &num_groups);
g_variant_get_child (variant, 1, "i", &num_levels);
symbol_matrix = eek_symbol_matrix_new (num_groups, num_levels);
g_variant_get_child (variant, 2, "v", &array);
g_variant_iter_init (&iter, array);
for (i = 0; i < num_groups * num_levels; i++) {
EekSerializable *serializable;
if (!g_variant_iter_next (&iter, "v", &child)) {
eek_symbol_matrix_free (symbol_matrix);
g_return_val_if_reached (NULL);
}
serializable = eek_serializable_deserialize (child);
symbol_matrix->data[i] = EEK_SYMBOL(serializable);
}
return symbol_matrix;
}
static void
eek_key_real_serialize (EekSerializable *self,
GVariantBuilder *builder)
{
EekKeyPrivate *priv = EEK_KEY_GET_PRIVATE(self);
eek_key_parent_serializable_iface->serialize (self, builder);
g_variant_builder_add (builder, "u", priv->keycode);
g_variant_builder_add (builder, "v",
_g_variant_new_symbol_matrix (priv->symbol_matrix));
g_variant_builder_add (builder, "i", priv->column);
g_variant_builder_add (builder, "i", priv->row);
g_variant_builder_add (builder, "u", priv->oref);
}
static gsize
eek_key_real_deserialize (EekSerializable *self,
GVariant *variant,
gsize index)
{
EekKeyPrivate *priv = EEK_KEY_GET_PRIVATE(self);
GVariant *symbol_matrix;
index = eek_key_parent_serializable_iface->deserialize (self,
variant,
index);
g_variant_get_child (variant, index++, "u", &priv->keycode);
g_variant_get_child (variant, index++, "v", &symbol_matrix);
eek_symbol_matrix_free (priv->symbol_matrix);
priv->symbol_matrix = _g_variant_get_symbol_matrix (symbol_matrix);
g_variant_get_child (variant, index++, "i", &priv->column);
g_variant_get_child (variant, index++, "i", &priv->row);
g_variant_get_child (variant, index++, "u", &priv->oref);
return index;
}
static void
eek_serializable_iface_init (EekSerializableIface *iface)
{
eek_key_parent_serializable_iface =
g_type_interface_peek_parent (iface);
iface->serialize = eek_key_real_serialize;
iface->deserialize = eek_key_real_deserialize;
}
static void
eek_key_real_set_keycode (EekKey *self, guint keycode)
{
@ -254,6 +155,13 @@ eek_key_real_is_pressed (EekKey *self)
return priv->is_pressed;
}
static gboolean
eek_key_real_is_locked (EekKey *self)
{
EekKeyPrivate *priv = EEK_KEY_GET_PRIVATE(self);
return priv->is_locked;
}
static void
eek_key_real_pressed (EekKey *self)
{
@ -276,6 +184,39 @@ eek_key_real_released (EekKey *self)
#endif
}
static void
eek_key_real_locked (EekKey *self)
{
EekKeyPrivate *priv = EEK_KEY_GET_PRIVATE(self);
priv->is_locked = TRUE;
#if DEBUG
g_debug ("locked %X", eek_key_get_keycode (self));
#endif
}
static void
eek_key_real_unlocked (EekKey *self)
{
EekKeyPrivate *priv = EEK_KEY_GET_PRIVATE(self);
priv->is_locked = FALSE;
#if DEBUG
g_debug ("unlocked %X", eek_key_get_keycode (self));
#endif
}
static void
eek_key_real_cancelled (EekKey *self)
{
EekKeyPrivate *priv = EEK_KEY_GET_PRIVATE(self);
priv->is_pressed = FALSE;
#if DEBUG
g_debug ("cancelled %X", eek_key_get_keycode (self));
#endif
}
static void
eek_key_finalize (GObject *object)
{
@ -374,6 +315,7 @@ eek_key_class_init (EekKeyClass *klass)
klass->set_oref = eek_key_real_set_oref;
klass->get_oref = eek_key_real_get_oref;
klass->is_pressed = eek_key_real_is_pressed;
klass->is_locked = eek_key_real_is_locked;
gobject_class->set_property = eek_key_set_property;
gobject_class->get_property = eek_key_get_property;
@ -382,6 +324,9 @@ eek_key_class_init (EekKeyClass *klass)
/* signals */
klass->pressed = eek_key_real_pressed;
klass->released = eek_key_real_released;
klass->locked = eek_key_real_locked;
klass->unlocked = eek_key_real_unlocked;
klass->cancelled = eek_key_real_cancelled;
/**
* EekKey:keycode:
@ -478,6 +423,59 @@ eek_key_class_init (EekKeyClass *klass)
NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
/**
* EekKey::locked:
* @key: an #EekKey
*
* The ::locked signal is emitted each time @key is shifted to
* the locked state. The class handler runs before signal
* handlers to allow signal handlers to read the status of @key
* with eek_key_is_locked().
*/
signals[LOCKED] =
g_signal_new (I_("locked"),
G_TYPE_FROM_CLASS(gobject_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET(EekKeyClass, locked),
NULL,
NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
/**
* EekKey::unlocked:
* @key: an #EekKey
*
* The ::unlocked signal is emitted each time @key is shifted to
* the unlocked state.
*/
signals[UNLOCKED] =
g_signal_new (I_("unlocked"),
G_TYPE_FROM_CLASS(gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(EekKeyClass, unlocked),
NULL,
NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
/**
* EekKey::cancelled:
* @key: an #EekKey
*
* The ::cancelled signal is emitted each time @key is shifted to
* the cancelled state.
*/
signals[CANCELLED] =
g_signal_new (I_("cancelled"),
G_TYPE_FROM_CLASS(gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(EekKeyClass, cancelled),
NULL,
NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
}
static void
@ -486,10 +484,7 @@ eek_key_init (EekKey *self)
EekKeyPrivate *priv;
priv = self->priv = EEK_KEY_GET_PRIVATE(self);
priv->keycode = 0;
priv->symbol_matrix = eek_symbol_matrix_new (0, 0);
priv->column = priv->row = 0;
priv->oref = 0;
}
/**
@ -545,7 +540,7 @@ eek_key_set_symbol_matrix (EekKey *key,
* @key: an #EekKey
*
* Get the symbol matrix of @key.
* Returns: #EekSymbolMatrix or %NULL
* Returns: (transfer none): #EekSymbolMatrix or %NULL
*/
EekSymbolMatrix *
eek_key_get_symbol_matrix (EekKey *key)
@ -749,3 +744,16 @@ eek_key_is_pressed (EekKey *key)
g_assert (EEK_IS_KEY(key));
return EEK_KEY_GET_CLASS(key)->is_pressed (key);
}
/**
* eek_key_is_locked:
* @key: an #EekKey
*
* Return %TRUE if key is marked as locked.
*/
gboolean
eek_key_is_locked (EekKey *key)
{
g_assert (EEK_IS_KEY(key));
return EEK_KEY_GET_CLASS(key)->is_locked (key);
}

View File

@ -40,6 +40,12 @@ G_BEGIN_DECLS
typedef struct _EekKeyClass EekKeyClass;
typedef struct _EekKeyPrivate EekKeyPrivate;
/**
* EekKey:
*
* The #EekKey structure contains only private data and should only be
* accessed using the provided API.
*/
struct _EekKey
{
/*< private >*/
@ -62,7 +68,11 @@ struct _EekKey
* @get_oref: virtual function for getting outline id of the key
* @pressed: class handler for #EekKey::pressed signal
* @released: class handler for #EekKey::released signal
* @locked: class handler for #EekKey::locked signal
* @unlocked: class handler for #EekKey::unlocked signal
* @cancelled: class handler for #EekKey::cancelled signal
* @is_pressed: virtual function for getting whether the key is pressed
* @is_locked: virtual function for getting whether the key is locked
*/
struct _EekKeyClass
{
@ -90,13 +100,18 @@ struct _EekKeyClass
gboolean (* is_pressed) (EekKey *self);
/* signals */
void (* pressed) (EekKey *key);
void (* released) (EekKey *key);
gboolean (* is_locked) (EekKey *self);
void (* locked) (EekKey *key);
void (* unlocked) (EekKey *key);
void (* cancelled) (EekKey *key);
/*< private >*/
/* padding */
gpointer pdummy[24];
gpointer pdummy[20];
};
GType eek_key_get_type (void) G_GNUC_CONST;
@ -130,6 +145,7 @@ void eek_key_set_oref (EekKey *key,
gulong eek_key_get_oref (EekKey *key);
gboolean eek_key_is_pressed (EekKey *key);
gboolean eek_key_is_locked (EekKey *key);
G_END_DECLS
#endif /* EEK_KEY_H */

View File

@ -35,7 +35,6 @@
#include "eek-section.h"
#include "eek-key.h"
#include "eek-symbol.h"
#include "eek-serializable.h"
#include "eek-enumtypes.h"
enum {
@ -48,26 +47,26 @@ enum {
enum {
KEY_PRESSED,
KEY_RELEASED,
KEY_LOCKED,
KEY_UNLOCKED,
KEY_CANCELLED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0, };
static void eek_serializable_iface_init (EekSerializableIface *iface);
G_DEFINE_TYPE_WITH_CODE (EekKeyboard, eek_keyboard, EEK_TYPE_CONTAINER,
G_IMPLEMENT_INTERFACE (EEK_TYPE_SERIALIZABLE,
eek_serializable_iface_init));
G_DEFINE_TYPE (EekKeyboard, eek_keyboard, EEK_TYPE_CONTAINER);
#define EEK_KEYBOARD_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEK_TYPE_KEYBOARD, EekKeyboardPrivate))
struct _EekKeyboardPrivate
{
EekLayout *layout;
EekModifierBehavior modifier_behavior;
EekModifierType modifiers;
GList *pressed_keys;
GList *locked_keys;
GArray *outline_array;
/* modifiers dynamically assigned at run time */
@ -75,120 +74,6 @@ struct _EekKeyboardPrivate
EekModifierType alt_gr_mask;
};
static EekSerializableIface *eek_keyboard_parent_serializable_iface;
static GVariant *_g_variant_new_outline (EekOutline *outline);
static EekOutline *_g_variant_get_outline (GVariant *variant);
static GVariant *
_g_variant_new_outline (EekOutline *outline)
{
GVariantBuilder builder, array;
gint i;
g_variant_builder_init (&builder, G_VARIANT_TYPE ("(div)"));
g_variant_builder_add (&builder, "d", outline->corner_radius);
g_variant_builder_add (&builder, "i", outline->num_points);
g_variant_builder_init (&array, G_VARIANT_TYPE ("a(dd)"));
for (i = 0; i < outline->num_points; i++)
g_variant_builder_add (&array,
"(dd)",
outline->points[i].x,
outline->points[i].y);
g_variant_builder_add (&builder, "v", g_variant_builder_end (&array));
return g_variant_builder_end (&builder);
}
static EekOutline *
_g_variant_get_outline (GVariant *variant)
{
EekOutline *outline;
GVariant *array;
GVariantIter iter;
gdouble x, y;
gint i;
outline = g_slice_new0 (EekOutline);
g_variant_get_child (variant, 0, "d", &outline->corner_radius);
g_variant_get_child (variant, 1, "i", &outline->num_points);
outline->points = g_slice_alloc0 (sizeof (EekPoint) * outline->num_points);
g_variant_get_child (variant, 2, "v", &array);
g_variant_iter_init (&iter, array);
for (i = 0; i < outline->num_points; i++) {
if (!g_variant_iter_next (&iter, "(dd)", &x, &y)) {
eek_outline_free (outline);
g_return_val_if_reached (NULL);
}
outline->points[i].x = x;
outline->points[i].y = y;
}
return outline;
}
static void
eek_keyboard_real_serialize (EekSerializable *self,
GVariantBuilder *builder)
{
EekKeyboardPrivate *priv = EEK_KEYBOARD_GET_PRIVATE(self);
GVariantBuilder array;
guint i;
eek_keyboard_parent_serializable_iface->serialize (self, builder);
g_variant_builder_init (&array, G_VARIANT_TYPE ("av"));
for (i = 0; i < priv->outline_array->len; i++) {
EekOutline *outline =
eek_keyboard_get_outline (EEK_KEYBOARD(self), i + 1);
g_variant_builder_add (&array, "v",
_g_variant_new_outline (outline));
}
g_variant_builder_add (builder, "v", g_variant_builder_end (&array));
g_variant_builder_add (builder, "u", priv->num_lock_mask);
g_variant_builder_add (builder, "u", priv->alt_gr_mask);
}
static gsize
eek_keyboard_real_deserialize (EekSerializable *self,
GVariant *variant,
gsize index)
{
EekKeyboardPrivate *priv = EEK_KEYBOARD_GET_PRIVATE(self);
GVariant *array, *outline;
GVariantIter iter;
index = eek_keyboard_parent_serializable_iface->deserialize (self,
variant,
index);
g_variant_get_child (variant, index++, "v", &array);
g_variant_iter_init (&iter, array);
while (g_variant_iter_next (&iter, "v", &outline)) {
EekOutline *_outline = _g_variant_get_outline (outline);
g_array_append_val (priv->outline_array, *_outline);
/* don't use eek_outline_free here, so as to keep _outline->points */
g_slice_free (EekOutline, _outline);
}
g_variant_get_child (variant, index++, "u", &priv->num_lock_mask);
g_variant_get_child (variant, index++, "u", &priv->alt_gr_mask);
return index;
}
static void
eek_serializable_iface_init (EekSerializableIface *iface)
{
eek_keyboard_parent_serializable_iface =
g_type_interface_peek_parent (iface);
iface->serialize = eek_keyboard_real_serialize;
iface->deserialize = eek_keyboard_real_deserialize;
}
static void
on_key_pressed (EekSection *section,
EekKey *key,
@ -205,6 +90,30 @@ on_key_released (EekSection *section,
g_signal_emit_by_name (keyboard, "key-released", key);
}
static void
on_key_locked (EekSection *section,
EekKey *key,
EekKeyboard *keyboard)
{
g_signal_emit_by_name (keyboard, "key-locked", key);
}
static void
on_key_unlocked (EekSection *section,
EekKey *key,
EekKeyboard *keyboard)
{
g_signal_emit_by_name (keyboard, "key-unlocked", key);
}
static void
on_key_cancelled (EekSection *section,
EekKey *key,
EekKeyboard *keyboard)
{
g_signal_emit_by_name (keyboard, "key-cancelled", key);
}
static void
on_symbol_index_changed (EekSection *section,
gint group,
@ -322,6 +231,45 @@ set_level_from_modifiers (EekKeyboard *self)
eek_element_set_level (EEK_ELEMENT(self), level);
}
static void
set_modifiers_with_key (EekKeyboard *self,
EekKey *key,
EekModifierType modifiers)
{
EekKeyboardPrivate *priv = EEK_KEYBOARD_GET_PRIVATE(self);
EekModifierType enabled = (priv->modifiers ^ modifiers) & modifiers;
EekModifierType disabled = (priv->modifiers ^ modifiers) & priv->modifiers;
if (enabled != 0) {
if (priv->modifier_behavior != EEK_MODIFIER_BEHAVIOR_NONE) {
EekModifierKey *modifier_key = g_slice_new (EekModifierKey);
modifier_key->modifiers = enabled;
modifier_key->key = key;
priv->locked_keys =
g_list_prepend (priv->locked_keys, modifier_key);
g_signal_emit_by_name (modifier_key->key, "locked");
}
} else {
if (priv->modifier_behavior != EEK_MODIFIER_BEHAVIOR_NONE) {
GList *head;
for (head = priv->locked_keys; head; ) {
EekModifierKey *modifier_key = head->data;
if (modifier_key->modifiers & disabled) {
GList *next = g_list_next (head);
priv->locked_keys =
g_list_remove_link (priv->locked_keys, head);
g_signal_emit_by_name (modifier_key->key, "unlocked");
g_list_free1 (head);
head = next;
} else
head = g_list_next (head);
}
}
}
priv->modifiers = modifiers;
}
static void
eek_keyboard_real_key_pressed (EekKeyboard *self,
EekKey *key)
@ -330,13 +278,15 @@ eek_keyboard_real_key_pressed (EekKeyboard *self,
EekSymbol *symbol;
EekModifierType modifier;
priv->pressed_keys = g_list_prepend (priv->pressed_keys, key);
symbol = eek_key_get_symbol_with_fallback (key, 0, 0);
if (!symbol)
return;
modifier = eek_symbol_get_modifier_mask (symbol);
if (priv->modifier_behavior == EEK_MODIFIER_BEHAVIOR_NONE) {
priv->modifiers |= modifier;
set_modifiers_with_key (self, key, priv->modifiers | modifier);
set_level_from_modifiers (self);
}
}
@ -349,6 +299,8 @@ eek_keyboard_real_key_released (EekKeyboard *self,
EekSymbol *symbol;
EekModifierType modifier;
EEK_KEYBOARD_GET_CLASS (self)->key_cancelled (self, key);
symbol = eek_key_get_symbol_with_fallback (key, 0, 0);
if (!symbol)
return;
@ -356,21 +308,42 @@ eek_keyboard_real_key_released (EekKeyboard *self,
modifier = eek_symbol_get_modifier_mask (symbol);
switch (priv->modifier_behavior) {
case EEK_MODIFIER_BEHAVIOR_NONE:
priv->modifiers &= ~modifier;
set_modifiers_with_key (self, key, priv->modifiers & ~modifier);
break;
case EEK_MODIFIER_BEHAVIOR_LOCK:
priv->modifiers ^= modifier;
break;
case EEK_MODIFIER_BEHAVIOR_LATCH:
if (modifier == priv->alt_gr_mask || modifier == EEK_SHIFT_MASK)
priv->modifiers ^= modifier;
if (modifier)
set_modifiers_with_key (self, key, priv->modifiers ^ modifier);
else
priv->modifiers = (priv->modifiers ^ modifier) & modifier;
set_modifiers_with_key (self, key,
(priv->modifiers ^ modifier) & modifier);
break;
}
set_level_from_modifiers (self);
}
static void
eek_keyboard_real_key_cancelled (EekKeyboard *self,
EekKey *key)
{
EekKeyboardPrivate *priv = EEK_KEYBOARD_GET_PRIVATE(self);
GList *head;
for (head = priv->pressed_keys; head; ) {
EekKey *pressed_key = head->data;
if (pressed_key == key) {
GList *next = g_list_next (head);
priv->pressed_keys =
g_list_remove_link (priv->pressed_keys, head);
g_list_free1 (head);
head = next;
} else
head = g_list_next (head);
}
}
static void
eek_keyboard_dispose (GObject *object)
{
@ -390,6 +363,9 @@ eek_keyboard_finalize (GObject *object)
EekKeyboardPrivate *priv = EEK_KEYBOARD_GET_PRIVATE(object);
gint i;
g_list_free (priv->pressed_keys);
g_list_free (priv->locked_keys);
for (i = 0; i < priv->outline_array->len; i++) {
EekOutline *outline = &g_array_index (priv->outline_array,
EekOutline,
@ -410,6 +386,12 @@ eek_keyboard_real_child_added (EekContainer *self,
G_CALLBACK(on_key_pressed), self);
g_signal_connect (element, "key-released",
G_CALLBACK(on_key_released), self);
g_signal_connect (element, "key-locked",
G_CALLBACK(on_key_locked), self);
g_signal_connect (element, "key-unlocked",
G_CALLBACK(on_key_unlocked), self);
g_signal_connect (element, "key-cancelled",
G_CALLBACK(on_key_cancelled), self);
g_signal_connect (element, "symbol-index-changed",
G_CALLBACK(on_symbol_index_changed), self);
}
@ -420,6 +402,9 @@ eek_keyboard_real_child_removed (EekContainer *self,
{
g_signal_handlers_disconnect_by_func (element, on_key_pressed, self);
g_signal_handlers_disconnect_by_func (element, on_key_released, self);
g_signal_handlers_disconnect_by_func (element, on_key_locked, self);
g_signal_handlers_disconnect_by_func (element, on_key_unlocked, self);
g_signal_handlers_disconnect_by_func (element, on_key_cancelled, self);
}
static void
@ -438,6 +423,7 @@ eek_keyboard_class_init (EekKeyboardClass *klass)
/* signals */
klass->key_pressed = eek_keyboard_real_key_pressed;
klass->key_released = eek_keyboard_real_key_released;
klass->key_cancelled = eek_keyboard_real_key_cancelled;
container_class->child_added = eek_keyboard_real_child_added;
container_class->child_removed = eek_keyboard_real_child_removed;
@ -515,6 +501,66 @@ eek_keyboard_class_init (EekKeyboardClass *klass)
G_TYPE_NONE,
1,
EEK_TYPE_KEY);
/**
* EekKeyboard::key-locked:
* @keyboard: an #EekKeyboard
* @key: an #EekKey
*
* The ::key-locked signal is emitted each time a key in @keyboard
* is shifted to the locked state.
*/
signals[KEY_LOCKED] =
g_signal_new (I_("key-locked"),
G_TYPE_FROM_CLASS(gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(EekKeyboardClass, key_locked),
NULL,
NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE,
1,
EEK_TYPE_KEY);
/**
* EekKeyboard::key-unlocked:
* @keyboard: an #EekKeyboard
* @key: an #EekKey
*
* The ::key-unlocked signal is emitted each time a key in @keyboard
* is shifted to the unlocked state.
*/
signals[KEY_UNLOCKED] =
g_signal_new (I_("key-unlocked"),
G_TYPE_FROM_CLASS(gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(EekKeyboardClass, key_unlocked),
NULL,
NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE,
1,
EEK_TYPE_KEY);
/**
* EekKeyboard::key-cancelled:
* @keyboard: an #EekKeyboard
* @key: an #EekKey
*
* The ::key-cancelled signal is emitted each time a key in @keyboard
* is shifted to the cancelled state.
*/
signals[KEY_CANCELLED] =
g_signal_new (I_("key-cancelled"),
G_TYPE_FROM_CLASS(gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(EekKeyboardClass, key_cancelled),
NULL,
NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE,
1,
EEK_TYPE_KEY);
}
static void
@ -523,11 +569,8 @@ eek_keyboard_init (EekKeyboard *self)
EekKeyboardPrivate *priv;
priv = self->priv = EEK_KEYBOARD_GET_PRIVATE(self);
priv->layout = NULL;
priv->modifier_behavior = EEK_MODIFIER_BEHAVIOR_NONE;
priv->modifiers = 0;
priv->outline_array = g_array_new (FALSE, TRUE, sizeof (EekOutline));
priv->num_lock_mask = 0;
eek_element_set_symbol_index (EEK_ELEMENT(self), 0, 0);
}
@ -748,6 +791,19 @@ eek_keyboard_get_modifier_behavior (EekKeyboard *keyboard)
return priv->modifier_behavior;
}
void
eek_keyboard_set_modifiers (EekKeyboard *keyboard,
EekModifierType modifiers)
{
EekKeyboardPrivate *priv;
g_assert (EEK_IS_KEYBOARD(keyboard));
priv = EEK_KEYBOARD_GET_PRIVATE(keyboard);
priv->modifiers = modifiers;
set_level_from_modifiers (keyboard);
}
/**
* eek_keyboard_get_modifiers:
* @keyboard: an #EekKeyboard
@ -887,3 +943,41 @@ eek_keyboard_get_alt_gr_mask (EekKeyboard *keyboard)
return priv->alt_gr_mask;
}
/**
* eek_keyboard_get_pressed_keys:
* @keyboard: an #EekKeyboard
*
* Get pressed keys.
* Returns: (transfer container) (element-type EekKey): A list of
* pressed keys.
*/
GList *
eek_keyboard_get_pressed_keys (EekKeyboard *keyboard)
{
EekKeyboardPrivate *priv;
g_assert (EEK_IS_KEYBOARD(keyboard));
priv = EEK_KEYBOARD_GET_PRIVATE(keyboard);
return priv->pressed_keys;
}
/**
* eek_keyboard_get_locked_keys:
* @keyboard: an #EekKeyboard
*
* Get locked keys.
* Returns: (transfer container) (element-type EekModifierKey): A list
* of locked keys.
*/
GList *
eek_keyboard_get_locked_keys (EekKeyboard *keyboard)
{
EekKeyboardPrivate *priv;
g_assert (EEK_IS_KEYBOARD(keyboard));
priv = EEK_KEYBOARD_GET_PRIVATE(keyboard);
return priv->locked_keys;
}

View File

@ -63,6 +63,9 @@ struct _EekKeyboard
* keyboard by keycode
* @key_pressed: class handler for #EekKeyboard::key-pressed signal
* @key_released: class handler for #EekKeyboard::key-released signal
* @key_locked: class handler for #EekKeyboard::key-locked signal
* @key_unlocked: class handler for #EekKeyboard::key-unlocked signal
* @key_cancelled: class handler for #EekKeyboard::key-cancelled signal
*/
struct _EekKeyboardClass
{
@ -89,10 +92,35 @@ struct _EekKeyboardClass
/* obsolete members moved to EekElement */
gpointer symbol_index_changed;
/*< public >*/
/* signals */
void (* key_locked) (EekKeyboard *self,
EekKey *key);
void (* key_unlocked) (EekKeyboard *self,
EekKey *key);
void (* key_cancelled) (EekKeyboard *self,
EekKey *key);
/*< private >*/
/* padding */
gpointer pdummy[24];
gpointer pdummy[21];
};
/**
* EekModifierKey:
* @modifiers: an #EekModifierType which @key triggers
* @key: an #EekKey
*
* Entry which associates modifier mask to a key. This is returned by
* eek_keyboard_get_locked_keys().
*/
struct _EekModifierKey {
/*< public >*/
EekModifierType modifiers;
EekKey *key;
};
typedef struct _EekModifierKey EekModifierKey;
GType eek_keyboard_get_type
(void) G_GNUC_CONST;
@ -135,6 +163,9 @@ void eek_keyboard_set_modifier_behavior
EekModifierBehavior modifier_behavior);
EekModifierBehavior eek_keyboard_get_modifier_behavior
(EekKeyboard *keyboard);
void eek_keyboard_set_modifiers
(EekKeyboard *keyboard,
EekModifierType modifiers);
EekModifierType eek_keyboard_get_modifiers
(EekKeyboard *keyboard);
@ -165,5 +196,10 @@ void eek_keyboard_set_alt_gr_mask
EekModifierType eek_keyboard_get_alt_gr_mask
(EekKeyboard *keyboard);
GList *eek_keyboard_get_pressed_keys
(EekKeyboard *keyboard);
GList *eek_keyboard_get_locked_keys
(EekKeyboard *keyboard);
G_END_DECLS
#endif /* EEK_KEYBOARD_H */

View File

@ -208,10 +208,7 @@ eek_keysym_class_init (EekKeysymClass *klass)
static void
eek_keysym_init (EekKeysym *self)
{
EekKeysymPrivate *priv;
priv = self->priv = EEK_KEYSYM_GET_PRIVATE(self);
priv->xkeysym = EEK_INVALID_KEYSYM;
self->priv = EEK_KEYSYM_GET_PRIVATE(self);
}
/**

View File

@ -47,6 +47,12 @@ G_BEGIN_DECLS
typedef struct _EekKeysymClass EekKeysymClass;
typedef struct _EekKeysymPrivate EekKeysymPrivate;
/**
* EekKeysym:
*
* The #EekKeysym structure contains only private data and should only
* be accessed using the provided API.
*/
struct _EekKeysym {
/*< private >*/
EekSymbol parent;
@ -65,7 +71,7 @@ guint eek_keysym_get_xkeysym (EekKeysym *keysym);
EekKeysym *eek_keysym_new_from_name (const gchar *name);
EekKeysym *eek_keysym_new_with_modifier (guint xkeysym,
EekModifierType modifier);
EekModifierType modifier_mask);
G_END_DECLS

View File

@ -87,7 +87,8 @@ static void eek_renderer_real_render_key_label (EekRenderer *self,
static void invalidate (EekRenderer *renderer);
static void render_key (EekRenderer *self,
cairo_t *cr,
EekKey *key);
EekKey *key,
gboolean active);
static void on_symbol_index_changed (EekKeyboard *keyboard,
gint group,
gint level,
@ -117,7 +118,7 @@ create_keyboard_surface_key_callback (EekElement *element,
bounds.width * priv->scale,
bounds.height * priv->scale);
cairo_clip (data->cr);
render_key (data->renderer, data->cr, EEK_KEY(element));
render_key (data->renderer, data->cr, EEK_KEY(element), FALSE);
cairo_restore (data->cr);
}
@ -197,7 +198,8 @@ create_keyboard_surface (EekRenderer *renderer)
static void
render_key_outline (EekRenderer *renderer,
cairo_t *cr,
EekKey *key)
EekKey *key,
gboolean active)
{
EekRendererPrivate *priv = EEK_RENDERER_GET_PRIVATE(renderer);
EekOutline *outline;
@ -215,10 +217,10 @@ render_key_outline (EekRenderer *renderer,
if (oref == 0)
return;
if (eek_key_is_pressed (key))
theme_node = g_object_get_data (G_OBJECT(key), "theme-node-pressed");
else
theme_node = g_object_get_data (G_OBJECT(key), "theme-node");
theme_node = g_object_get_data (G_OBJECT(key),
active ?
"theme-node-pressed" :
"theme-node");
if (theme_node) {
eek_theme_node_get_foreground_color (theme_node, &foreground);
eek_theme_node_get_background_color (theme_node, &background);
@ -428,7 +430,8 @@ calculate_font_size (EekRenderer *renderer,
static void
render_key (EekRenderer *self,
cairo_t *cr,
EekKey *key)
EekKey *key,
gboolean active)
{
EekRendererPrivate *priv = EEK_RENDERER_GET_PRIVATE(self);
EekOutline *outline;
@ -437,13 +440,20 @@ render_key (EekRenderer *self,
gulong oref;
EekSymbol *symbol;
GHashTable *outline_surface_cache;
PangoLayout *layout;
PangoRectangle extents = { 0, };
EekColor foreground;
/* render outline */
eek_element_get_bounds (EEK_ELEMENT(key), &bounds);
bounds.width *= priv->scale;
bounds.height *= priv->scale;
oref = eek_key_get_oref (key);
if (oref == 0)
return;
if (eek_key_is_pressed (key))
if (active)
outline_surface_cache = priv->active_outline_surface_cache;
else
outline_surface_cache = priv->outline_surface_cache;
@ -455,15 +465,19 @@ render_key (EekRenderer *self,
outline_surface =
cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
bounds.width * priv->scale,
bounds.height * priv->scale);
bounds.width,
bounds.height);
cr = cairo_create (outline_surface);
/* blank background */
cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.0);
cairo_paint (cr);
eek_renderer_render_key_outline (self, cr, key, 1.0, 0);
cairo_save (cr);
eek_renderer_apply_transformation_for_key (self, cr, key, 1.0, FALSE);
render_key_outline (self, cr, key, active);
cairo_restore (cr);
cairo_destroy (cr);
g_hash_table_insert (outline_surface_cache,
@ -474,15 +488,46 @@ render_key (EekRenderer *self,
cairo_set_source_surface (cr, outline_surface, 0.0, 0.0);
cairo_paint (cr);
/* render icon (if any) */
symbol = eek_key_get_symbol_with_fallback (key, 0, 0);
if (EEK_RENDERER_GET_CLASS(self)->render_key_icon &&
symbol && eek_symbol_get_icon_name (symbol)) {
eek_renderer_render_key_icon (self, cr, key, 1.0, 0);
} else {
PangoLayout *layout;
PangoRectangle extents = { 0, };
EekColor foreground;
if (!symbol)
return;
if (eek_symbol_get_icon_name (symbol)) {
cairo_surface_t *icon_surface =
eek_renderer_get_icon_surface (self,
eek_symbol_get_icon_name (symbol),
MIN(bounds.width, bounds.height));
if (icon_surface) {
gint width = cairo_image_surface_get_width (icon_surface);
gint height = cairo_image_surface_get_height (icon_surface);
gdouble scale;
if (height * bounds.width / width <= bounds.height)
scale = bounds.width / width;
else if (width * bounds.height / height <= bounds.width)
scale = bounds.height / height;
else {
if (width * bounds.height < height * bounds.width)
scale = width / bounds.width;
else
scale = height / bounds.height;
}
cairo_save (cr);
cairo_translate (cr,
(bounds.width - width * scale) / 2,
(bounds.height - height * scale) / 2);
cairo_rectangle (cr, 0, 0, width, height);
cairo_clip (cr);
cairo_set_source_surface (cr, icon_surface, 0.0, 0.0);
cairo_paint (cr);
cairo_restore (cr);
return;
}
}
/* render label */
layout = pango_cairo_create_layout (cr);
eek_renderer_render_key_label (self, layout, key);
pango_layout_get_extents (layout, NULL, &extents);
@ -490,8 +535,8 @@ render_key (EekRenderer *self,
cairo_save (cr);
cairo_move_to
(cr,
(bounds.width * priv->scale - extents.width / PANGO_SCALE) / 2,
(bounds.height * priv->scale - extents.height / PANGO_SCALE) / 2);
(bounds.width - extents.width / PANGO_SCALE) / 2,
(bounds.height - extents.height / PANGO_SCALE) / 2);
eek_renderer_get_foreground_color (self, EEK_ELEMENT(key), &foreground);
cairo_set_source_rgba (cr,
@ -503,7 +548,6 @@ render_key (EekRenderer *self,
pango_cairo_show_layout (cr, layout);
cairo_restore (cr);
g_object_unref (layout);
}
}
void
@ -625,7 +669,7 @@ eek_renderer_real_render_key_outline (EekRenderer *self,
{
cairo_save (cr);
eek_renderer_apply_transformation_for_key (self, cr, key, scale, rotate);
render_key_outline (self, cr, key);
render_key_outline (self, cr, key, eek_key_is_pressed (key) || eek_key_is_locked (key));
cairo_restore (cr);
}
@ -638,7 +682,7 @@ eek_renderer_real_render_key (EekRenderer *self,
{
cairo_save (cr);
eek_renderer_apply_transformation_for_key (self, cr, key, scale, rotate);
render_key (self, cr, key);
render_key (self, cr, key, eek_key_is_pressed (key) || eek_key_is_locked (key));
cairo_restore (cr);
}
@ -873,8 +917,17 @@ eek_renderer_set_allocation_size (EekRenderer *renderer,
priv->allocation_height = height;
eek_element_get_bounds (EEK_ELEMENT(priv->keyboard), &bounds);
scale = width > height ? height / bounds.height :
width / bounds.width;
if (bounds.height * width / bounds.width <= height)
scale = width / bounds.width;
else if (bounds.width * height / bounds.height <= width)
scale = height / bounds.height;
else {
if (bounds.width * height < bounds.height * width)
scale = bounds.width / width;
else
scale = bounds.height / height;
}
if (scale != priv->scale) {
priv->scale = scale;
@ -1024,22 +1077,19 @@ eek_renderer_render_key_outline (EekRenderer *renderer,
rotate);
}
void
eek_renderer_render_key_icon (EekRenderer *renderer,
cairo_t *cr,
EekKey *key,
gdouble scale,
gboolean rotate)
cairo_surface_t *
eek_renderer_get_icon_surface (EekRenderer *renderer,
const gchar *icon_name,
gint size)
{
g_return_if_fail (EEK_IS_RENDERER(renderer));
g_return_if_fail (EEK_IS_KEY(key));
g_return_if_fail (scale >= 0.0);
EekRendererClass *klass;
EEK_RENDERER_GET_CLASS(renderer)->render_key_icon (renderer,
cr,
key,
scale,
rotate);
g_return_val_if_fail (EEK_IS_RENDERER(renderer), NULL);
klass = EEK_RENDERER_GET_CLASS(renderer);
if (klass->get_icon_surface)
return klass->get_icon_surface (renderer, icon_name, size);
return NULL;
}
void

View File

@ -70,11 +70,9 @@ struct _EekRendererClass
void (* render_keyboard) (EekRenderer *self,
cairo_t *cr);
void (* render_key_icon) (EekRenderer *self,
cairo_t *cr,
EekKey *key,
gdouble scale,
gboolean rotate);
cairo_surface_t *(* get_icon_surface) (EekRenderer *self,
const gchar *icon_name,
gint size);
/*< private >*/
/* padding */
@ -84,7 +82,8 @@ struct _EekRendererClass
GType eek_renderer_get_type (void) G_GNUC_CONST;
EekRenderer *eek_renderer_new (EekKeyboard *keyboard,
PangoContext *pcontext);
void eek_renderer_set_allocation_size (EekRenderer *renderer,
void eek_renderer_set_allocation_size
(EekRenderer *renderer,
gdouble width,
gdouble height);
void eek_renderer_get_size (EekRenderer *renderer,
@ -97,12 +96,14 @@ void eek_renderer_get_key_bounds (EekRenderer *renderer,
gdouble eek_renderer_get_scale (EekRenderer *renderer);
PangoLayout *eek_renderer_create_pango_layout (EekRenderer *renderer);
PangoLayout *eek_renderer_create_pango_layout
(EekRenderer *renderer);
void eek_renderer_render_key_label (EekRenderer *renderer,
PangoLayout *layout,
EekKey *key);
void eek_renderer_render_key_outline (EekRenderer *renderer,
void eek_renderer_render_key_outline
(EekRenderer *renderer,
cairo_t *cr,
EekKey *key,
gdouble scale,
@ -114,11 +115,9 @@ void eek_renderer_render_key (EekRenderer *renderer,
gdouble scale,
gboolean rotate);
void eek_renderer_render_key_icon (EekRenderer *renderer,
cairo_t *cr,
EekKey *key,
gdouble scale,
gboolean rotate);
cairo_surface_t *eek_renderer_get_icon_surface (EekRenderer *renderer,
const gchar *icon_name,
gint size);
void eek_renderer_render_keyboard (EekRenderer *renderer,
cairo_t *cr);
@ -129,10 +128,12 @@ void eek_renderer_set_default_foreground_color
void eek_renderer_set_default_background_color
(EekRenderer *renderer,
const EekColor *color);
void eek_renderer_get_foreground_color (EekRenderer *renderer,
void eek_renderer_get_foreground_color
(EekRenderer *renderer,
EekElement *element,
EekColor *color);
void eek_renderer_get_background_color (EekRenderer *renderer,
void eek_renderer_get_background_color
(EekRenderer *renderer,
EekElement *element,
EekColor *color);
void eek_renderer_get_background_gradient
@ -143,7 +144,8 @@ void eek_renderer_get_background_gradient
EekColor *end);
void eek_renderer_set_border_width (EekRenderer *renderer,
gdouble border_width);
EekKey *eek_renderer_find_key_by_position (EekRenderer *renderer,
EekKey *eek_renderer_find_key_by_position
(EekRenderer *renderer,
gdouble x,
gdouble y);
void eek_renderer_apply_transformation_for_key

View File

@ -37,7 +37,6 @@
#include "eek-section.h"
#include "eek-key.h"
#include "eek-symbol.h"
#include "eek-serializable.h"
enum {
PROP_0,
@ -48,16 +47,15 @@ enum {
enum {
KEY_PRESSED,
KEY_RELEASED,
KEY_LOCKED,
KEY_UNLOCKED,
KEY_CANCELLED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0, };
static void eek_serializable_iface_init (EekSerializableIface *iface);
G_DEFINE_TYPE_WITH_CODE (EekSection, eek_section, EEK_TYPE_CONTAINER,
G_IMPLEMENT_INTERFACE (EEK_TYPE_SERIALIZABLE,
eek_serializable_iface_init));
G_DEFINE_TYPE (EekSection, eek_section, EEK_TYPE_CONTAINER);
#define EEK_SECTION_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEK_TYPE_SECTION, EekSectionPrivate))
@ -77,80 +75,6 @@ struct _EekSectionPrivate
EekModifierType modifiers;
};
static EekSerializableIface *eek_section_parent_serializable_iface;
static GVariant *
_g_variant_new_row (EekRow *row)
{
GVariantBuilder builder;
g_variant_builder_init (&builder, G_VARIANT_TYPE ("(iu)"));
g_variant_builder_add (&builder, "i", row->num_columns);
g_variant_builder_add (&builder, "u", row->orientation);
return g_variant_builder_end (&builder);
}
static EekRow *
_g_variant_get_row (GVariant *variant)
{
EekRow *row = g_slice_new (EekRow);
g_variant_get_child (variant, 0, "i", &row->num_columns);
g_variant_get_child (variant, 1, "u", &row->orientation);
return row;
}
static void
eek_section_real_serialize (EekSerializable *self,
GVariantBuilder *builder)
{
EekSectionPrivate *priv = EEK_SECTION_GET_PRIVATE(self);
GSList *head;
GVariantBuilder array;
eek_section_parent_serializable_iface->serialize (self, builder);
g_variant_builder_add (builder, "i", priv->angle);
g_variant_builder_init (&array, G_VARIANT_TYPE("av"));
for (head = priv->rows; head; head = g_slist_next (head))
g_variant_builder_add (&array, "v", _g_variant_new_row (head->data));
g_variant_builder_add (builder, "v", g_variant_builder_end (&array));
}
static gsize
eek_section_real_deserialize (EekSerializable *self,
GVariant *variant,
gsize index)
{
EekSectionPrivate *priv = EEK_SECTION_GET_PRIVATE(self);
GVariant *array, *child;
GVariantIter iter;
index = eek_section_parent_serializable_iface->deserialize (self,
variant,
index);
g_variant_get_child (variant, index++, "i", &priv->angle);
g_variant_get_child (variant, index++, "v", &array);
g_variant_iter_init (&iter, array);
while (g_variant_iter_next (&iter, "v", &child))
priv->rows = g_slist_prepend (priv->rows, _g_variant_get_row (child));
priv->rows = g_slist_reverse (priv->rows);
return index;
}
static void
eek_serializable_iface_init (EekSerializableIface *iface)
{
eek_section_parent_serializable_iface =
g_type_interface_peek_parent (iface);
iface->serialize = eek_section_real_serialize;
iface->deserialize = eek_section_real_deserialize;
}
static void
eek_section_real_set_angle (EekSection *self,
gint angle)
@ -223,6 +147,27 @@ on_released (EekKey *key,
g_signal_emit_by_name (section, "key-released", key);
}
static void
on_locked (EekKey *key,
EekSection *section)
{
g_signal_emit_by_name (section, "key-locked", key);
}
static void
on_unlocked (EekKey *key,
EekSection *section)
{
g_signal_emit_by_name (section, "key-unlocked", key);
}
static void
on_cancelled (EekKey *key,
EekSection *section)
{
g_signal_emit_by_name (section, "key-cancelled", key);
}
static EekKey *
eek_section_real_create_key (EekSection *self,
gint column,
@ -389,6 +334,9 @@ eek_section_real_child_added (EekContainer *self,
{
g_signal_connect (element, "pressed", G_CALLBACK(on_pressed), self);
g_signal_connect (element, "released", G_CALLBACK(on_released), self);
g_signal_connect (element, "locked", G_CALLBACK(on_locked), self);
g_signal_connect (element, "unlocked", G_CALLBACK(on_unlocked), self);
g_signal_connect (element, "cancelled", G_CALLBACK(on_cancelled), self);
}
static void
@ -397,6 +345,9 @@ eek_section_real_child_removed (EekContainer *self,
{
g_signal_handlers_disconnect_by_func (element, on_pressed, self);
g_signal_handlers_disconnect_by_func (element, on_released, self);
g_signal_handlers_disconnect_by_func (element, on_locked, self);
g_signal_handlers_disconnect_by_func (element, on_unlocked, self);
g_signal_handlers_disconnect_by_func (element, on_cancelled, self);
}
static void
@ -480,17 +431,72 @@ eek_section_class_init (EekSectionClass *klass)
G_TYPE_NONE,
1,
EEK_TYPE_KEY);
/**
* EekSection::key-locked:
* @section: an #EekSection
* @key: an #EekKey
*
* The ::key-locked signal is emitted each time a key in @section
* is shifted to the locked state.
*/
signals[KEY_LOCKED] =
g_signal_new (I_("key-locked"),
G_TYPE_FROM_CLASS(gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(EekSectionClass, key_locked),
NULL,
NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE,
1,
EEK_TYPE_KEY);
/**
* EekSection::key-unlocked:
* @section: an #EekSection
* @key: an #EekKey
*
* The ::key-unlocked signal is emitted each time a key in @section
* is shifted to the unlocked state.
*/
signals[KEY_UNLOCKED] =
g_signal_new (I_("key-unlocked"),
G_TYPE_FROM_CLASS(gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(EekSectionClass, key_unlocked),
NULL,
NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE,
1,
EEK_TYPE_KEY);
/**
* EekSection::key-cancelled:
* @section: an #EekSection
* @key: an #EekKey
*
* The ::key-cancelled signal is emitted each time a key in @section
* is shifted to the cancelled state.
*/
signals[KEY_CANCELLED] =
g_signal_new (I_("key-cancelled"),
G_TYPE_FROM_CLASS(gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(EekSectionClass, key_cancelled),
NULL,
NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE,
1,
EEK_TYPE_KEY);
}
static void
eek_section_init (EekSection *self)
{
EekSectionPrivate *priv;
priv = self->priv = EEK_SECTION_GET_PRIVATE (self);
priv->angle = 0;
priv->rows = NULL;
priv->modifiers = 0;
self->priv = EEK_SECTION_GET_PRIVATE (self);
}
/**

View File

@ -41,6 +41,12 @@ G_BEGIN_DECLS
typedef struct _EekSectionClass EekSectionClass;
typedef struct _EekSectionPrivate EekSectionPrivate;
/**
* EekSection:
*
* The #EekSection structure contains only private data and should
* only be accessed using the provided API.
*/
struct _EekSection
{
/*< private >*/
@ -61,6 +67,9 @@ struct _EekSection
* section by keycode
* @key_pressed: class handler for #EekSection::key-pressed signal
* @key_released: class handler for #EekSection::key-released signal
* @key_locked: class handler for #EekSection::key-locked signal
* @key_unlocked: class handler for #EekSection::key-unlocked signal
* @key_cancelled: class handler for #EekSection::key-cancelled signal
*/
struct _EekSectionClass
{
@ -93,10 +102,16 @@ struct _EekSectionClass
EekKey *key);
void (* key_released) (EekSection *self,
EekKey *key);
void (* key_locked) (EekSection *self,
EekKey *key);
void (* key_unlocked) (EekSection *self,
EekKey *key);
void (* key_cancelled) (EekSection *self,
EekKey *key);
/*< private >*/
/* padding */
gpointer pdummy[22];
gpointer pdummy[19];
};
GType eek_section_get_type (void) G_GNUC_CONST;

View File

@ -20,11 +20,11 @@
/**
* SECTION:eek-serializable
* @short_description: Interface implemented by #EekElement to
* serialize it to #GVariant
* @short_description: Interface which provides object serialization
* into #GVariant
*
* The #EekSerializableIface interface defines serialize/deserialize
* method of #EekElement.
* method.
*/
#ifdef HAVE_CONFIG_H

View File

@ -34,6 +34,7 @@ G_BEGIN_DECLS
*/
struct _EekSymbolMatrix
{
/*< public >*/
gint num_groups;
gint num_levels;
EekSymbol **data;

View File

@ -228,11 +228,7 @@ eek_symbol_init (EekSymbol *self)
EekSymbolPrivate *priv;
priv = self->priv = EEK_SYMBOL_GET_PRIVATE(self);
priv->name = NULL;
priv->label = NULL;
priv->icon_name = NULL;
priv->category = EEK_SYMBOL_CATEGORY_UNKNOWN;
priv->modifier_mask = 0;
}
/**
@ -244,7 +240,7 @@ eek_symbol_init (EekSymbol *self)
EekSymbol *
eek_symbol_new (const gchar *name)
{
return g_object_new (EEK_TYPE_SYMBOL, "name", name);
return g_object_new (EEK_TYPE_SYMBOL, "name", name, NULL);
}
/**

View File

@ -102,9 +102,9 @@ void eek_symbol_set_category (EekSymbol *symbol,
EekSymbolCategory category);
EekSymbolCategory eek_symbol_get_category (EekSymbol *symbol);
EekModifierType eek_symbol_get_modifier_mask
(EekSymbol *keysym);
(EekSymbol *symbol);
void eek_symbol_set_modifier_mask
(EekSymbol *keysym,
(EekSymbol *symbol,
EekModifierType mask);
gboolean eek_symbol_is_modifier (EekSymbol *symbol);
void eek_symbol_set_icon_name (EekSymbol *symbol,

View File

@ -489,11 +489,11 @@ eek_theme_get_property (GObject *object,
/**
* eek_theme_new:
* @application_stylesheet: The highest priority stylesheet, representing application-specific
* @application_stylesheet: (allow-none): The highest priority stylesheet, representing application-specific
* styling; this is associated with the CSS "author" stylesheet, may be %NULL
* @theme_stylesheet: The second priority stylesheet, representing theme-specific styling ;
* @theme_stylesheet: (allow-none): The second priority stylesheet, representing theme-specific styling ;
* this is associated with the CSS "user" stylesheet, may be %NULL
* @default_stylesheet: The lowest priority stylesheet, representing global default styling;
* @default_stylesheet: (allow-none): The lowest priority stylesheet, representing global default styling;
* this is associated with the CSS "user agent" stylesheet, may be %NULL
*
* Return value: the newly created theme object

View File

@ -20,7 +20,8 @@
/**
* SECTION:eek-types
* @short_description: Miscellaneous types
* @title: Miscellaneous Types
* @short_description: Miscellaneous types used in Libeek
*/
#ifdef HAVE_CONFIG_H

View File

@ -159,6 +159,7 @@ typedef struct _EekColor EekColor;
typedef struct _EekPoint EekPoint;
struct _EekPoint
{
/*< public >*/
gdouble x;
gdouble y;
};
@ -180,6 +181,7 @@ void eek_point_rotate (EekPoint *point,
*/
struct _EekBounds
{
/*< public >*/
gdouble x;
gdouble y;
gdouble width;
@ -206,6 +208,7 @@ eek_bounds_long_side (EekBounds *bounds)
*/
struct _EekOutline
{
/*< public >*/
gdouble corner_radius;
EekPoint *points;
gint num_points;
@ -226,6 +229,7 @@ void eek_outline_free (EekOutline *outline);
*/
struct _EekColor
{
/*< public >*/
gdouble red;
gdouble green;
gdouble blue;

View File

@ -457,7 +457,6 @@ eek_xkb_layout_init (EekXkbLayout *self)
EekXkbLayoutPrivate *priv;
priv = self->priv = EEK_XKB_LAYOUT_GET_PRIVATE (self);
memset (&priv->names, 0, sizeof priv->names);
priv->display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
g_return_if_fail (priv->display);

View File

@ -84,11 +84,6 @@ eek_xkl_layout_dispose (GObject *object)
priv->config = NULL;
}
if (priv->engine) {
g_object_unref (priv->engine);
priv->engine = NULL;
}
G_OBJECT_CLASS (eek_xkl_layout_parent_class)->dispose (object);
}

View File

@ -94,9 +94,7 @@ static const gchar *valid_path_list[] = {
"groups/symbols/key/section/keyboard",
"levels/symbols/key/section/keyboard",
"keysym/symbols/key/section/keyboard",
"custom/symbols/key/section/keyboard",
"text/symbols/key/section/keyboard",
"icon/symbols/key/section/keyboard",
"symbol/symbols/key/section/keyboard",
"invalid/symbols/key/section/keyboard",
"index/key/section/keyboard",
"point/outline/keyboard",
@ -229,9 +227,11 @@ start_element_callback (GMarkupParseContext *pcontext,
goto out;
}
if (g_strcmp0 (element_name, "keysym") == 0) {
if (g_strcmp0 (element_name, "symbol") == 0 ||
g_strcmp0 (element_name, "keysym") == 0) {
data->label = g_strdup (label);
data->icon = g_strdup (icon);
if (g_strcmp0 (element_name, "keysym") == 0)
data->keyval = keyval;
}
@ -410,23 +410,32 @@ end_element_callback (GMarkupParseContext *pcontext,
goto out;
}
if (g_strcmp0 (element_name, "symbol") == 0 ||
g_strcmp0 (element_name, "keysym") == 0) {
EekSymbol *symbol;
if (g_strcmp0 (element_name, "keysym") == 0) {
EekKeysym *keysym;
if (data->keyval != EEK_INVALID_KEYSYM) {
if (data->keyval != EEK_INVALID_KEYSYM)
keysym = eek_keysym_new (data->keyval);
//g_debug ("%u %s", data->keyval, eek_symbol_get_label (EEK_SYMBOL(keysym)));
} else
else
keysym = eek_keysym_new_from_name (text);
symbol = EEK_SYMBOL(keysym);
} else {
symbol = eek_symbol_new (text);
eek_symbol_set_category (symbol, EEK_SYMBOL_CATEGORY_KEYNAME);
}
if (data->label) {
eek_symbol_set_label (EEK_SYMBOL(keysym), data->label);
eek_symbol_set_label (symbol, data->label);
g_free (data->label);
}
if (data->icon) {
eek_symbol_set_icon_name (EEK_SYMBOL(keysym), data->icon);
eek_symbol_set_icon_name (symbol, data->icon);
g_free (data->icon);
}
data->symbols = g_slist_prepend (data->symbols, keysym);
data->symbols = g_slist_prepend (data->symbols, symbol);
goto out;
}
@ -676,10 +685,7 @@ eek_xml_layout_class_init (EekXmlLayoutClass *klass)
static void
eek_xml_layout_init (EekXmlLayout *self)
{
EekXmlLayoutPrivate *priv;
priv = self->priv = EEK_XML_LAYOUT_GET_PRIVATE (self);
priv->source = NULL;
self->priv = EEK_XML_LAYOUT_GET_PRIVATE (self);
}
EekLayout *

View File

@ -18,6 +18,7 @@
/**
* SECTION: eek-xml
* @title: XML Conversion Utilities
* @short_description: #EekKeyboard to XML conversion utilities
*/

45
eek/eek.c Normal file
View File

@ -0,0 +1,45 @@
/*
* Copyright (C) 2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2011 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
/**
* SECTION:eek
* @title: Library Initialization
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#include "eek.h"
/**
* eek_init:
*
* Initialize the Libeek library. This must be called before using
* functions provided by Libeek.
*/
void
eek_init (void)
{
g_type_init ();
g_type_class_ref (EEK_TYPE_SYMBOL);
g_type_class_ref (EEK_TYPE_KEYSYM);
}

View File

@ -32,4 +32,6 @@
#include "eek-serializable.h"
#include "eek-theme.h"
void eek_init (void);
#endif /* EEK_H */

View File

@ -30,9 +30,9 @@
0xFF9E "Ins" EEK_SYMBOL_CATEGORY_FUNCTION
0xFF9F "Del" EEK_SYMBOL_CATEGORY_FUNCTION
# aliases
0xFE03 "AltGr" EEK_SYMBOL_CATEGORY_KEYNAME
0xFE04 "AltGr" EEK_SYMBOL_CATEGORY_KEYNAME
0xFE05 "AltGr" EEK_SYMBOL_CATEGORY_KEYNAME
0xFE03 "" EEK_SYMBOL_CATEGORY_KEYNAME
0xFE04 "" EEK_SYMBOL_CATEGORY_KEYNAME
0xFE05 "" EEK_SYMBOL_CATEGORY_KEYNAME
0xFE08 "Next" EEK_SYMBOL_CATEGORY_KEYNAME
0xFE0A "Prev" EEK_SYMBOL_CATEGORY_KEYNAME
0xFF08 "←" EEK_SYMBOL_CATEGORY_KEYNAME

View File

@ -19,16 +19,42 @@
lib_LTLIBRARIES = libeekboard.la
libeekboard_headers = \
eekboard.h \
eekboard-eekboard.h \
eekboard-context.h
eekboard-service.h \
eekboard-context-service.h \
eekboard-client.h \
eekboard-context.h \
eekboard-xklutil.h
libeekboard_private_headers = \
eekboard-marshalers.h
libeekboard_sources = \
eekboard-eekboard.c \
eekboard-context.c
eekboard-service.c \
eekboard-context-service.c \
eekboard-client.c \
eekboard-context.c \
eekboard-xklutil.c
libeekboard_la_SOURCES = $(libeekboard_sources)
libeekboard_la_CFLAGS = -DEEKBOARD_COMPILATION=1 -I$(top_srcdir) $(GIO2_CFLAGS)
libeekboard_la_LIBADD = $(top_builddir)/eek/libeek.la $(GIO2_LIBS)
libeekboard_marshalers_sources = \
eekboard-marshalers.c \
eekboard-marshalers.h
BUILT_SOURCES = \
$(libeekboard_marshalers_sources)
libeekboard_la_SOURCES = \
$(libeekboard_sources) \
eekboard-marshalers.c
libeekboard_la_CFLAGS = \
-DEEKBOARD_COMPILATION=1 \
-DKEYBOARDDIR=\"$(pkgdatadir)/keyboards\" \
-I$(top_srcdir) \
$(GIO2_CFLAGS) \
$(LIBXKLAVIER_CFLAGS)
libeekboard_la_LIBADD = \
$(top_builddir)/eek/libeek.la \
$(top_builddir)/eek/libeek-xkl.la \
$(GIO2_LIBS) \
$(LIBXKLAVIER_LIBS)
eekboarddir = $(includedir)/eekboard-$(EEK_API_VERSION)/eekboard
eekboard_HEADERS = $(libeekboard_headers)
@ -37,10 +63,23 @@ pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = \
eekboard-$(EEK_API_VERSION).pc
DISTCLEANFILES = \
$(BUILT_SOURCES) \
$(pkgconfig_DATA)
CLEANFILES =
EXTRA_DIST = eekboard-marshalers.list
# gen marshal
eekboard-marshalers.h: eekboard-marshalers.list
$(AM_V_GEN) $(GLIB_GENMARSHAL) --prefix=_eekboard_marshal $(srcdir)/eekboard-marshalers.list --header --internal > $@.tmp && \
mv $@.tmp $@
eekboard-marshalers.c: eekboard-marshalers.list eekboard-marshalers.h
$(AM_V_GEN) (echo "#include \"eekboard-marshalers.h\""; \
$(GLIB_GENMARSHAL) --prefix=_eekboard_marshal $(srcdir)/eekboard-marshalers.list --body --internal) > $@.tmp && \
mv $@.tmp $@
-include $(INTROSPECTION_MAKEFILE)
INTROSPECTION_GIRS =
INTROSPECTION_SCANNER_ARGS = --add-include-path=$(builddir) --add-include-path=$(top_builddir)/eek

View File

@ -17,17 +17,17 @@
*/
/**
* SECTION:eekboard-eekboard
* @short_description: D-Bus proxy of eekboard-server
* SECTION:eekboard-client
* @short_description: client interface of eekboard service
*
* The #EekboardEekboard class provides a client side access to eekboard-server.
* The #EekboardClient class provides a client side access to eekboard-server.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#include "eekboard/eekboard-eekboard.h"
#include "eekboard/eekboard-client.h"
enum {
DESTROYED,
@ -36,53 +36,53 @@ enum {
static guint signals[LAST_SIGNAL] = { 0, };
G_DEFINE_TYPE (EekboardEekboard, eekboard_eekboard, G_TYPE_DBUS_PROXY);
G_DEFINE_TYPE (EekboardClient, eekboard_client, G_TYPE_DBUS_PROXY);
#define EEKBOARD_EEKBOARD_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEKBOARD_TYPE_EEKBOARD, EekboardEekboardPrivate))
#define EEKBOARD_CLIENT_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEKBOARD_TYPE_CLIENT, EekboardClientPrivate))
struct _EekboardEekboardPrivate
struct _EekboardClientPrivate
{
GHashTable *context_hash;
};
static void
eekboard_eekboard_real_destroyed (EekboardEekboard *self)
eekboard_client_real_destroyed (EekboardClient *self)
{
EekboardEekboardPrivate *priv = EEKBOARD_EEKBOARD_GET_PRIVATE(self);
EekboardClientPrivate *priv = EEKBOARD_CLIENT_GET_PRIVATE(self);
// g_debug ("eekboard_eekboard_real_destroyed");
// g_debug ("eekboard_client_real_destroyed");
g_hash_table_remove_all (priv->context_hash);
}
static void
eekboard_eekboard_dispose (GObject *object)
eekboard_client_dispose (GObject *object)
{
EekboardEekboardPrivate *priv = EEKBOARD_EEKBOARD_GET_PRIVATE(object);
EekboardClientPrivate *priv = EEKBOARD_CLIENT_GET_PRIVATE(object);
if (priv->context_hash) {
g_hash_table_destroy (priv->context_hash);
priv->context_hash = NULL;
}
G_OBJECT_CLASS (eekboard_eekboard_parent_class)->dispose (object);
G_OBJECT_CLASS (eekboard_client_parent_class)->dispose (object);
}
static void
eekboard_eekboard_class_init (EekboardEekboardClass *klass)
eekboard_client_class_init (EekboardClientClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (gobject_class,
sizeof (EekboardEekboardPrivate));
sizeof (EekboardClientPrivate));
klass->destroyed = eekboard_eekboard_real_destroyed;
klass->destroyed = eekboard_client_real_destroyed;
gobject_class->dispose = eekboard_eekboard_dispose;
gobject_class->dispose = eekboard_client_dispose;
/**
* EekboardEekboard::destroyed:
* @eekboard: an #EekboardEekboard
* EekboardClient::destroyed:
* @eekboard: an #EekboardClient
*
* The ::destroyed signal is emitted each time the name of remote
* end is vanished.
@ -91,7 +91,7 @@ eekboard_eekboard_class_init (EekboardEekboardClass *klass)
g_signal_new (I_("destroyed"),
G_TYPE_FROM_CLASS(gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(EekboardEekboardClass, destroyed),
G_STRUCT_OFFSET(EekboardClientClass, destroyed),
NULL,
NULL,
g_cclosure_marshal_VOID__VOID,
@ -100,11 +100,11 @@ eekboard_eekboard_class_init (EekboardEekboardClass *klass)
}
static void
eekboard_eekboard_init (EekboardEekboard *self)
eekboard_client_init (EekboardClient *self)
{
EekboardEekboardPrivate *priv;
EekboardClientPrivate *priv;
priv = self->priv = EEKBOARD_EEKBOARD_GET_PRIVATE(self);
priv = self->priv = EEKBOARD_CLIENT_GET_PRIVATE(self);
priv->context_hash =
g_hash_table_new_full (g_str_hash,
g_str_equal,
@ -117,19 +117,19 @@ eekboard_name_vanished_callback (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
EekboardEekboard *eekboard = user_data;
g_signal_emit_by_name (eekboard, "destroyed", NULL);
EekboardClient *client = user_data;
g_signal_emit_by_name (client, "destroyed", NULL);
}
/**
* eekboard_eekboard_new:
* eekboard_client_new:
* @connection: a #GDBusConnection
* @cancellable: a #GCancellable
*
* Create a D-Bus proxy of eekboard-eekboard.
* Create a client.
*/
EekboardEekboard *
eekboard_eekboard_new (GDBusConnection *connection,
EekboardClient *
eekboard_client_new (GDBusConnection *connection,
GCancellable *cancellable)
{
GInitable *initable;
@ -139,19 +139,19 @@ eekboard_eekboard_new (GDBusConnection *connection,
error = NULL;
initable =
g_initable_new (EEKBOARD_TYPE_EEKBOARD,
g_initable_new (EEKBOARD_TYPE_CLIENT,
cancellable,
&error,
"g-connection", connection,
"g-name", "org.fedorahosted.Eekboard.Server",
"g-interface-name", "org.fedorahosted.Eekboard.Server",
"g-object-path", "/org/fedorahosted/Eekboard/Server",
"g-name", "org.fedorahosted.Eekboard",
"g-interface-name", "org.fedorahosted.Eekboard",
"g-object-path", "/org/fedorahosted/Eekboard",
NULL);
if (initable != NULL) {
EekboardEekboard *eekboard = EEKBOARD_EEKBOARD (initable);
gchar *name_owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY(eekboard));
EekboardClient *client = EEKBOARD_CLIENT (initable);
gchar *name_owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY(client));
if (name_owner == NULL) {
g_object_unref (eekboard);
g_object_unref (client);
return NULL;
}
@ -161,11 +161,11 @@ eekboard_eekboard_new (GDBusConnection *connection,
G_BUS_NAME_WATCHER_FLAGS_NONE,
NULL,
eekboard_name_vanished_callback,
eekboard,
client,
NULL);
g_free (name_owner);
return eekboard;
return client;
}
return NULL;
}
@ -174,16 +174,16 @@ static void
on_context_destroyed (EekboardContext *context,
gpointer user_data)
{
EekboardEekboard *eekboard = user_data;
EekboardEekboardPrivate *priv = EEKBOARD_EEKBOARD_GET_PRIVATE(eekboard);
EekboardClient *client = user_data;
EekboardClientPrivate *priv = EEKBOARD_CLIENT_GET_PRIVATE(client);
g_hash_table_remove (priv->context_hash,
g_dbus_proxy_get_object_path (G_DBUS_PROXY(context)));
}
/**
* eekboard_eekboard_create_context:
* @eekboard: an #EekboardEekboard
* eekboard_client_create_context:
* @eekboard: an #EekboardClient
* @client_name: name of the client
* @cancellable: a #GCancellable
*
@ -192,22 +192,22 @@ on_context_destroyed (EekboardContext *context,
* Return value: (transfer full): a newly created #EekboardContext.
*/
EekboardContext *
eekboard_eekboard_create_context (EekboardEekboard *eekboard,
eekboard_client_create_context (EekboardClient *client,
const gchar *client_name,
GCancellable *cancellable)
{
GVariant *variant;
const gchar *object_path;
EekboardContext *context;
EekboardEekboardPrivate *priv;
EekboardClientPrivate *priv;
GError *error;
GDBusConnection *connection;
g_assert (EEKBOARD_IS_EEKBOARD(eekboard));
g_assert (EEKBOARD_IS_CLIENT(client));
g_assert (client_name);
error = NULL;
variant = g_dbus_proxy_call_sync (G_DBUS_PROXY(eekboard),
variant = g_dbus_proxy_call_sync (G_DBUS_PROXY(client),
"CreateContext",
g_variant_new ("(s)", client_name),
G_DBUS_CALL_FLAGS_NONE,
@ -218,19 +218,19 @@ eekboard_eekboard_create_context (EekboardEekboard *eekboard,
return NULL;
g_variant_get (variant, "(&s)", &object_path);
connection = g_dbus_proxy_get_connection (G_DBUS_PROXY(eekboard));
connection = g_dbus_proxy_get_connection (G_DBUS_PROXY(client));
context = eekboard_context_new (connection, object_path, cancellable);
if (!context) {
g_variant_unref (variant);
return NULL;
}
priv = EEKBOARD_EEKBOARD_GET_PRIVATE(eekboard);
priv = EEKBOARD_CLIENT_GET_PRIVATE(client);
g_hash_table_insert (priv->context_hash,
g_strdup (object_path),
g_object_ref (context));
g_signal_connect (context, "destroyed",
G_CALLBACK(on_context_destroyed), eekboard);
G_CALLBACK(on_context_destroyed), client);
return context;
}
@ -250,33 +250,33 @@ eekboard_async_ready_callback (GObject *source_object,
}
/**
* eekboard_eekboard_push_context:
* @eekboard: an #EekboardEekboard
* eekboard_client_push_context:
* @eekboard: an #EekboardClient
* @context: an #EekboardContext
* @cancellable: a #GCancellable
*
* Enable the input context @context and disable the others.
*/
void
eekboard_eekboard_push_context (EekboardEekboard *eekboard,
eekboard_client_push_context (EekboardClient *client,
EekboardContext *context,
GCancellable *cancellable)
{
EekboardEekboardPrivate *priv;
EekboardClientPrivate *priv;
const gchar *object_path;
g_return_if_fail (EEKBOARD_IS_EEKBOARD(eekboard));
g_return_if_fail (EEKBOARD_IS_CLIENT(client));
g_return_if_fail (EEKBOARD_IS_CONTEXT(context));
object_path = g_dbus_proxy_get_object_path (G_DBUS_PROXY(context));
priv = EEKBOARD_EEKBOARD_GET_PRIVATE(eekboard);
priv = EEKBOARD_CLIENT_GET_PRIVATE(client);
context = g_hash_table_lookup (priv->context_hash, object_path);
if (!context)
return;
eekboard_context_set_enabled (context, TRUE);
g_dbus_proxy_call (G_DBUS_PROXY(eekboard),
g_dbus_proxy_call (G_DBUS_PROXY(client),
"PushContext",
g_variant_new ("(s)", object_path),
G_DBUS_CALL_FLAGS_NONE,
@ -287,19 +287,19 @@ eekboard_eekboard_push_context (EekboardEekboard *eekboard,
}
/**
* eekboard_eekboard_pop_context:
* @eekboard: an #EekboardEekboard
* eekboard_client_pop_context:
* @eekboard: an #EekboardClient
* @cancellable: a #GCancellable
*
* Disable the current input context and enable the previous one.
*/
void
eekboard_eekboard_pop_context (EekboardEekboard *eekboard,
eekboard_client_pop_context (EekboardClient *client,
GCancellable *cancellable)
{
g_return_if_fail (EEKBOARD_IS_EEKBOARD(eekboard));
g_return_if_fail (EEKBOARD_IS_CLIENT(client));
g_dbus_proxy_call (G_DBUS_PROXY(eekboard),
g_dbus_proxy_call (G_DBUS_PROXY(client),
"PopContext",
NULL,
G_DBUS_CALL_FLAGS_NONE,
@ -310,30 +310,29 @@ eekboard_eekboard_pop_context (EekboardEekboard *eekboard,
}
/**
* eekboard_eekboard_destroy_context:
* @eekboard: an #EekboardEekboard
* eekboard_client_destroy_context:
* @eekboard: an #EekboardClient
* @context: an #EekboardContext
* @cancellable: a #GCancellable
*
* Remove @context from @eekboard.
*/
void
eekboard_eekboard_destroy_context (EekboardEekboard *eekboard,
eekboard_client_destroy_context (EekboardClient *client,
EekboardContext *context,
GCancellable *cancellable)
{
EekboardEekboardPrivate *priv;
EekboardClientPrivate *priv;
const gchar *object_path;
g_return_if_fail (EEKBOARD_IS_EEKBOARD(eekboard));
g_return_if_fail (EEKBOARD_IS_CLIENT(client));
g_return_if_fail (EEKBOARD_IS_CONTEXT(context));
priv = EEKBOARD_EEKBOARD_GET_PRIVATE(eekboard);
priv = EEKBOARD_CLIENT_GET_PRIVATE(client);
object_path = g_dbus_proxy_get_object_path (G_DBUS_PROXY(context));
g_hash_table_remove (priv->context_hash, object_path);
g_dbus_proxy_call (G_DBUS_PROXY(eekboard),
g_dbus_proxy_call (G_DBUS_PROXY(client),
"DestroyContext",
g_variant_new ("(s)", object_path),
G_DBUS_CALL_FLAGS_NONE,

View File

@ -0,0 +1,75 @@
/*
* Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2010-2011 Red Hat, Inc.
*
* 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/>.
*/
#ifndef EEKBOARD_CLIENT_H
#define EEKBOARD_CLIENT_H 1
#define __EEKBOARD_CLIENT_H_INSIDE__ 1
#include <gio/gio.h>
#include "eekboard/eekboard-context.h"
G_BEGIN_DECLS
#define EEKBOARD_TYPE_CLIENT (eekboard_client_get_type())
#define EEKBOARD_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEKBOARD_TYPE_CLIENT, EekboardClient))
#define EEKBOARD_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEKBOARD_TYPE_CLIENT, EekboardClientClass))
#define EEKBOARD_IS_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEKBOARD_TYPE_CLIENT))
#define EEKBOARD_IS_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEKBOARD_TYPE_CLIENT))
#define EEKBOARD_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEKBOARD_TYPE_CLIENT, EekboardClientClass))
typedef struct _EekboardClient EekboardClient;
typedef struct _EekboardClientClass EekboardClientClass;
typedef struct _EekboardClientPrivate EekboardClientPrivate;
struct _EekboardClient {
/*< private >*/
GDBusProxy parent;
EekboardClientPrivate *priv;
};
struct _EekboardClientClass {
/*< private >*/
GDBusProxyClass parent_class;
/* signals */
void (* destroyed) (EekboardClient *self);
/*< private >*/
/* padding */
gpointer pdummy[23];
};
GType eekboard_client_get_type (void) G_GNUC_CONST;
EekboardClient *eekboard_client_new (GDBusConnection *connection,
GCancellable *cancellable);
EekboardContext *eekboard_client_create_context (EekboardClient *eekboard,
const gchar *client_name,
GCancellable *cancellable);
void eekboard_client_push_context (EekboardClient *eekboard,
EekboardContext *context,
GCancellable *cancellable);
void eekboard_client_pop_context (EekboardClient *eekboard,
GCancellable *cancellable);
void eekboard_client_destroy_context (EekboardClient *eekboard,
EekboardContext *context,
GCancellable *cancellable);
G_END_DECLS
#endif /* EEKBOARD_CLIENT_H */

View File

@ -0,0 +1,996 @@
/*
* Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2010-2011 Red Hat, Inc.
*
* 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/>.
*/
/**
* SECTION:eekboard-context-service
* @short_description: base server implementation of eekboard input
* context service
*
* The #EekboardService class provides a base server side
* implementation of eekboard input context service.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#include "eekboard/eekboard-context-service.h"
#include "eekboard/eekboard-xklutil.h"
#include "eek/eek-xkl.h"
#define CSW 640
#define CSH 480
enum {
PROP_0,
PROP_OBJECT_PATH,
PROP_CONNECTION,
PROP_CLIENT_NAME,
PROP_KEYBOARD,
PROP_VISIBLE,
PROP_FULLSCREEN,
PROP_LAST
};
enum {
ENABLED,
DISABLED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0, };
#define EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEKBOARD_TYPE_CONTEXT_SERVICE, EekboardContextServicePrivate))
struct _EekboardContextServicePrivate {
GDBusConnection *connection;
GDBusNodeInfo *introspection_data;
guint registration_id;
char *object_path;
char *client_name;
gboolean enabled;
gboolean visible;
gboolean fullscreen;
EekKeyboard *keyboard;
GHashTable *keyboard_hash;
gulong key_pressed_handler;
gulong key_released_handler;
EekKey *repeat_key;
guint repeat_timeout_id;
gboolean repeat_triggered;
GSettings *settings;
};
G_DEFINE_TYPE (EekboardContextService, eekboard_context_service, G_TYPE_OBJECT);
static const gchar introspection_xml[] =
"<node>"
" <interface name='org.fedorahosted.Eekboard.Context'>"
" <method name='AddKeyboard'>"
" <arg direction='in' type='s' name='keyboard'/>"
" <arg direction='out' type='u' name='keyboard_id'/>"
" </method>"
" <method name='RemoveKeyboard'>"
" <arg direction='in' type='u' name='keyboard_id'/>"
" </method>"
" <method name='SetKeyboard'>"
" <arg type='u' name='keyboard_id'/>"
" </method>"
" <method name='SetFullscreen'>"
" <arg type='b' name='fullscreen'/>"
" </method>"
" <method name='ShowKeyboard'/>"
" <method name='HideKeyboard'/>"
" <method name='SetGroup'>"
" <arg type='i' name='group'/>"
" </method>"
" <method name='PressKeycode'>"
" <arg type='u' name='keycode'/>"
" </method>"
" <method name='ReleaseKeycode'>"
" <arg type='u' name='keycode'/>"
" </method>"
/* signals */
" <signal name='Enabled'/>"
" <signal name='Disabled'/>"
" <signal name='KeyPressed'>"
" <arg type='s' name='keyname'/>"
" <arg type='v' name='symbol'/>"
" <arg type='u' name='modifiers'/>"
" </signal>"
" <signal name='VisibilityChanged'>"
" <arg type='b' name='visible'/>"
" </signal>"
" <signal name='KeyboardChanged'>"
" <arg type='u' name='keyboard_id'/>"
" </signal>"
" <signal name='GroupChanged'>"
" <arg type='i' name='group'/>"
" </signal>"
" </interface>"
"</node>";
static void connect_keyboard_signals (EekboardContextService *context);
static void disconnect_keyboard_signals
(EekboardContextService *context);
static void handle_method_call (GDBusConnection *connection,
const gchar *sender,
const gchar *object_path,
const gchar *interface_name,
const gchar *method_name,
GVariant *parameters,
GDBusMethodInvocation *invocation,
gpointer user_data);
static void emit_visibility_changed_signal
(EekboardContextService *context,
gboolean visible);
static const GDBusInterfaceVTable interface_vtable =
{
handle_method_call,
NULL,
NULL
};
static EekKeyboard *
eekboard_context_service_real_create_keyboard (EekboardContextService *self,
const gchar *keyboard_type)
{
EekKeyboard *keyboard;
EekLayout *layout;
if (g_str_has_prefix (keyboard_type, "xkb:")) {
XklConfigRec *rec =
eekboard_xkl_config_rec_from_string (&keyboard_type[4]);
layout = eek_xkl_layout_new ();
if (!eek_xkl_layout_set_config (EEK_XKL_LAYOUT(layout), rec)) {
g_object_unref (layout);
return NULL;
}
} else {
gchar *path;
GFile *file;
GFileInputStream *input;
GError *error;
path = g_strdup_printf ("%s/%s.xml", KEYBOARDDIR, keyboard_type);
file = g_file_new_for_path (path);
g_free (path);
error = NULL;
input = g_file_read (file, NULL, &error);
g_object_unref (file);
if (input == NULL)
return NULL;
layout = eek_xml_layout_new (G_INPUT_STREAM(input));
}
keyboard = eek_keyboard_new (layout, CSW, CSH);
g_object_unref (layout);
return keyboard;
}
static void
eekboard_context_service_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
EekboardContextService *context = EEKBOARD_CONTEXT_SERVICE(object);
EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context);
GDBusConnection *connection;
gboolean was_visible;
switch (prop_id) {
case PROP_OBJECT_PATH:
if (priv->object_path)
g_free (priv->object_path);
priv->object_path = g_strdup (g_value_get_string (value));
break;
case PROP_CONNECTION:
connection = g_value_get_object (value);
if (priv->connection)
g_object_unref (priv->connection);
priv->connection = g_object_ref (connection);
break;
case PROP_CLIENT_NAME:
if (priv->client_name)
g_free (priv->client_name);
priv->client_name = g_strdup (g_value_get_string (value));
break;
case PROP_KEYBOARD:
if (priv->keyboard)
g_object_unref (priv->keyboard);
priv->keyboard = g_value_get_object (value);
break;
case PROP_VISIBLE:
was_visible = priv->visible;
priv->visible = g_value_get_boolean (value);
if (was_visible != priv->visible)
emit_visibility_changed_signal (EEKBOARD_CONTEXT_SERVICE(object),
priv->visible);
break;
case PROP_FULLSCREEN:
priv->fullscreen = g_value_get_boolean (value);
break;
default:
g_object_set_property (object,
g_param_spec_get_name (pspec),
value);
break;
}
}
static void
eekboard_context_service_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
EekboardContextService *context = EEKBOARD_CONTEXT_SERVICE(object);
EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context);
switch (prop_id) {
case PROP_OBJECT_PATH:
g_value_set_string (value, priv->object_path);
break;
case PROP_CONNECTION:
g_value_set_object (value, priv->connection);
break;
case PROP_CLIENT_NAME:
g_value_set_string (value, priv->client_name);
break;
case PROP_KEYBOARD:
g_value_set_object (value, priv->keyboard);
break;
case PROP_VISIBLE:
g_value_set_boolean (value, priv->visible);
break;
case PROP_FULLSCREEN:
g_value_set_boolean (value, priv->fullscreen);
break;
default:
g_object_set_property (object,
g_param_spec_get_name (pspec),
value);
break;
}
}
static void
eekboard_context_service_dispose (GObject *object)
{
EekboardContextService *context = EEKBOARD_CONTEXT_SERVICE(object);
EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context);
if (priv->keyboard_hash) {
g_hash_table_destroy (priv->keyboard_hash);
priv->keyboard_hash = NULL;
}
if (priv->connection) {
if (priv->registration_id > 0) {
g_dbus_connection_unregister_object (priv->connection,
priv->registration_id);
priv->registration_id = 0;
}
g_object_unref (priv->connection);
priv->connection = NULL;
}
if (priv->introspection_data) {
g_dbus_node_info_unref (priv->introspection_data);
priv->introspection_data = NULL;
}
G_OBJECT_CLASS (eekboard_context_service_parent_class)->dispose (object);
}
static void
eekboard_context_service_finalize (GObject *object)
{
EekboardContextService *context = EEKBOARD_CONTEXT_SERVICE(object);
EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context);
g_free (priv->object_path);
g_free (priv->client_name);
G_OBJECT_CLASS (eekboard_context_service_parent_class)->finalize (object);
}
static void
eekboard_context_service_constructed (GObject *object)
{
EekboardContextService *context = EEKBOARD_CONTEXT_SERVICE (object);
EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context);
if (priv->connection && priv->object_path) {
GError *error = NULL;
priv->registration_id = g_dbus_connection_register_object
(priv->connection,
priv->object_path,
priv->introspection_data->interfaces[0],
&interface_vtable,
context,
NULL,
&error);
}
}
static void
eekboard_context_service_class_init (EekboardContextServiceClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GParamSpec *pspec;
g_type_class_add_private (gobject_class,
sizeof (EekboardContextServicePrivate));
klass->create_keyboard = eekboard_context_service_real_create_keyboard;
klass->show_keyboard = NULL;
klass->hide_keyboard = NULL;
gobject_class->constructed = eekboard_context_service_constructed;
gobject_class->set_property = eekboard_context_service_set_property;
gobject_class->get_property = eekboard_context_service_get_property;
gobject_class->dispose = eekboard_context_service_dispose;
gobject_class->finalize = eekboard_context_service_finalize;
/**
* EekboardContextService::enabled:
* @context: an #EekboardContextService
*
* Emitted when @context is enabled.
*/
signals[ENABLED] =
g_signal_new (I_("enabled"),
G_TYPE_FROM_CLASS(gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(EekboardContextServiceClass, enabled),
NULL,
NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0);
/**
* EekboardContextService::disabled:
* @context: an #EekboardContextService
*
* Emitted when @context is enabled.
*/
signals[DISABLED] =
g_signal_new (I_("disabled"),
G_TYPE_FROM_CLASS(gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(EekboardContextServiceClass, disabled),
NULL,
NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0);
/**
* EekboardContextService:object-path:
*
* D-Bus object path.
*/
pspec = g_param_spec_string ("object-path",
"Object-path",
"Object-path",
NULL,
G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
g_object_class_install_property (gobject_class,
PROP_OBJECT_PATH,
pspec);
/**
* EekboardContextService:connection:
*
* D-Bus connection.
*/
pspec = g_param_spec_object ("connection",
"Connection",
"Connection",
G_TYPE_DBUS_CONNECTION,
G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
g_object_class_install_property (gobject_class,
PROP_CONNECTION,
pspec);
/**
* EekboardContextService:client-name:
*
* Name of a client who created this context service.
*/
pspec = g_param_spec_string ("client-name",
"Client-name",
"Client-name",
NULL,
G_PARAM_READWRITE);
g_object_class_install_property (gobject_class,
PROP_CLIENT_NAME,
pspec);
/**
* EekboardContextService:keyboard:
*
* An #EekKeyboard currently active in this context.
*/
pspec = g_param_spec_object ("keyboard",
"Keyboard",
"Keyboard",
EEK_TYPE_KEYBOARD,
G_PARAM_READWRITE);
g_object_class_install_property (gobject_class,
PROP_KEYBOARD,
pspec);
/**
* EekboardContextService:visible:
*
* Flag to indicate if keyboard is visible or not.
*/
pspec = g_param_spec_boolean ("visible",
"Visible",
"Visible",
FALSE,
G_PARAM_READWRITE);
g_object_class_install_property (gobject_class,
PROP_VISIBLE,
pspec);
/**
* EekboardContextService:fullscreen:
*
* Flag to indicate if keyboard is rendered in fullscreen mode.
*/
pspec = g_param_spec_boolean ("fullscreen",
"Fullscreen",
"Fullscreen",
FALSE,
G_PARAM_READWRITE);
g_object_class_install_property (gobject_class,
PROP_FULLSCREEN,
pspec);
}
static void
eekboard_context_service_init (EekboardContextService *context)
{
EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context);
GError *error;
error = NULL;
priv->introspection_data =
g_dbus_node_info_new_for_xml (introspection_xml, &error);
g_assert (priv->introspection_data != NULL);
priv->keyboard_hash =
g_hash_table_new_full (g_direct_hash,
g_direct_equal,
NULL,
(GDestroyNotify)g_object_unref);
priv->settings = g_settings_new ("org.fedorahosted.eekboard");
}
static void
disconnect_keyboard_signals (EekboardContextService *context)
{
EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context);
if (g_signal_handler_is_connected (priv->keyboard,
priv->key_pressed_handler))
g_signal_handler_disconnect (priv->keyboard,
priv->key_pressed_handler);
if (g_signal_handler_is_connected (priv->keyboard,
priv->key_released_handler))
g_signal_handler_disconnect (priv->keyboard,
priv->key_released_handler);
}
static void
emit_visibility_changed_signal (EekboardContextService *context,
gboolean visible)
{
EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context);
if (priv->connection && priv->enabled) {
GError *error = NULL;
g_dbus_connection_emit_signal (priv->connection,
NULL,
priv->object_path,
EEKBOARD_CONTEXT_SERVICE_INTERFACE,
"VisibilityChanged",
g_variant_new ("(b)", visible),
&error);
g_assert_no_error (error);
}
}
static void
emit_group_changed_signal (EekboardContextService *context,
gint group)
{
EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context);
if (priv->connection && priv->enabled) {
GError *error = NULL;
g_dbus_connection_emit_signal (priv->connection,
NULL,
priv->object_path,
EEKBOARD_CONTEXT_SERVICE_INTERFACE,
"GroupChanged",
g_variant_new ("(i)", group),
&error);
g_assert_no_error (error);
}
}
static void
emit_key_pressed_dbus_signal (EekboardContextService *context,
EekKey *key)
{
EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context);
if (priv->connection && priv->enabled) {
const gchar *keyname = eek_element_get_name (EEK_ELEMENT(key));
EekSymbol *symbol = eek_key_get_symbol_with_fallback (key, 0, 0);
guint modifiers = eek_keyboard_get_modifiers (priv->keyboard);
GVariant *variant;
GError *error;
variant = eek_serializable_serialize (EEK_SERIALIZABLE(symbol));
error = NULL;
g_dbus_connection_emit_signal (priv->connection,
NULL,
priv->object_path,
EEKBOARD_CONTEXT_SERVICE_INTERFACE,
"KeyPressed",
g_variant_new ("(svu)",
keyname,
variant,
modifiers),
&error);
g_variant_unref (variant);
g_assert_no_error (error);
}
}
static gboolean on_repeat_timeout (EekboardContextService *context);
static gboolean
on_repeat_timeout (EekboardContextService *context)
{
EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context);
guint delay;
g_settings_get (priv->settings, "repeat-interval", "u", &delay);
emit_key_pressed_dbus_signal (context, priv->repeat_key);
priv->repeat_timeout_id =
g_timeout_add (delay,
(GSourceFunc)on_repeat_timeout,
context);
return FALSE;
}
static gboolean
on_repeat_timeout_init (EekboardContextService *context)
{
EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context);
emit_key_pressed_dbus_signal (context, priv->repeat_key);
/* FIXME: clear modifiers for further key repeat; better not
depend on modifier behavior is LATCH */
eek_keyboard_set_modifiers (priv->keyboard, 0);
/* reschedule repeat timeout only when "repeat" option is set */
if (g_settings_get_boolean (priv->settings, "repeat")) {
guint delay;
g_settings_get (priv->settings, "repeat-interval", "u", &delay);
priv->repeat_timeout_id =
g_timeout_add (delay,
(GSourceFunc)on_repeat_timeout,
context);
} else
priv->repeat_timeout_id = 0;
return FALSE;
}
static void
on_key_pressed (EekKeyboard *keyboard,
EekKey *key,
gpointer user_data)
{
EekboardContextService *context = user_data;
EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context);
guint delay;
g_settings_get (priv->settings, "repeat-delay", "u", &delay);
if (priv->repeat_timeout_id) {
g_source_remove (priv->repeat_timeout_id);
priv->repeat_timeout_id = 0;
}
priv->repeat_key = key;
priv->repeat_timeout_id =
g_timeout_add (delay,
(GSourceFunc)on_repeat_timeout_init,
context);
}
static void
on_key_released (EekKeyboard *keyboard,
EekKey *key,
gpointer user_data)
{
EekboardContextService *context = user_data;
EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context);
if (priv->repeat_timeout_id > 0) {
g_source_remove (priv->repeat_timeout_id);
priv->repeat_timeout_id = 0;
/* KeyPressed signal has not been emitted in repeat handler */
emit_key_pressed_dbus_signal (context, priv->repeat_key);
}
}
static void
connect_keyboard_signals (EekboardContextService *context)
{
EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context);
priv->key_pressed_handler =
g_signal_connect (priv->keyboard, "key-pressed",
G_CALLBACK(on_key_pressed),
context);
priv->key_released_handler =
g_signal_connect (priv->keyboard, "key-released",
G_CALLBACK(on_key_released),
context);
}
static void
handle_method_call (GDBusConnection *connection,
const gchar *sender,
const gchar *object_path,
const gchar *interface_name,
const gchar *method_name,
GVariant *parameters,
GDBusMethodInvocation *invocation,
gpointer user_data)
{
EekboardContextService *context = user_data;
EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context);
EekboardContextServiceClass *klass = EEKBOARD_CONTEXT_SERVICE_GET_CLASS(context);
if (g_strcmp0 (method_name, "AddKeyboard") == 0) {
const gchar *keyboard_type;
static guint keyboard_id = 0;
EekKeyboard *keyboard;
g_variant_get (parameters, "(&s)", &keyboard_type);
keyboard = klass->create_keyboard (context, keyboard_type);
if (keyboard == NULL) {
g_dbus_method_invocation_return_error (invocation,
G_IO_ERROR,
G_IO_ERROR_FAILED_HANDLED,
"can't create a keyboard");
return;
}
eek_keyboard_set_modifier_behavior (keyboard,
EEK_MODIFIER_BEHAVIOR_LATCH);
keyboard_id++;
g_hash_table_insert (priv->keyboard_hash,
GUINT_TO_POINTER(keyboard_id),
keyboard);
g_object_set_data (G_OBJECT(keyboard),
"keyboard-id",
GUINT_TO_POINTER(keyboard_id));
g_dbus_method_invocation_return_value (invocation,
g_variant_new ("(u)",
keyboard_id));
return;
}
if (g_strcmp0 (method_name, "RemoveKeyboard") == 0) {
guint keyboard_id, current_keyboard_id;
g_variant_get (parameters, "(u)", &keyboard_id);
current_keyboard_id =
GPOINTER_TO_UINT (g_object_get_data (G_OBJECT(priv->keyboard),
"keyboard-id"));
if (keyboard_id == current_keyboard_id) {
disconnect_keyboard_signals (context);
priv->keyboard = NULL;
g_object_notify (G_OBJECT(context), "keyboard");
}
g_hash_table_remove (priv->keyboard_hash,
GUINT_TO_POINTER(keyboard_id));
g_dbus_method_invocation_return_value (invocation, NULL);
return;
}
if (g_strcmp0 (method_name, "SetKeyboard") == 0) {
EekKeyboard *keyboard;
guint keyboard_id;
gint group;
g_variant_get (parameters, "(u)", &keyboard_id);
keyboard = g_hash_table_lookup (priv->keyboard_hash,
GUINT_TO_POINTER(keyboard_id));
if (!keyboard) {
g_dbus_method_invocation_return_error (invocation,
G_IO_ERROR,
G_IO_ERROR_FAILED_HANDLED,
"no such keyboard");
return;
}
if (keyboard == priv->keyboard) {
g_dbus_method_invocation_return_value (invocation, NULL);
return;
}
if (priv->keyboard)
disconnect_keyboard_signals (context);
priv->keyboard = keyboard;
connect_keyboard_signals (context);
g_dbus_method_invocation_return_value (invocation, NULL);
group = eek_element_get_group (EEK_ELEMENT(priv->keyboard));
emit_group_changed_signal (context, group);
g_object_notify (G_OBJECT(context), "keyboard");
return;
}
if (g_strcmp0 (method_name, "SetFullscreen") == 0) {
gboolean fullscreen;
g_variant_get (parameters, "(b)", &fullscreen);
if (priv->fullscreen == fullscreen) {
g_dbus_method_invocation_return_value (invocation, NULL);
return;
}
priv->fullscreen = fullscreen;
g_dbus_method_invocation_return_value (invocation, NULL);
g_object_notify (G_OBJECT(context), "fullscreen");
return;
}
if (g_strcmp0 (method_name, "SetGroup") == 0) {
gint group;
if (!priv->keyboard) {
g_dbus_method_invocation_return_error (invocation,
G_IO_ERROR,
G_IO_ERROR_FAILED_HANDLED,
"keyboard is not set");
return;
}
g_variant_get (parameters, "(i)", &group);
eek_element_set_group (EEK_ELEMENT(priv->keyboard), group);
g_dbus_method_invocation_return_value (invocation, NULL);
emit_group_changed_signal (context, group);
return;
}
if (g_strcmp0 (method_name, "ShowKeyboard") == 0) {
if (!priv->keyboard) {
g_dbus_method_invocation_return_error (invocation,
G_IO_ERROR,
G_IO_ERROR_FAILED_HANDLED,
"keyboard is not set");
return;
}
if (klass->show_keyboard)
klass->show_keyboard (context);
g_dbus_method_invocation_return_value (invocation, NULL);
return;
}
if (g_strcmp0 (method_name, "HideKeyboard") == 0) {
if (klass->hide_keyboard)
klass->hide_keyboard (context);
g_dbus_method_invocation_return_value (invocation, NULL);
return;
}
if (g_strcmp0 (method_name, "PressKeycode") == 0 ||
g_strcmp0 (method_name, "ReleaseKeycode") == 0) {
EekKey *key;
guint keycode;
if (!priv->keyboard) {
g_dbus_method_invocation_return_error (invocation,
G_IO_ERROR,
G_IO_ERROR_FAILED_HANDLED,
"keyboard is not set");
return;
}
g_variant_get (parameters, "(u)", &keycode);
key = eek_keyboard_find_key_by_keycode (priv->keyboard, keycode);
if (!key) {
g_dbus_method_invocation_return_error (invocation,
G_IO_ERROR,
G_IO_ERROR_FAILED_HANDLED,
"key for %u is not found",
keycode);
return;
}
if (g_strcmp0 (method_name, "PressKeycode") == 0) {
g_signal_handler_block (priv->keyboard,
priv->key_pressed_handler);
g_signal_emit_by_name (key, "pressed");
g_signal_handler_unblock (priv->keyboard,
priv->key_pressed_handler);
} else {
g_signal_handler_block (priv->keyboard,
priv->key_released_handler);
g_signal_emit_by_name (key, "released");
g_signal_handler_unblock (priv->keyboard,
priv->key_released_handler);
}
g_dbus_method_invocation_return_value (invocation, NULL);
return;
}
g_return_if_reached ();
}
/**
* eekboard_context_service_enable:
* @context: an #EekboardContextService
*
* Enable @context. This function is called when @context is pushed
* by eekboard_service_push_context().
*/
void
eekboard_context_service_enable (EekboardContextService *context)
{
EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context);
GError *error;
g_return_if_fail (EEKBOARD_IS_CONTEXT_SERVICE(context));
g_return_if_fail (priv->connection);
if (!priv->enabled) {
priv->enabled = TRUE;
error = NULL;
g_dbus_connection_emit_signal (priv->connection,
NULL,
priv->object_path,
EEKBOARD_CONTEXT_SERVICE_INTERFACE,
"Enabled",
NULL,
&error);
g_assert_no_error (error);
g_signal_emit_by_name (context, "enabled", NULL);
}
}
/**
* eekboard_context_service_disable:
* @context: an #EekboardContextService
*
* Disable @context. This function is called when @context is pushed
* by eekboard_service_pop_context().
*/
void
eekboard_context_service_disable (EekboardContextService *context)
{
EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context);
GError *error;
g_return_if_fail (EEKBOARD_IS_CONTEXT_SERVICE(context));
g_return_if_fail (priv->connection);
if (priv->enabled) {
priv->enabled = FALSE;
error = NULL;
g_dbus_connection_emit_signal (priv->connection,
NULL,
priv->object_path,
EEKBOARD_CONTEXT_SERVICE_INTERFACE,
"Disabled",
NULL,
&error);
g_assert_no_error (error);
g_signal_emit_by_name (context, "disabled", NULL);
}
}
/**
* eekboard_context_service_get_keyboard:
* @context: an #EekboardContextService
*
* Get keyboard currently active in @context.
* Returns: (transfer none): an #EekKeyboard
*/
EekKeyboard *
eekboard_context_service_get_keyboard (EekboardContextService *context)
{
EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context);
return priv->keyboard;
}
/**
* eekboard_context_service_get_fullscreen:
* @context: an #EekboardContextService
*
* Check if keyboard is rendered in fullscreen mode in @context.
* Returns: %TRUE or %FALSE
*/
gboolean
eekboard_context_service_get_fullscreen (EekboardContextService *context)
{
EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context);
return priv->fullscreen;
}
/**
* eekboard_context_service_get_client_name:
* @context: an #EekboardContextService
*
* Get the name of client which created @context.
* Returns: (transfer none): a string
*/
const gchar *
eekboard_context_service_get_client_name (EekboardContextService *context)
{
EekboardContextServicePrivate *priv = EEKBOARD_CONTEXT_SERVICE_GET_PRIVATE(context);
return priv->client_name;
}

View File

@ -0,0 +1,94 @@
/*
* Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2010-2011 Red Hat, Inc.
*
* 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/>.
*/
#if !defined(__EEKBOARD_SERVICE_H_INSIDE__) && !defined(EEKBOARD_COMPILATION)
#error "Only <eekboard/eekboard-service.h> can be included directly."
#endif
#ifndef EEKBOARD_CONTEXT_SERVICE_H
#define EEKBOARD_CONTEXT_SERVICE_H 1
#include <eek/eek.h>
G_BEGIN_DECLS
#define EEKBOARD_CONTEXT_SERVICE_PATH "/org/fedorahosted/Eekboard/Context_%d"
#define EEKBOARD_CONTEXT_SERVICE_INTERFACE "org.fedorahosted.Eekboard.Context"
#define EEKBOARD_TYPE_CONTEXT_SERVICE (eekboard_context_service_get_type())
#define EEKBOARD_CONTEXT_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEKBOARD_TYPE_CONTEXT_SERVICE, EekboardContextService))
#define EEKBOARD_CONTEXT_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEKBOARD_TYPE_CONTEXT_SERVICE, EekboardContextServiceClass))
#define EEKBOARD_IS_CONTEXT_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEKBOARD_TYPE_CONTEXT_SERVICE))
#define EEKBOARD_IS_CONTEXT_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEKBOARD_TYPE_CONTEXT_SERVICE))
#define EEKBOARD_CONTEXT_SERVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEKBOARD_TYPE_CONTEXT_SERVICE, EekboardContextServiceClass))
typedef struct _EekboardContextService EekboardContextService;
typedef struct _EekboardContextServiceClass EekboardContextServiceClass;
typedef struct _EekboardContextServicePrivate EekboardContextServicePrivate;
/**
* EekboardContextService:
*
* The #EekboardContextService structure contains only private data
* and should only be accessed using the provided API.
*/
struct _EekboardContextService {
GObject parent;
EekboardContextServicePrivate *priv;
};
/**
* EekboardContextServiceClass:
* @create_keyboard: virtual function for create a keyboard from string
* @show_keyboard: virtual function for show a keyboard
* @hide_keyboard: virtual function for hide a keyboard
* @enabled: class handler for #EekboardContextService::enabled signal
* @disabled: class handler for #EekboardContextService::disabled signal
*/
struct _EekboardContextServiceClass {
/*< private >*/
GObjectClass parent_class;
/*< public >*/
EekKeyboard *(*create_keyboard) (EekboardContextService *self,
const gchar *keyboard_type);
void (*show_keyboard) (EekboardContextService *self);
void (*hide_keyboard) (EekboardContextService *self);
/* signals */
void (*enabled) (EekboardContextService *self);
void (*disabled) (EekboardContextService *self);
/*< private >*/
/* padding */
gpointer pdummy[24];
};
GType eekboard_context_service_get_type
(void) G_GNUC_CONST;
void eekboard_context_service_enable (EekboardContextService *context);
void eekboard_context_service_disable (EekboardContextService *context);
EekKeyboard *eekboard_context_service_get_keyboard
(EekboardContextService *context);
gboolean eekboard_context_service_get_fullscreen
(EekboardContextService *context);
const gchar * eekboard_context_service_get_client_name
(EekboardContextService *context);
G_END_DECLS
#endif /* EEKBOARD_CONTEXT_SERVICE_H */

View File

@ -18,7 +18,7 @@
/**
* SECTION:eekboard-context
* @short_description: input context maintained by #EekboardServer.
* @short_description: client interface of eekboard input context service
*
* The #EekboardContext class provides a client access to remote input
* context.
@ -29,6 +29,7 @@
#endif /* HAVE_CONFIG_H */
#include "eekboard/eekboard-context.h"
#include "eekboard/eekboard-marshalers.h"
#define I_(string) g_intern_static_string (string)
@ -36,7 +37,6 @@ enum {
ENABLED,
DISABLED,
KEY_PRESSED,
KEY_RELEASED,
DESTROYED,
LAST_SIGNAL
};
@ -45,7 +45,7 @@ static guint signals[LAST_SIGNAL] = { 0, };
enum {
PROP_0,
PROP_KEYBOARD_VISIBLE,
PROP_VISIBLE,
PROP_LAST
};
@ -56,11 +56,10 @@ G_DEFINE_TYPE (EekboardContext, eekboard_context, G_TYPE_DBUS_PROXY);
struct _EekboardContextPrivate
{
EekKeyboard *keyboard;
GHashTable *keyboard_hash;
gboolean keyboard_visible;
gboolean visible;
gboolean enabled;
gboolean fullscreen;
gint group;
};
static void
@ -83,26 +82,44 @@ eekboard_context_real_g_signal (GDBusProxy *self,
}
if (g_strcmp0 (signal_name, "KeyPressed") == 0) {
guint keycode;
g_variant_get (parameters, "(u)", &keycode);
g_signal_emit_by_name (context, "key-pressed", keycode);
const gchar *keyname;
GVariant *variant = NULL;
guint modifiers = 0;
EekSerializable *serializable;
g_variant_get (parameters, "(&svu)", &keyname, &variant, &modifiers);
g_return_if_fail (variant != NULL);
serializable = eek_serializable_deserialize (variant);
g_variant_unref (variant);
g_return_if_fail (EEK_IS_SYMBOL(serializable));
g_signal_emit_by_name (context, "key-pressed",
keyname, EEK_SYMBOL(serializable), modifiers);
g_object_unref (serializable);
return;
}
if (g_strcmp0 (signal_name, "KeyReleased") == 0) {
guint keycode;
g_variant_get (parameters, "(u)", &keycode);
g_signal_emit_by_name (context, "key-released", keycode);
if (g_strcmp0 (signal_name, "VisibilityChanged") == 0) {
gboolean visible = FALSE;
g_variant_get (parameters, "(b)", &visible);
if (visible != priv->visible) {
priv->visible = visible;
g_object_notify (G_OBJECT(context), "visible");
}
return;
}
if (g_strcmp0 (signal_name, "KeyboardVisibilityChanged") == 0) {
gboolean keyboard_visible;
if (g_strcmp0 (signal_name, "GroupChanged") == 0) {
gint group = 0;
g_variant_get (parameters, "(b)", &keyboard_visible);
if (keyboard_visible != priv->keyboard_visible) {
priv->keyboard_visible = keyboard_visible;
g_object_notify (G_OBJECT(context), "keyboard-visible");
g_variant_get (parameters, "(i)", &group);
if (group != priv->group) {
priv->group = group;
//g_object_notify (G_OBJECT(context), "group");
}
return;
}
@ -126,32 +143,15 @@ eekboard_context_real_disabled (EekboardContext *self)
static void
eekboard_context_real_key_pressed (EekboardContext *self,
guint keycode)
const gchar *keyname,
EekSymbol *symbol,
guint modifiers)
{
EekboardContextPrivate *priv = EEKBOARD_CONTEXT_GET_PRIVATE(self);
if (priv->keyboard) {
EekKey *key = eek_keyboard_find_key_by_keycode (priv->keyboard,
keycode);
g_signal_emit_by_name (key, "pressed");
}
}
static void
eekboard_context_real_key_released (EekboardContext *self,
guint keycode)
{
EekboardContextPrivate *priv = EEKBOARD_CONTEXT_GET_PRIVATE(self);
if (priv->keyboard) {
EekKey *key = eek_keyboard_find_key_by_keycode (priv->keyboard,
keycode);
g_signal_emit_by_name (key, "released");
}
}
static void
eekboard_context_real_destroyed (EekboardContext *self)
{
// g_debug ("eekboard_context_real_destroyed");
}
static void
@ -162,8 +162,8 @@ eekboard_context_get_property (GObject *object,
{
EekboardContextPrivate *priv = EEKBOARD_CONTEXT_GET_PRIVATE(object);
switch (prop_id) {
case PROP_KEYBOARD_VISIBLE:
g_value_set_boolean (value, priv->keyboard_visible);
case PROP_VISIBLE:
g_value_set_boolean (value, priv->visible);
break;
default:
g_object_get_property (object,
@ -173,22 +173,6 @@ eekboard_context_get_property (GObject *object,
}
}
static void
eekboard_context_dispose (GObject *self)
{
EekboardContextPrivate *priv = EEKBOARD_CONTEXT_GET_PRIVATE (self);
if (priv->keyboard) {
g_object_unref (priv->keyboard);
priv->keyboard = NULL;
}
if (priv->keyboard_hash) {
g_hash_table_destroy (priv->keyboard_hash);
priv->keyboard_hash = NULL;
}
}
static void
eekboard_context_class_init (EekboardContextClass *klass)
{
@ -202,26 +186,24 @@ eekboard_context_class_init (EekboardContextClass *klass)
klass->enabled = eekboard_context_real_enabled;
klass->disabled = eekboard_context_real_disabled;
klass->key_pressed = eekboard_context_real_key_pressed;
klass->key_released = eekboard_context_real_key_released;
klass->destroyed = eekboard_context_real_destroyed;
proxy_class->g_signal = eekboard_context_real_g_signal;
gobject_class->get_property = eekboard_context_get_property;
gobject_class->dispose = eekboard_context_dispose;
/**
* EekboardContext:keyboard-visible:
* EekboardContext:visible:
*
* Flag to indicate if keyboard is visible or not.
*/
pspec = g_param_spec_boolean ("keyboard-visible",
"Keyboard-visible",
pspec = g_param_spec_boolean ("visible",
"visible",
"Flag that indicates if keyboard is visible",
FALSE,
G_PARAM_READABLE);
g_object_class_install_property (gobject_class,
PROP_KEYBOARD_VISIBLE,
PROP_VISIBLE,
pspec);
/**
@ -262,6 +244,8 @@ eekboard_context_class_init (EekboardContextClass *klass)
* EekboardContext::key-pressed:
* @context: an #EekboardContext
* @keycode: keycode
* @symbol: an #EekSymbol
* @modifiers: modifiers
*
* The ::key-pressed signal is emitted each time a key is pressed
* in @context.
@ -273,29 +257,11 @@ eekboard_context_class_init (EekboardContextClass *klass)
G_STRUCT_OFFSET(EekboardContextClass, key_pressed),
NULL,
NULL,
g_cclosure_marshal_VOID__UINT,
_eekboard_marshal_VOID__STRING_OBJECT_UINT,
G_TYPE_NONE,
1,
G_TYPE_UINT);
/**
* EekboardContext::key-released:
* @context: an #EekboardContext
* @keycode: keycode
*
* The ::key-released signal is emitted each time a key is released
* in @context.
*/
signals[KEY_RELEASED] =
g_signal_new (I_("key-released"),
G_TYPE_FROM_CLASS(gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(EekboardContextClass, key_released),
NULL,
NULL,
g_cclosure_marshal_VOID__UINT,
G_TYPE_NONE,
1,
3,
G_TYPE_STRING,
G_TYPE_OBJECT,
G_TYPE_UINT);
/**
@ -320,17 +286,7 @@ eekboard_context_class_init (EekboardContextClass *klass)
static void
eekboard_context_init (EekboardContext *self)
{
EekboardContextPrivate *priv;
priv = self->priv = EEKBOARD_CONTEXT_GET_PRIVATE(self);
priv->keyboard = NULL;
priv->keyboard_visible = FALSE;
priv->enabled = FALSE;
priv->keyboard_hash =
g_hash_table_new_full (g_direct_hash,
g_direct_equal,
NULL,
(GDestroyNotify)g_object_unref);
self->priv = EEKBOARD_CONTEXT_GET_PRIVATE(self);
}
static void
@ -368,7 +324,7 @@ eekboard_context_new (GDBusConnection *connection,
g_initable_new (EEKBOARD_TYPE_CONTEXT,
cancellable,
&error,
"g-name", "org.fedorahosted.Eekboard.Server",
"g-name", "org.fedorahosted.Eekboard",
"g-connection", connection,
"g-interface-name", "org.fedorahosted.Eekboard.Context",
"g-object-path", object_path,
@ -415,38 +371,29 @@ context_async_ready_callback (GObject *source_object,
/**
* eekboard_context_add_keyboard:
* @context: an #EekboardContext
* @keyboard: an #EekKeyboard
* @keyboard: a string representing keyboard
* @cancellable: a #GCancellable
*
* Register @keyboard in @context.
*/
guint
eekboard_context_add_keyboard (EekboardContext *context,
EekKeyboard *keyboard,
const gchar *keyboard,
GCancellable *cancellable)
{
EekboardContextPrivate *priv;
GVariant *variant, *result;
GVariant *result;
GError *error;
g_return_val_if_fail (EEKBOARD_IS_CONTEXT(context), 0);
g_return_val_if_fail (EEK_IS_KEYBOARD(keyboard), 0);
priv = EEKBOARD_CONTEXT_GET_PRIVATE (context);
variant = eek_serializable_serialize (EEK_SERIALIZABLE(keyboard));
if (g_variant_is_floating (variant))
g_variant_ref_sink (variant);
error = NULL;
result = g_dbus_proxy_call_sync (G_DBUS_PROXY(context),
"AddKeyboard",
g_variant_new ("(v)", variant),
g_variant_new ("(s)", keyboard),
G_DBUS_CALL_FLAGS_NONE,
-1,
cancellable,
&error);
g_variant_unref (variant);
if (result) {
guint keyboard_id;
@ -454,11 +401,6 @@ eekboard_context_add_keyboard (EekboardContext *context,
g_variant_get (result, "(u)", &keyboard_id);
g_variant_unref (result);
if (keyboard_id != 0) {
g_hash_table_insert (priv->keyboard_hash,
GUINT_TO_POINTER(keyboard_id),
g_object_ref (keyboard));
}
return keyboard_id;
}
return 0;
@ -477,20 +419,8 @@ eekboard_context_remove_keyboard (EekboardContext *context,
guint keyboard_id,
GCancellable *cancellable)
{
EekboardContextPrivate *priv;
EekKeyboard *keyboard;
g_return_if_fail (EEKBOARD_IS_CONTEXT(context));
priv = EEKBOARD_CONTEXT_GET_PRIVATE (context);
keyboard = g_hash_table_lookup (priv->keyboard_hash,
GUINT_TO_POINTER(keyboard_id));
if (keyboard == priv->keyboard)
priv->keyboard = NULL;
g_hash_table_remove (priv->keyboard_hash, GUINT_TO_POINTER(keyboard_id));
g_dbus_proxy_call (G_DBUS_PROXY(context),
"RemoveKeyboard",
g_variant_new ("(u)", keyboard_id),
@ -514,20 +444,8 @@ eekboard_context_set_keyboard (EekboardContext *context,
guint keyboard_id,
GCancellable *cancellable)
{
EekboardContextPrivate *priv;
EekKeyboard *keyboard;
g_return_if_fail (EEKBOARD_IS_CONTEXT(context));
priv = EEKBOARD_CONTEXT_GET_PRIVATE (context);
keyboard = g_hash_table_lookup (priv->keyboard_hash,
GUINT_TO_POINTER(keyboard_id));
if (!keyboard || keyboard == priv->keyboard)
return;
priv->keyboard = keyboard;
g_dbus_proxy_call (G_DBUS_PROXY(context),
"SetKeyboard",
g_variant_new ("(u)", keyboard_id),
@ -557,10 +475,7 @@ eekboard_context_set_group (EekboardContext *context,
priv = EEKBOARD_CONTEXT_GET_PRIVATE (context);
g_return_if_fail (priv->keyboard);
if (eek_element_get_group (EEK_ELEMENT(priv->keyboard)) != group) {
eek_element_set_group (EEK_ELEMENT(priv->keyboard), group);
if (priv->group != group) {
g_dbus_proxy_call (G_DBUS_PROXY(context),
"SetGroup",
g_variant_new ("(i)", group),
@ -572,6 +487,25 @@ eekboard_context_set_group (EekboardContext *context,
}
}
/**
* eekboard_context_get_group:
* @context: an #EekboardContext
* @cancellable: a #GCancellable
*
* Get the keyboard group of @context.
*/
gint
eekboard_context_get_group (EekboardContext *context,
GCancellable *cancellable)
{
EekboardContextPrivate *priv;
g_return_val_if_fail (EEKBOARD_IS_CONTEXT(context), 0);
priv = EEKBOARD_CONTEXT_GET_PRIVATE (context);
return priv->group;
}
/**
* eekboard_context_show_keyboard:
* @context: an #EekboardContext
@ -632,7 +566,7 @@ eekboard_context_hide_keyboard (EekboardContext *context,
}
/**
* eekboard_context_press_key:
* eekboard_context_press_keycode:
* @context: an #EekboardContext
* @keycode: keycode number
* @cancellable: a #GCancellable
@ -640,7 +574,7 @@ eekboard_context_hide_keyboard (EekboardContext *context,
* Tell eekboard-server that a key identified by @keycode is pressed.
*/
void
eekboard_context_press_key (EekboardContext *context,
eekboard_context_press_keycode (EekboardContext *context,
guint keycode,
GCancellable *cancellable)
{
@ -653,7 +587,7 @@ eekboard_context_press_key (EekboardContext *context,
return;
g_dbus_proxy_call (G_DBUS_PROXY(context),
"PressKey",
"PressKeycode",
g_variant_new ("(u)", keycode),
G_DBUS_CALL_FLAGS_NONE,
-1,
@ -663,7 +597,7 @@ eekboard_context_press_key (EekboardContext *context,
}
/**
* eekboard_context_release_key:
* eekboard_context_release_keycode:
* @context: an #EekboardContext
* @keycode: keycode number
* @cancellable: a #GCancellable
@ -671,7 +605,7 @@ eekboard_context_press_key (EekboardContext *context,
* Tell eekboard-server that a key identified by @keycode is released.
*/
void
eekboard_context_release_key (EekboardContext *context,
eekboard_context_release_keycode (EekboardContext *context,
guint keycode,
GCancellable *cancellable)
{
@ -684,7 +618,7 @@ eekboard_context_release_key (EekboardContext *context,
return;
g_dbus_proxy_call (G_DBUS_PROXY(context),
"ReleaseKey",
"ReleaseKeycode",
g_variant_new ("(u)", keycode),
G_DBUS_CALL_FLAGS_NONE,
-1,
@ -694,20 +628,20 @@ eekboard_context_release_key (EekboardContext *context,
}
/**
* eekboard_context_is_keyboard_visible:
* eekboard_context_is_visible:
* @context: an #EekboardContext
*
* Check if keyboard is visible.
*/
gboolean
eekboard_context_is_keyboard_visible (EekboardContext *context)
eekboard_context_is_visible (EekboardContext *context)
{
EekboardContextPrivate *priv;
g_assert (EEKBOARD_IS_CONTEXT(context));
priv = EEKBOARD_CONTEXT_GET_PRIVATE (context);
return priv->enabled && priv->keyboard_visible;
return priv->enabled && priv->visible;
}
/**

View File

@ -15,9 +15,8 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(__EEKBOARD_H_INSIDE__) && !defined(EEKBOARD_COMPILATION)
#error "Only <eekboard/eekboard.h> can be included directly."
#if !defined(__EEKBOARD_CLIENT_H_INSIDE__) && !defined(EEKBOARD_COMPILATION)
#error "Only <eekboard/eekboard-client.h> can be included directly."
#endif
#ifndef EEKBOARD_CONTEXT_H
@ -57,7 +56,7 @@ struct _EekboardContext {
* @enabled: class handler for #EekboardContext::enabled signal
* @disabled: class handler for #EekboardContext::disabled signal
* @key_pressed: class handler for #EekboardContext::key-pressed signal
* @key_released: class handler for #EekboardContext::key-released signal
* @destroyed: class handler for #EekboardContext::destroyed signal
*/
struct _EekboardContextClass {
/*< private >*/
@ -68,14 +67,14 @@ struct _EekboardContextClass {
void (*enabled) (EekboardContext *self);
void (*disabled) (EekboardContext *self);
void (*key_pressed) (EekboardContext *self,
guint keycode);
void (*key_released) (EekboardContext *self,
guint keycode);
const gchar *keyname,
EekSymbol *symbol,
guint modifiers);
void (*destroyed) (EekboardContext *self);
/*< private >*/
/* padding */
gpointer pdummy[23];
gpointer pdummy[24];
};
GType eekboard_context_get_type (void) G_GNUC_CONST;
@ -84,7 +83,7 @@ EekboardContext *eekboard_context_new (GDBusConnection *connection,
const gchar *object_path,
GCancellable *cancellable);
guint eekboard_context_add_keyboard (EekboardContext *context,
EekKeyboard *keyboard,
const gchar *keyboard,
GCancellable *cancellable);
void eekboard_context_remove_keyboard (EekboardContext *context,
guint keyboard_id,
@ -99,10 +98,12 @@ void eekboard_context_hide_keyboard (EekboardContext *context,
void eekboard_context_set_group (EekboardContext *context,
gint group,
GCancellable *cancellable);
void eekboard_context_press_key (EekboardContext *context,
gint eekboard_context_get_group (EekboardContext *context,
GCancellable *cancellable);
void eekboard_context_press_keycode (EekboardContext *context,
guint keycode,
GCancellable *cancellable);
void eekboard_context_release_key (EekboardContext *context,
void eekboard_context_release_keycode (EekboardContext *context,
guint keycode,
GCancellable *cancellable);
gboolean eekboard_context_is_keyboard_visible

View File

@ -1,81 +0,0 @@
/*
* Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2010-2011 Red Hat, Inc.
*
* 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/>.
*/
#if !defined(__EEKBOARD_H_INSIDE__) && !defined(EEKBOARD_COMPILATION)
#error "Only <eekboard/eekboard.h> can be included directly."
#endif
#ifndef EEKBOARD_EEKBOARD_H
#define EEKBOARD_EEKBOARD_H 1
#include <gio/gio.h>
#include "eekboard/eekboard-context.h"
G_BEGIN_DECLS
#define EEKBOARD_TYPE_EEKBOARD (eekboard_eekboard_get_type())
#define EEKBOARD_EEKBOARD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEKBOARD_TYPE_EEKBOARD, EekboardEekboard))
#define EEKBOARD_EEKBOARD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEKBOARD_TYPE_EEKBOARD, EekboardEekboardClass))
#define EEKBOARD_IS_EEKBOARD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEKBOARD_TYPE_EEKBOARD))
#define EEKBOARD_IS_EEKBOARD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEKBOARD_TYPE_EEKBOARD))
#define EEKBOARD_EEKBOARD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEKBOARD_TYPE_EEKBOARD, EekboardEekboardClass))
typedef struct _EekboardEekboard EekboardEekboard;
typedef struct _EekboardEekboardClass EekboardEekboardClass;
typedef struct _EekboardEekboardPrivate EekboardEekboardPrivate;
struct _EekboardEekboard {
/*< private >*/
GDBusProxy parent;
EekboardEekboardPrivate *priv;
};
struct _EekboardEekboardClass {
/*< private >*/
GDBusProxyClass parent_class;
/* signals */
void (* destroyed) (EekboardEekboard *self);
/*< private >*/
/* padding */
gpointer pdummy[23];
};
GType eekboard_eekboard_get_type (void) G_GNUC_CONST;
EekboardEekboard *eekboard_eekboard_new (GDBusConnection *connection,
GCancellable *cancellable);
EekboardContext *eekboard_eekboard_create_context
(EekboardEekboard *eekboard,
const gchar *client_name,
GCancellable *cancellable);
void eekboard_eekboard_push_context
(EekboardEekboard *eekboard,
EekboardContext *context,
GCancellable *cancellable);
void eekboard_eekboard_pop_context (EekboardEekboard *eekboard,
GCancellable *cancellable);
void eekboard_eekboard_destroy_context
(EekboardEekboard *eekboard,
EekboardContext *context,
GCancellable *cancellable);
G_END_DECLS
#endif /* EEKBOARD_EEKBOARD_H */

View File

@ -0,0 +1 @@
VOID:STRING,OBJECT,UINT

505
eekboard/eekboard-service.c Normal file
View File

@ -0,0 +1,505 @@
/*
* Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2010-2011 Red Hat, Inc.
*
* 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/>.
*/
/**
* SECTION:eekboard-service
* @short_description: base server implementation of eekboard service
*
* The #EekboardService class provides a base server side
* implementation of eekboard service.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#include "eekboard/eekboard-service.h"
enum {
PROP_0,
PROP_OBJECT_PATH,
PROP_CONNECTION,
PROP_LAST
};
enum {
DESTROYED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0, };
#define EEKBOARD_SERVICE_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEKBOARD_TYPE_SERVICE, EekboardServicePrivate))
struct _EekboardServicePrivate {
GDBusConnection *connection;
GDBusNodeInfo *introspection_data;
guint registration_id;
char *object_path;
GHashTable *context_hash;
GSList *context_stack;
};
G_DEFINE_TYPE (EekboardService, eekboard_service, G_TYPE_OBJECT);
static const gchar introspection_xml[] =
"<node>"
" <interface name='org.fedorahosted.Eekboard'>"
" <method name='CreateContext'>"
" <arg direction='in' type='s' name='client_name'/>"
" <arg direction='out' type='s' name='object_path'/>"
" </method>"
" <method name='PushContext'>"
" <arg direction='in' type='s' name='object_path'/>"
" </method>"
" <method name='PopContext'/>"
" <method name='DestroyContext'>"
" <arg direction='in' type='s' name='object_path'/>"
" </method>"
" <method name='Destroy'/>"
/* signals */
" </interface>"
"</node>";
static void handle_method_call (GDBusConnection *connection,
const gchar *sender,
const gchar *object_path,
const gchar *interface_name,
const gchar *method_name,
GVariant *parameters,
GDBusMethodInvocation *invocation,
gpointer user_data);
static const GDBusInterfaceVTable interface_vtable =
{
handle_method_call,
NULL,
NULL
};
static void
eekboard_service_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
EekboardService *service = EEKBOARD_SERVICE(object);
EekboardServicePrivate *priv = EEKBOARD_SERVICE_GET_PRIVATE(service);
GDBusConnection *connection;
switch (prop_id) {
case PROP_OBJECT_PATH:
if (priv->object_path)
g_free (priv->object_path);
priv->object_path = g_strdup (g_value_get_string (value));
break;
case PROP_CONNECTION:
connection = g_value_get_object (value);
if (priv->connection)
g_object_unref (priv->connection);
priv->connection = g_object_ref (connection);
break;
default:
g_object_set_property (object,
g_param_spec_get_name (pspec),
value);
break;
}
}
static void
eekboard_service_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
EekboardService *service = EEKBOARD_SERVICE(object);
EekboardServicePrivate *priv = EEKBOARD_SERVICE_GET_PRIVATE(service);
switch (prop_id) {
case PROP_OBJECT_PATH:
g_value_set_string (value, priv->object_path);
break;
case PROP_CONNECTION:
g_value_set_object (value, priv->connection);
break;
default:
g_object_set_property (object,
g_param_spec_get_name (pspec),
value);
break;
}
}
static void
eekboard_service_dispose (GObject *object)
{
EekboardService *service = EEKBOARD_SERVICE(object);
EekboardServicePrivate *priv = EEKBOARD_SERVICE_GET_PRIVATE(service);
GSList *head;
if (priv->context_hash) {
g_hash_table_destroy (priv->context_hash);
priv->context_hash = NULL;
}
for (head = priv->context_stack; head; head = priv->context_stack) {
g_object_unref (head->data);
priv->context_stack = g_slist_next (head);
g_slist_free1 (head);
}
if (priv->connection) {
if (priv->registration_id > 0) {
g_dbus_connection_unregister_object (priv->connection,
priv->registration_id);
priv->registration_id = 0;
}
g_object_unref (priv->connection);
priv->connection = NULL;
}
if (priv->introspection_data) {
g_dbus_node_info_unref (priv->introspection_data);
priv->introspection_data = NULL;
}
G_OBJECT_CLASS (eekboard_service_parent_class)->dispose (object);
}
static void
eekboard_service_finalize (GObject *object)
{
EekboardServicePrivate *priv = EEKBOARD_SERVICE_GET_PRIVATE(object);
g_free (priv->object_path);
G_OBJECT_CLASS (eekboard_service_parent_class)->finalize (object);
}
static void
eekboard_service_constructed (GObject *object)
{
EekboardServicePrivate *priv = EEKBOARD_SERVICE_GET_PRIVATE(object);
if (priv->connection && priv->object_path) {
GError *error = NULL;
priv->registration_id = g_dbus_connection_register_object
(priv->connection,
priv->object_path,
priv->introspection_data->interfaces[0],
&interface_vtable,
object,
NULL,
&error);
}
}
static void
eekboard_service_class_init (EekboardServiceClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GParamSpec *pspec;
g_type_class_add_private (gobject_class,
sizeof (EekboardServicePrivate));
klass->create_context = NULL;
gobject_class->constructed = eekboard_service_constructed;
gobject_class->set_property = eekboard_service_set_property;
gobject_class->get_property = eekboard_service_get_property;
gobject_class->dispose = eekboard_service_dispose;
gobject_class->finalize = eekboard_service_finalize;
/**
* EekboardService::destroyed:
* @service: an #EekboardService
*
* The ::destroyed signal is emitted when the service is vanished.
*/
signals[DESTROYED] =
g_signal_new (I_("destroyed"),
G_TYPE_FROM_CLASS(gobject_class),
G_SIGNAL_RUN_LAST,
0,
NULL,
NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0);
/**
* EekboardService:object-path:
*
* D-Bus object path.
*/
pspec = g_param_spec_string ("object-path",
"Object-path",
"Object-path",
NULL,
G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
g_object_class_install_property (gobject_class,
PROP_OBJECT_PATH,
pspec);
/**
* EekboardService:connection:
*
* D-Bus connection.
*/
pspec = g_param_spec_object ("connection",
"Connection",
"Connection",
G_TYPE_DBUS_CONNECTION,
G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
g_object_class_install_property (gobject_class,
PROP_CONNECTION,
pspec);
}
static void
eekboard_service_init (EekboardService *service)
{
EekboardServicePrivate *priv;
GError *error;
priv = service->priv = EEKBOARD_SERVICE_GET_PRIVATE(service);
error = NULL;
priv->introspection_data =
g_dbus_node_info_new_for_xml (introspection_xml, &error);
g_assert (priv->introspection_data != NULL);
priv->context_hash =
g_hash_table_new_full (g_str_hash,
g_str_equal,
(GDestroyNotify)g_free,
(GDestroyNotify)g_object_unref);
}
static void
remove_context_from_stack (EekboardService *service,
EekboardContextService *context)
{
EekboardServicePrivate *priv = EEKBOARD_SERVICE_GET_PRIVATE(service);
GSList *head;
head = g_slist_find (priv->context_stack, context);
if (head) {
priv->context_stack = g_slist_remove_link (priv->context_stack, head);
g_object_unref (head->data);
g_slist_free1 (head);
}
if (priv->context_stack)
eekboard_context_service_enable (priv->context_stack->data);
}
static void
service_name_vanished_callback (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
EekboardService *service = user_data;
EekboardServicePrivate *priv = EEKBOARD_SERVICE_GET_PRIVATE(service);
GSList *head;
GHashTableIter iter;
gpointer k, v;
g_hash_table_iter_init (&iter, priv->context_hash);
while (g_hash_table_iter_next (&iter, &k, &v)) {
const gchar *owner = g_object_get_data (G_OBJECT(v), "owner");
if (g_strcmp0 (owner, name) == 0)
g_hash_table_iter_remove (&iter);
}
for (head = priv->context_stack; head; ) {
const gchar *owner = g_object_get_data (G_OBJECT(head->data), "owner");
GSList *next = g_slist_next (head);
if (g_strcmp0 (owner, name) == 0) {
priv->context_stack =
g_slist_remove_link (priv->context_stack, head);
g_object_unref (head->data);
g_slist_free1 (head);
}
head = next;
}
if (priv->context_stack)
eekboard_context_service_enable (priv->context_stack->data);
}
static void
handle_method_call (GDBusConnection *connection,
const gchar *sender,
const gchar *object_path,
const gchar *interface_name,
const gchar *method_name,
GVariant *parameters,
GDBusMethodInvocation *invocation,
gpointer user_data)
{
EekboardService *service = user_data;
EekboardServicePrivate *priv = EEKBOARD_SERVICE_GET_PRIVATE(service);
EekboardServiceClass *klass = EEKBOARD_SERVICE_GET_CLASS(service);
if (g_strcmp0 (method_name, "CreateContext") == 0) {
const gchar *client_name;
gchar *object_path;
static gint context_id = 0;
EekboardContextService *context;
g_variant_get (parameters, "(&s)", &client_name);
object_path = g_strdup_printf (EEKBOARD_CONTEXT_SERVICE_PATH, context_id++);
g_assert (klass->create_context);
context = klass->create_context (service, client_name, object_path);
g_object_set_data_full (G_OBJECT(context),
"owner", g_strdup (sender),
(GDestroyNotify)g_free);
g_hash_table_insert (priv->context_hash,
object_path,
context);
/* the vanished callback is called when clients are disconnected */
g_bus_watch_name_on_connection (priv->connection,
sender,
G_BUS_NAME_WATCHER_FLAGS_NONE,
NULL,
service_name_vanished_callback,
service,
NULL);
g_dbus_method_invocation_return_value (invocation,
g_variant_new ("(s)",
object_path));
return;
}
if (g_strcmp0 (method_name, "PushContext") == 0) {
const gchar *object_path;
EekboardContextService *context;
g_variant_get (parameters, "(&s)", &object_path);
context = g_hash_table_lookup (priv->context_hash, object_path);
if (!context) {
g_dbus_method_invocation_return_error (invocation,
G_IO_ERROR,
G_IO_ERROR_FAILED_HANDLED,
"context not found");
return;
}
if (priv->context_stack)
eekboard_context_service_disable (priv->context_stack->data);
priv->context_stack = g_slist_prepend (priv->context_stack,
g_object_ref (context));
eekboard_context_service_enable (context);
g_dbus_method_invocation_return_value (invocation, NULL);
return;
}
if (g_strcmp0 (method_name, "PopContext") == 0) {
if (priv->context_stack) {
EekboardContextService *context = priv->context_stack->data;
gchar *object_path;
const gchar *owner;
g_object_get (G_OBJECT(context), "object-path", &object_path, NULL);
owner = g_object_get_data (G_OBJECT(context), "owner");
if (g_strcmp0 (owner, sender) != 0) {
g_dbus_method_invocation_return_error
(invocation,
G_IO_ERROR,
G_IO_ERROR_FAILED_HANDLED,
"context at %s not owned by %s",
object_path, sender);
return;
}
g_free (object_path);
eekboard_context_service_disable (context);
priv->context_stack = g_slist_next (priv->context_stack);
if (priv->context_stack)
eekboard_context_service_enable (priv->context_stack->data);
}
g_dbus_method_invocation_return_value (invocation, NULL);
return;
}
if (g_strcmp0 (method_name, "DestroyContext") == 0) {
EekboardContextService *context;
const gchar *object_path;
const gchar *owner;
g_variant_get (parameters, "(&s)", &object_path);
context = g_hash_table_lookup (priv->context_hash, object_path);
if (!context) {
g_dbus_method_invocation_return_error (invocation,
G_IO_ERROR,
G_IO_ERROR_FAILED_HANDLED,
"context not found");
return;
}
owner = g_object_get_data (G_OBJECT(context), "owner");
if (g_strcmp0 (owner, sender) != 0) {
g_dbus_method_invocation_return_error
(invocation,
G_IO_ERROR,
G_IO_ERROR_FAILED_HANDLED,
"the context at %s not owned by %s",
object_path, sender);
return;
}
remove_context_from_stack (service, context);
g_hash_table_remove (priv->context_hash, object_path);
g_dbus_method_invocation_return_value (invocation, NULL);
return;
}
if (g_strcmp0 (method_name, "Destroy") == 0) {
g_signal_emit_by_name (service, "destroyed", NULL);
g_dbus_method_invocation_return_value (invocation, NULL);
return;
}
g_return_if_reached ();
}
/**
* eekboard_service_new:
* @connection: a #GDBusConnection
* @object_path: object path
*
* Create an empty server for testing purpose.
*/
EekboardService *
eekboard_service_new (GDBusConnection *connection,
const gchar *object_path)
{
return g_object_new (EEKBOARD_TYPE_SERVICE,
"object-path", object_path,
"connection", connection,
NULL);
}

View File

@ -0,0 +1,77 @@
/*
* Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2010-2011 Red Hat, Inc.
*
* 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/>.
*/
#ifndef EEKBOARD_SERVICE_H
#define EEKBOARD_SERVICE_H 1
#define __EEKBOARD_SERVICE_H_INSIDE__ 1
#include "eekboard/eekboard-context-service.h"
G_BEGIN_DECLS
#define EEKBOARD_SERVICE_PATH "/org/fedorahosted/Eekboard"
#define EEKBOARD_SERVICE_INTERFACE "org.fedorahosted.Eekboard"
#define EEKBOARD_TYPE_SERVICE (eekboard_service_get_type())
#define EEKBOARD_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEKBOARD_TYPE_SERVICE, EekboardService))
#define EEKBOARD_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEKBOARD_TYPE_SERVICE, EekboardServiceClass))
#define EEKBOARD_IS_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEKBOARD_TYPE_SERVICE))
#define EEKBOARD_IS_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEKBOARD_TYPE_SERVICE))
#define EEKBOARD_SERVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEKBOARD_TYPE_SERVICE, EekboardServiceClass))
typedef struct _EekboardService EekboardService;
typedef struct _EekboardServiceClass EekboardServiceClass;
typedef struct _EekboardServicePrivate EekboardServicePrivate;
/**
* EekboardService:
*
* The #EekboardService structure contains only private data and
* should only be accessed using the provided API.
*/
struct _EekboardService {
/*< private >*/
GObject parent;
EekboardServicePrivate *priv;
};
/**
* EekboardServiceClass:
* @create_context: virtual function for creating a context
*/
struct _EekboardServiceClass {
/*< private >*/
GObjectClass parent_class;
/*< public >*/
EekboardContextService *(*create_context) (EekboardService *self,
const gchar *client_name,
const gchar *object_path);
/*< private >*/
/* padding */
gpointer pdummy[24];
};
GType eekboard_service_get_type (void) G_GNUC_CONST;
EekboardService * eekboard_service_new (GDBusConnection *connection,
const gchar *object_path);
G_END_DECLS
#endif /* EEKBOARD_SERVICE_H */

View File

@ -18,16 +18,19 @@
* 02110-1301 USA
*/
#include <string.h>
#include "xklutil.h"
#include "eekboard/eekboard-xklutil.h"
XklConfigRec *
eekboard_xkl_config_rec_new_from_string (const gchar *layouts)
eekboard_xkl_config_rec_from_string (const gchar *layouts)
{
XklConfigRec *rec;
gchar **l, **v;
gchar **strv, **l, **v;
gint i;
l = g_strsplit (layouts, ",", -1);
strv = g_strsplit (layouts, "/", -1);
g_return_val_if_fail (g_strv_length (strv) == 3, NULL);
l = g_strsplit (strv[1], ";", -1);
v = g_strdupv (l);
for (i = 0; l[i]; i++) {
gchar *layout = l[i], *variant = v[i],
@ -44,12 +47,48 @@ eekboard_xkl_config_rec_new_from_string (const gchar *layouts)
}
rec = xkl_config_rec_new ();
rec->model = g_strdup (strv[0]);
rec->layouts = l;
rec->variants = v;
rec->options = g_strsplit (strv[2], ";", -1);
g_strfreev (strv);
return rec;
}
gchar *
eekboard_xkl_config_rec_to_string (XklConfigRec *rec)
{
gchar **strv, **sp, **lp, **vp, *p;
gint n_layouts;
GString *str;
n_layouts = g_strv_length (rec->layouts);
strv = g_malloc0_n (n_layouts + 2, sizeof (gchar *));
for (sp = strv, lp = rec->layouts, vp = rec->variants; *lp; sp++, lp++) {
if (*vp != NULL && **vp != '\0')
*sp = g_strdup_printf ("%s(%s)", *lp, *vp++);
else
*sp = g_strdup_printf ("%s", *lp);
}
/* MODEL/L0(V0);L1(V1);...;Ln(Vn)/O0;O1;...;On */
str = g_string_new (rec->model);
g_string_append_c (str, '/');
p = g_strjoinv (";", strv);
g_strfreev (strv);
g_string_append (str, p);
g_free (p);
g_string_append_c (str, '/');
p = g_strjoinv (";", rec->options);
g_string_append (str, p);
g_free (p);
return g_string_free (str,FALSE);
}
static XklConfigItem *
xkl_config_item_copy (const XklConfigItem *item)
{

View File

@ -24,8 +24,8 @@
G_BEGIN_DECLS
XklConfigRec *eekboard_xkl_config_rec_new_from_string
(const gchar *layouts);
XklConfigRec *eekboard_xkl_config_rec_from_string (const gchar *layouts);
gchar *eekboard_xkl_config_rec_to_string (XklConfigRec *rec);
GSList *eekboard_xkl_list_models (XklConfigRegistry *registry);
GSList *eekboard_xkl_list_layouts (XklConfigRegistry *registry);

View File

@ -1 +1 @@
SUBDIRS = eekboard-inscript simple-client
SUBDIRS = eekxml simple-client

View File

@ -1,14 +0,0 @@
bin_SCRIPTS = eekboard-inscript
keyboarddir = $(pkgdatadir)/keyboards
eekboard_inscript_datadir = $(datarootdir)/eekboard-inscript
eekboard_inscript_data_PYTHON = inscript.py main.py
eekboard-inscript: eekboard-inscript.in
$(AM_V_GEN) sed -e 's!@''PYTHON@!'$(PYTHON)'!' \
-e 's!@EEKBOARD_KEYBOARDDIR@!'$(keyboarddir)'!' \
-e 's!@M17N_DIR@!'$(datadir)/m17n'!' \
-e 's!@EEKBOARD_INSCRIPT_DATADIR@!'$(eekboard_inscript_datadir)'!' < $< > $@
CLEANFILES = eekboard-inscript
EXTRA_DIST = eekboard-inscript.in

View File

@ -1,23 +0,0 @@
#!/bin/sh
# Copyright (C) 2011 Daiki Ueno <ueno@unixuser.org>
# Copyright (C) 2011 Red Hat, Inc.
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
# This library 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
# Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA
export EEKBOARD_KEYBOARDDIR=@EEKBOARD_KEYBOARDDIR@
export M17N_DIR=@M17N_DIR@
exec @PYTHON@ @EEKBOARD_INSCRIPT_DATADIR@/main.py $@

View File

@ -1,226 +0,0 @@
#!/usr/bin/env python
# Copyright (C) 2011 Daiki Ueno <ueno@unixuser.org>
# Copyright (C) 2011 Red Hat, Inc.
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
# This library 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
# Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA
import eekboard
import gobject, gtk, virtkey
import sys, os.path, re
KEYCODE_TABLE = {
'1': 10, '2': 11, '3': 12, '4': 13, '5': 14, '6': 15, '7': 16, '8': 17,
'9': 18, '0': 19, '-': 20, '=': 21, 'q': 24, 'w': 25, 'e': 26, 'r': 27,
't': 28, 'y': 29, 'u': 30, 'i': 31, 'o': 32, 'p': 33, '[': 34, ']': 35,
'a': 38, 's': 39, 'd': 40, 'f': 41, 'g': 42, 'h': 43, 'j': 44, 'k': 45,
'l': 46, ';': 47, '\'': 48, '`': 49, '\\': 51, 'z': 52, 'x': 53, 'c': 54,
'v': 55, 'b': 56, 'n': 57, 'm': 58, ',': 59, '.': 60, '/': 61
}
MARK_UPPER = '~!@#$%^&*()_+{}|:"<>?'
MARK_LOWER = '`1234567890-=[]\\;\',./'
INSCRIPT_MAPS = (
"as-inscript",
"bn-inscript",
"gu-inscript",
"hi-inscript",
"kn-inscript",
"ml-inscript",
"mr-inscript",
"or-inscript",
"pa-inscript",
"sd-inscript",
"ta-inscript",
"te-inscript",
"kn-inscript2",
"kok-inscript2-deva",
"mai-inscript2",
"ml-inscript2",
"mni-inscript2-beng",
"mni-inscript2-mtei",
"mr-inscript2",
"ne-inscript2-deva",
"or-inscript2",
"pa-inscript2-guru",
"sa-inscript2",
"sat-inscript2-deva",
"sat-inscript2-olck",
"sd-inscript2-deva",
"ta-inscript2",
"te-inscript2")
class MapFile(object):
MAPENTRY_PATTERN = re.compile(r'\A\s*\((?:\((.*?)\)|"(.*?)")\s*"(.*?)"\)')
def __init__(self, path):
self.__dict = dict()
with open(path, 'r') as fp:
for line in fp:
match = re.match(self.MAPENTRY_PATTERN, line)
if match:
insert = match.group(3).decode('UTF-8')
if match.group(1):
keyseq = re.sub(r'\\(.)', r'\1', match.group(1))
self.__add_symbol_entry(keyseq, insert)
else:
keyseq = re.sub(r'\\(.)', r'\1', match.group(2))
self.__add_text_entry(keyseq, insert)
def get_entry_for_keycode(self, keycode):
return self.__dict.get(keycode)
def __add_entry(self, letter, level, insert):
if letter.isupper():
level |= 1
letter = letter.lower()
elif letter in MARK_UPPER:
level |= 1
letter = MARK_LOWER[MARK_UPPER.index(letter)]
keycode = KEYCODE_TABLE[letter]
if keycode not in self.__dict:
self.__dict[keycode] = list([None,None,None,None])
self.__dict[keycode][level] = insert
def __add_symbol_entry(self, symbol, insert):
level = 0
if symbol.startswith('G-'):
level |= 2
symbol = symbol[2:]
if not symbol.startswith('KP_'):
self.__add_entry(symbol, level, insert)
def __add_text_entry(self, text, insert):
self.__add_entry(text, 0, insert)
class Keyboard(gobject.GObject):
__gtype_name__ = "PYInscriptKeyboard"
__gsignals__ = {
'quit': (
gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE,
()),
}
def __init__(self, client_name, map_path, kbd_path):
super(Keyboard, self).__init__()
self.__keyboard = self.__create_keyboard(map_path, kbd_path)
self.__eekboard = eekboard.Eekboard()
self.__context = self.__eekboard.create_context(client_name)
keyboard_id = self.__context.add_keyboard(self.__keyboard)
self.__context.set_keyboard(keyboard_id)
self.__keyboard.connect('key-pressed', self.__key_pressed_cb)
self.__keyboard.connect('key-released', self.__key_released_cb)
self.__virtkey = virtkey.virtkey()
self.__english = False
self.__eekboard.connect('destroyed', self.__destroyed_cb)
self.__context.connect('destroyed', self.__destroyed_cb)
self.__context.connect('notify::keyboard-visible', self.__notify_keyboard_visible_cb)
def __create_keyboard(self, map_path, kbd_path):
def __each_key(element, data):
keycode = element.get_keycode()
# keycode 37 is used to toggle English/Inscript
if keycode == 37:
matrix = eekboard.SymbolMatrix.new(2, 1)
keysym = eekboard.Keysym.new(0)
keysym.set_label("Ind")
keysym.set_category(eekboard.SymbolCategory.FUNCTION)
matrix.set_symbol(0, 0, keysym)
keysym = eekboard.Keysym.new(0)
keysym.set_label("Eng")
keysym.set_category(eekboard.SymbolCategory.FUNCTION)
matrix.set_symbol(1, 0, keysym)
element.set_symbol_matrix(matrix)
return
# group(0) is us keyboard
matrix = eekboard.SymbolMatrix.new(2, 4)
for l in xrange(4):
keysym = element.get_symbol_at_index(0, l, 0, 0)
matrix.set_symbol(0, l, keysym)
# group(1) is inscript keyboard
entry = data.get_entry_for_keycode(keycode)
for l in xrange(4):
if entry and entry[l]:
try:
keyval = gtk.gdk.unicode_to_keyval(ord(entry[l]))
keysym = eekboard.Keysym.new(keyval)
except:
keysym = eekboard.Keysym.new(0)
keysym.set_label(entry[l].encode('UTF-8'))
keysym.set_category(eekboard.SymbolCategory.LETTER)
print >> sys.stderr, "can't convert %s (%d) to keyval" % (entry[l], keycode)
else:
keysym = element.get_symbol_at_index(1, l, 0, 0)
matrix.set_symbol(1, l, keysym)
element.set_symbol_matrix(matrix)
def __each_section(element, data):
element.foreach_child(__each_key, data)
mapfile = MapFile(map_path)
keyboard = eekboard.XmlKeyboard(kbd_path,
eekboard.MODIFIER_BEHAVIOR_LATCH)
keyboard.foreach_child(__each_section, mapfile)
return keyboard
def __destroyed_cb(self, *args):
self.emit('quit')
def __notify_keyboard_visible_cb(self, obj, pspec):
if not obj.get_property(pspec.name):
self.emit('quit')
def enable(self):
self.__eekboard.push_context(self.__context)
def disable(self):
self.__eekboard.pop_context(self.__context)
def show(self):
self.__context.show_keyboard()
def set_group(self, group):
self.__group = group
self.__context.set_group(self.__group)
def __key_pressed_cb(self, keyboard, key):
if key.get_keycode() == 37:
return
symbol = key.get_symbol()
if isinstance(symbol, eekboard.Keysym):
xkeysym = symbol.get_xkeysym()
modifiers = self.__keyboard.get_modifiers()
self.__virtkey.latch_mod(modifiers)
self.__virtkey.press_keysym(xkeysym)
self.__virtkey.unlatch_mod(modifiers)
def __key_released_cb(self, keyboard, key):
if key.get_keycode() == 37:
if self.__english:
self.__context.set_group(self.__group)
self.__english = False
else:
self.__context.set_group(0)
self.__english = True
return
symbol = key.get_symbol()
if isinstance(symbol, eekboard.Keysym):
xkeysym = symbol.get_xkeysym()
self.__virtkey.release_keysym(xkeysym)

View File

@ -1,60 +0,0 @@
# Copyright (C) 2011 Daiki Ueno <ueno@unixuser.org>
# Copyright (C) 2011 Red Hat, Inc.
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
# This library 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
# Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA
import inscript
import gtk
from optparse import OptionParser
import sys, os, os.path, glob
parser = OptionParser()
parser.add_option("-n", "--name=LANGCODE", dest="langcode",
help="Specify language code to LANGCODE",
metavar="LANGCODE")
parser.add_option("-l", "--list", dest="list", default=False,
action="store_true",
help="List available language codes")
(options, args) = parser.parse_args()
if options.list:
pat = os.path.join(os.getenv("M17N_DIR"), "*.mim")
for fname in sorted(glob.glob(pat)):
mname = os.path.basename(fname[:-4])
if mname in inscript.INSCRIPT_MAPS:
print mname
exit(0)
if options.langcode is None:
print >> sys.stderr, "Specify language code with -n"
exit(1)
map_path = os.path.join(os.getenv("M17N_DIR"), options.langcode + ".mim")
if not os.path.exists(map_path):
print >> sys.stderr, "%s not found" % map_path
exit(1)
kbd_path = os.path.join(os.getenv("EEKBOARD_KEYBOARDDIR"), "us-qwerty.xml")
if not os.path.exists(kbd_path):
print >> sys.stderr, "%s not found" % kbd_path
exit(1)
keyboard = inscript.Keyboard("eekboard-inscript", map_path, kbd_path)
keyboard.connect('quit', lambda *args: gtk.main_quit())
keyboard.set_group(1)
keyboard.enable()
keyboard.show()
gtk.main()

View File

@ -0,0 +1,6 @@
bin_SCRIPTS = eekxml
EXTRA_DIST = eekxml.in mim2remap
DISTCLEANFILES = eekxml
eekxml: eekxml.in
$(AM_V_GEN) sed '1s!@''PYTHON@!'$(PYTHON)'!' $< > $@

124
examples/eekxml/eekxml.in Normal file
View File

@ -0,0 +1,124 @@
#!@PYTHON@
# -*- python -*-
# Copyright (C) 2011 Daiki Ueno <ueno@unixuser.org>
# Copyright (C) 2011 Red Hat, Inc.
# 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 argparse
import json
from gi.repository import GLib, Gtk, Eek, EekXkl, EekGtk, Gio
DEFAULT_WIDTH = 640
DEFAULT_HEIGHT = 480
# XXX: level3 shift is not supported yet in remap files
def remap(keyboard, mapping):
def __each_key(element, data):
matrix = element.get_symbol_matrix()
for level in xrange(matrix.num_levels):
symbol = matrix.get_symbol(0, level)
if isinstance(symbol, Eek.Keysym):
mapped = data.get(symbol.get_name(), None)
if mapped:
if mapped.has_key('xkeysym'):
replace = Eek.Keysym.new(mapped['xkeysym'])
else:
replace = Eek.Symbol.new(mapped['name'])
replace.set_category(Eek.SymbolCategory.LETTER)
if mapped.has_key('label'):
replace.set_label(mapped['label'])
if mapped.has_key('category'):
replace.set_category(mapped['category'])
matrix.set_symbol(0, level, replace)
def __each_section(element, data):
element.foreach_child(__each_key, data)
keyboard.foreach_child(__each_section, mapping)
def create_keyboard(args):
if args.file:
_file = Gio.file_new_for_path(args.file)
layout = Eek.XmlLayout.new(_file.read(None))
else:
layout = EekXkl.Layout.new()
if args.model:
layout.set_model(args.model)
if args.layout:
layout.set_layouts(args.layout)
if args.variant:
layout.set_variants(args.variant)
if args.option:
layout.set_options(args.option)
keyboard = Eek.Keyboard.new(layout, DEFAULT_WIDTH, DEFAULT_HEIGHT)
if args.remap_file:
with open(args.remap_file) as remap_file:
mapping = json.load(remap_file)
remap(keyboard, mapping)
return keyboard
def show(args):
keyboard = create_keyboard(args)
keyboard.set_modifier_behavior(Eek.ModifierBehavior.LATCH)
widget = EekGtk.Keyboard.new(keyboard)
if args.theme:
theme = Eek.Theme.new(args.theme, None, None)
widget.set_theme(theme)
window = Gtk.Window.new(Gtk.WindowType.TOPLEVEL)
bounds = keyboard.get_bounds()
window.set_default_size(bounds.width, bounds.height)
window.connect('destroy', lambda *args: Gtk.main_quit())
window.add(widget)
window.show_all()
Gtk.main()
def dump(args):
keyboard = create_keyboard(args)
output = GLib.String()
keyboard.output(output, 0)
print output.str
# Add a simple function to print usage, for the 'help' command
def usage(args, parser):
parser.print_help()
def parse_cmdline():
parser = argparse.ArgumentParser(
description='manipulate XML files used by eekboard')
subparsers = parser.add_subparsers(help='sub-command help')
parser_help = subparsers.add_parser('help', help = 'show usage')
parser_help.set_defaults(command = lambda args: usage(args, parser=parser))
parser_common = subparsers.add_parser('common', add_help=False)
parser_common.add_argument('--model', help='specify XKB model')
parser_common.add_argument('--layout', help='specify XKB layout')
parser_common.add_argument('--variant', help='specify XKB variant')
parser_common.add_argument('--option', help='specify XKB option')
parser_common.add_argument('--file', help='specify XML layout file')
parser_common.add_argument('--remap-file', help='remap keysyms with the file')
parser_show = subparsers.add_parser('show',
help='show help',
parents=[parser_common])
parser_show.add_argument('--theme', help='use the theme file')
parser_show.add_argument('--group', help='switch to the given group')
parser_show.set_defaults(command = show)
parser_dump = subparsers.add_parser('dump',
help='dump help',
parents=[parser_common])
parser_dump.set_defaults(command = dump)
return parser.parse_args()
if __name__ == '__main__':
args = parse_cmdline()
args.command(args)

73
examples/eekxml/mim2remap Executable file
View File

@ -0,0 +1,73 @@
#!/usr/bin/env python
# Copyright (C) 2011 Daiki Ueno <ueno@unixuser.org>
# Copyright (C) 2011 Red Hat, Inc.
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
# This library 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
# Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA
import json
from gi.repository import Gdk
import sys, os.path, re
class MapFile(object):
MAPENTRY_PATTERN = re.compile(r'\A\s*\((?:\((.*?)\)|"(.*?)")\s*(?:"(.*?)"|\?(.*?))\)')
def __init__(self, path):
self.__dict = dict()
with open(path, 'r') as fp:
for line in fp:
match = re.match(self.MAPENTRY_PATTERN, line)
if match:
if match.group(1):
keyseq = re.sub(r'\\(.)', r'\1', match.group(1))
# should check G-* and A-*
else:
keyseq = re.sub(r'\\(.)', r'\1', match.group(2))
# combination of keys is not supported
if len(keyseq) > 1:
continue
try:
keyval = Gdk.unicode_to_keyval(ord(keyseq))
keyseq = Gdk.keyval_name(keyval)
except:
pass
if match.group(3):
insert = match.group(3).decode('UTF-8')
else:
insert = match.group(4).decode('UTF-8')
replace = {}
if len(insert) > 1:
replace = { 'name': insert,
'label': insert }
else:
try:
keyval = Gdk.unicode_to_keyval(ord(insert))
name = Gdk.keyval_name(keyval)
replace = { 'name': name,
'label': insert,
'xkeysym': keyval }
except:
replace = { 'name': insert,
'label': insert }
self.__dict[keyseq] = replace
def __str__(self):
return json.dumps(self.__dict)
if __name__ == "__main__":
mapfile = MapFile(sys.argv[1])
print mapfile

View File

@ -1,12 +1 @@
noinst_PROGRAMS = simple-client
simple_client_CFLAGS = \
-I$(top_srcdir) \
$(GIO2_CFLAGS)
simple_client_LDADD = \
$(top_builddir)/eekboard/libeekboard.la \
$(top_builddir)/eek/libeek.la \
$(GIO2_LIBS)
simple_client_SOURCES = main.c
EXTRA_DIST = simple-client

View File

@ -1,217 +0,0 @@
/*
* Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2010-2011 Red Hat, Inc.
*
* 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/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#include <stdlib.h>
#include <glib/gi18n.h>
#include "eekboard/eekboard.h"
static gboolean opt_system = FALSE;
static gboolean opt_session = FALSE;
static gchar *opt_address = NULL;
static gchar *opt_set_keyboard = NULL;
static gint opt_set_group = -1;
static gboolean opt_show_keyboard = FALSE;
static gboolean opt_hide_keyboard = FALSE;
static gint opt_press_key = -1;
static gint opt_release_key = -1;
static gboolean opt_listen = FALSE;
static const GOptionEntry options[] = {
{"system", 'y', 0, G_OPTION_ARG_NONE, &opt_system,
N_("Connect to the system bus")},
{"session", 'e', 0, G_OPTION_ARG_NONE, &opt_session,
N_("Connect to the session bus")},
{"address", 'a', 0, G_OPTION_ARG_STRING, &opt_address,
N_("Connect to the given D-Bus address")},
{"set-keyboard", '\0', 0, G_OPTION_ARG_STRING, &opt_set_keyboard,
N_("Upload keyboard description from an XML file")},
{"set-group", '\0', 0, G_OPTION_ARG_INT, &opt_set_group,
N_("Set group of the keyboard")},
{"show-keyboard", '\0', 0, G_OPTION_ARG_NONE, &opt_show_keyboard,
N_("Show keyboard")},
{"hide-keyboard", '\0', 0, G_OPTION_ARG_NONE, &opt_hide_keyboard,
N_("Hide keyboard")},
{"press-key", '\0', 0, G_OPTION_ARG_INT, &opt_press_key,
N_("Press key")},
{"release-key", '\0', 0, G_OPTION_ARG_INT, &opt_release_key,
N_("Release key")},
{"listen", '\0', 0, G_OPTION_ARG_NONE, &opt_listen,
N_("Listen events")},
{NULL}
};
static void
on_key_pressed (guint keycode, gpointer user_data)
{
g_print ("KeyPressed %u\n", keycode);
}
static void
on_key_released (guint keycode, gpointer user_data)
{
g_print ("KeyReleased %u\n", keycode);
}
int
main (int argc, char **argv)
{
EekboardEekboard *eekboard = NULL;
EekboardContext *context = NULL;
GBusType bus_type;
GDBusConnection *connection = NULL;
GError *error;
GOptionContext *option_context;
GMainLoop *loop = NULL;
gint retval = 0;
g_type_init ();
g_log_set_always_fatal (G_LOG_LEVEL_CRITICAL);
option_context = g_option_context_new ("eekboard-client");
g_option_context_add_main_entries (option_context, options, NULL);
g_option_context_parse (option_context, &argc, &argv, NULL);
g_option_context_free (option_context);
if (opt_system)
bus_type = G_BUS_TYPE_SYSTEM;
else if (opt_address)
bus_type = G_BUS_TYPE_NONE;
else
bus_type = G_BUS_TYPE_SESSION;
switch (bus_type) {
case G_BUS_TYPE_SYSTEM:
case G_BUS_TYPE_SESSION:
error = NULL;
connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
if (connection == NULL) {
g_printerr ("Can't connect to the bus: %s\n", error->message);
exit (1);
}
break;
case G_BUS_TYPE_NONE:
error = NULL;
connection = g_dbus_connection_new_for_address_sync (opt_address,
0,
NULL,
NULL,
&error);
if (connection == NULL) {
g_printerr ("Can't connect to the bus at %s: %s\n",
opt_address,
error->message);
exit (1);
}
break;
default:
g_assert_not_reached ();
break;
}
eekboard = eekboard_eekboard_new (connection, NULL);
if (eekboard == NULL) {
g_printerr ("Can't create eekboard proxy\n");
retval = 1;
goto out;
}
context = eekboard_eekboard_create_context (eekboard,
"eekboard-client",
NULL);
if (context == NULL) {
g_printerr ("Can't create context\n");
retval = 1;
goto out;
}
eekboard_eekboard_push_context (eekboard, context, NULL);
if (opt_set_keyboard) {
GFile *file;
GFileInputStream *input;
EekLayout *layout;
EekKeyboard *keyboard;
guint keyboard_id;
file = g_file_new_for_path (opt_set_keyboard);
error = NULL;
input = g_file_read (file, NULL, &error);
if (error) {
g_printerr ("Can't read file %s: %s\n",
opt_set_keyboard, error->message);
retval = 1;
goto out;
}
layout = eek_xml_layout_new (G_INPUT_STREAM(input));
g_object_unref (input);
keyboard = eek_keyboard_new (layout, 640, 480);
g_object_unref (layout);
keyboard_id = eekboard_context_add_keyboard (context, keyboard, NULL);
g_object_unref (keyboard);
eekboard_context_set_keyboard (context, keyboard_id, NULL);
}
if (opt_set_group >= 0) {
eekboard_context_set_group (context, opt_set_group, NULL);
}
if (opt_show_keyboard) {
eekboard_context_show_keyboard (context, NULL);
}
if (opt_hide_keyboard) {
eekboard_context_hide_keyboard (context, NULL);
}
if (opt_press_key >= 0) {
eekboard_context_press_key (context, opt_press_key, NULL);
}
if (opt_release_key >= 0) {
eekboard_context_release_key (context, opt_release_key, NULL);
}
if (opt_listen) {
g_signal_connect (context, "key-pressed",
G_CALLBACK(on_key_pressed), NULL);
g_signal_connect (context, "key-released",
G_CALLBACK(on_key_released), NULL);
loop = g_main_loop_new (NULL, FALSE);
g_main_loop_run (loop);
}
out:
if (context)
g_object_unref (context);
if (connection)
g_object_unref (connection);
if (loop)
g_main_loop_unref (loop);
return retval;
}

View File

@ -0,0 +1,47 @@
#!/usr/bin/python
# Copyright (C) 2011 Daiki Ueno <ueno@unixuser.org>
# Copyright (C) 2011 Red Hat, Inc.
# 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 eekboard
import glib
class SimpleClient(object):
def __init__(self):
client = eekboard.Client()
self.__context = client.create_context('simple-client')
client.push_context(self.__context)
keyboard_id = self.__context.add_keyboard('us')
self.__context.set_keyboard(keyboard_id)
def __key_pressed_cb(self, c, keyname, symbol, modifiers):
print (keyname, symbol, modifiers)
def __notify_visible_cb(self, c, p, mainloop):
if not c.props.visible:
mainloop.quit()
def run(self):
mainloop = glib.MainLoop()
self.__context.connect('key-pressed', self.__key_pressed_cb)
self.__context.connect('notify::visible', self.__notify_visible_cb,
mainloop)
self.__context.show_keyboard();
mainloop.run()
if __name__ == '__main__':
client = SimpleClient()
client.run()

View File

@ -1,7 +1,8 @@
src/server-server.c
src/server-context.c
eekboard/eekboard-context-service.c
eekboard/eekboard-service.c
src/server-service.c
src/server-context-service.c
src/server-main.c
src/client.c
src/client-main.c
src/xml-main.c
examples/simple-client/main.c
[type: gettext/glade]src/preferences-dialog.ui

View File

@ -3,5 +3,5 @@ eek/eek-container.c
eek/eek-key.c
eek/eek-keyboard.c
eek/eek-section.c
eekboard/eekboard-eekboard.c
eekboard/eekboard-client.c
eekboard/eekboard-context.c

View File

@ -18,10 +18,7 @@
bin_PROGRAMS = \
eekboard \
eekboard-server \
eekboard-xml
noinst_LTLIBRARIES = libxklutil.la
eekboard-server
eekboard_CFLAGS = \
-I$(top_srcdir) \
@ -29,10 +26,10 @@ eekboard_CFLAGS = \
$(GTK_CFLAGS) \
$(XKB_CFLAGS) \
$(LIBXKLAVIER_CFLAGS) \
-DKEYBOARDDIR=\"$(pkgdatadir)/keyboards\"
-DKEYBOARDDIR=\"$(pkgdatadir)/keyboards\" \
-DPKGDATADIR=\"$(pkgdatadir)\"
eekboard_LDADD = \
$(builddir)/libxklutil.la \
$(top_builddir)/eekboard/libeekboard.la \
$(top_builddir)/eek/libeek.la \
$(top_builddir)/eek/libeek-xkl.la \
@ -62,21 +59,25 @@ eekboard_LDADD += \
$(IBUS_LIBS)
endif
eekboard_headers = client.h
eekboard_SOURCES = client.c client-main.c
eekboard_headers = client.h preferences-dialog.h
eekboard_SOURCES = client.c preferences-dialog.c client-main.c
eekboard_server_CFLAGS = \
-I$(top_srcdir) \
$(GIO2_CFLAGS) \
$(GTK_CFLAGS) \
-DTHEMEDIR=\"$(pkgdatadir)/themes\"
$(LIBXKLAVIER_CFLAGS) \
-DTHEMEDIR=\"$(pkgdatadir)/themes\" \
-DKEYBOARDDIR=\"$(pkgdatadir)/keyboards\"
eekboard_server_LDADD = \
$(top_builddir)/eekboard/libeekboard.la \
$(top_builddir)/eek/libeek.la \
$(top_builddir)/eek/libeek-gtk.la \
$(top_builddir)/eek/libeek-xkl.la \
$(GIO2_LIBS) \
$(GTK_LIBS)
$(GTK_LIBS) \
$(LIBXKLAVIER_LIBS)
if ENABLE_CLUTTER_GTK
eekboard_server_CFLAGS += $(CLUTTER_GTK_CFLAGS)
@ -88,35 +89,8 @@ eekboard_server_CFLAGS += $(XDOCK_CFLAGS)
eekboard_server_LDADD += $(XDOCK_LIBS)
endif
eekboard_server_headers = server-server.h server-context.h
eekboard_server_SOURCES = server-server.c server-context.c server-main.c
eekboard_xml_CFLAGS = \
-I$(top_srcdir) \
$(GIO2_CFLAGS) \
$(GTK_CFLAGS) \
$(LIBXKLAVIER_CFLAGS)
eekboard_xml_LDADD = \
$(builddir)/libxklutil.la \
$(top_builddir)/eek/libeek.la \
$(top_builddir)/eek/libeek-xkl.la \
$(top_builddir)/eek/libeek-gtk.la \
$(GIO2_LIBS) \
$(GTK_LIBS) \
$(LIBXKLAVIER_LIBS)
if ENABLE_CLUTTER
eekboard_xml_CFLAGS += $(CLUTTER_CFLAGS) $(CLUTTER_GTK_CFLAGS)
eekboard_xml_LDADD += $(CLUTTER_LIBS) $(top_builddir)/eek/libeek-clutter.la $(CLUTTER_GTK_LIBS)
endif
eekboard_xml_SOURCES = xml-main.c
libxklutil_la_headers = xklutil.h
libxklutil_la_SOURCES = xklutil.c
libxklutil_la_CFLAGS = $(LIBXKLAVIER_CFLAGS)
libxklutil_la_LIBADD = $(LIBXKLAVIER_LIBS)
eekboard_server_headers = server-service.h server-context-service.h
eekboard_server_SOURCES = server-service.c server-context-service.c server-main.c
eekboarddir = $(includedir)/eekboard-$(EEK_API_VERSION)/eekboard
eekboard_HEADERS = \
@ -124,6 +98,6 @@ eekboard_HEADERS = \
noinst_HEADERS = \
$(eekboard_headers) \
$(eekboard_server_headers) \
$(eekboard_xml_headers) \
$(libxklutil_la_headers)
$(eekboard_server_headers)
dist_pkgdata_DATA = preferences-dialog.ui

View File

@ -29,25 +29,18 @@
#endif /* HAVE_IBUS */
#include <gtk/gtk.h>
#include <glib/gi18n.h>
#include "eekboard/eekboard.h"
#include "eekboard/eekboard-client.h"
#include "client.h"
#define DEFAULT_LAYOUT "us-qwerty"
#define DEFAULT_KEYBOARD "us"
static gboolean opt_system = FALSE;
static gboolean opt_session = FALSE;
static gchar *opt_address = NULL;
static gboolean opt_use_system_layout = FALSE;
static gboolean opt_focus = FALSE;
static gboolean opt_keystroke = FALSE;
static gchar *opt_keyboard = NULL;
static gchar *opt_model = NULL;
static gchar *opt_layouts = NULL;
static gchar *opt_options = NULL;
static gboolean opt_fullscreen = FALSE;
static const GOptionEntry options[] = {
@ -57,8 +50,6 @@ static const GOptionEntry options[] = {
N_("Connect to the session bus")},
{"address", 'a', 0, G_OPTION_ARG_STRING, &opt_address,
N_("Connect to the given D-Bus address")},
{"use-system-layout", 'x', 0, G_OPTION_ARG_NONE, &opt_use_system_layout,
N_("Use system keyboard layout")},
#if ENABLE_FOCUS_LISTENER
{"listen-focus", 'f', 0, G_OPTION_ARG_NONE, &opt_focus,
N_("Listen focus change events")},
@ -67,28 +58,20 @@ static const GOptionEntry options[] = {
{"listen-keystroke", 's', 0, G_OPTION_ARG_NONE, &opt_keystroke,
N_("Listen keystroke events with AT-SPI")},
#endif /* HAVE_ATSPI */
{"keyboard", 'k', 0, G_OPTION_ARG_STRING, &opt_keyboard,
N_("Specify keyboard")},
{"model", '\0', 0, G_OPTION_ARG_STRING, &opt_model,
N_("Specify model")},
{"layouts", '\0', 0, G_OPTION_ARG_STRING, &opt_layouts,
N_("Specify layouts")},
{"options", '\0', 0, G_OPTION_ARG_STRING, &opt_options,
N_("Specify options")},
{"fullscreen", 'F', 0, G_OPTION_ARG_NONE, &opt_fullscreen,
N_("Create window in fullscreen mode")},
{NULL}
};
static void
on_notify_keyboard_visible (GObject *object,
on_notify_visible (GObject *object,
GParamSpec *spec,
gpointer user_data)
{
GMainLoop *loop = user_data;
gboolean visible;
g_object_get (object, "keyboard-visible", &visible, NULL);
g_object_get (object, "visible", &visible, NULL);
/* user explicitly closed the window */
if (!visible && eekboard_context_is_enabled (EEKBOARD_CONTEXT(object)))
@ -105,7 +88,7 @@ on_context_destroyed (EekboardContext *context,
}
static void
on_destroyed (EekboardEekboard *eekboard,
on_destroyed (EekboardClient *eekboard,
gpointer user_data)
{
GMainLoop *loop = user_data;
@ -113,31 +96,53 @@ on_destroyed (EekboardEekboard *eekboard,
g_main_loop_quit (loop);
}
enum {
enum FocusListenerType {
FOCUS_NONE,
FOCUS_ATSPI,
FOCUS_IBUS
};
static gboolean
set_keyboard (Client *client,
const gchar *keyboard)
{
if (g_strcmp0 (keyboard, "system") == 0) {
if (!client_enable_xkl (client)) {
g_printerr ("Can't register xklavier event listeners\n");
return FALSE;
}
} else {
if (!client_set_keyboard (client, keyboard)) {
g_printerr ("Can't set keyboard \"%s\"\n", keyboard);
return FALSE;
}
}
return TRUE;
}
int
main (int argc, char **argv)
{
EekboardClient *client;
EekboardEekboard *eekboard;
Client *client = NULL;
EekboardClient *eekboard;
EekboardContext *context;
GBusType bus_type;
GDBusConnection *connection;
GError *error;
GOptionContext *option_context;
GMainLoop *loop;
GMainLoop *loop = NULL;
gint focus;
GSettings *settings;
GSettings *settings = NULL;
gchar *keyboard;
gint retval = 0;
if (!gtk_init_check (&argc, &argv)) {
g_printerr ("Can't init GTK\n");
exit (1);
}
eek_init ();
option_context = g_option_context_new ("eekboard-desktop-client");
g_option_context_add_main_entries (option_context, options, NULL);
g_option_context_parse (option_context, &argc, &argv, NULL);
@ -179,7 +184,7 @@ main (int argc, char **argv)
break;
}
client = eekboard_client_new (connection);
client = client_new (connection);
g_object_unref (connection);
if (client == NULL) {
@ -192,51 +197,65 @@ main (int argc, char **argv)
if (opt_focus) {
gchar *focus_listener = g_settings_get_string (settings,
"focus-listener");
g_object_unref (settings);
const struct {
const gchar *name;
enum FocusListenerType type;
} focus_listeners[] = {
#ifdef HAVE_ATSPI
{ "atspi", FOCUS_ATSPI },
#endif
#ifdef HAVE_IBUS
{ "ibus", FOCUS_IBUS },
#endif
{ NULL }
};
gint i;
if (g_strcmp0 (focus_listener, "atspi") == 0)
focus = FOCUS_ATSPI;
else if (g_strcmp0 (focus_listener, "ibus") == 0)
focus = FOCUS_IBUS;
else {
focus = FOCUS_NONE;
for (i = 0; focus_listeners[i].name; i++) {
if (g_strcmp0 (focus_listener, focus_listeners[i].name) == 0)
focus = focus_listeners[i].type;
}
if (focus == FOCUS_NONE) {
g_printerr ("Unknown focus listener \"%s\". "
"Try \"atspi\" or \"ibus\"\n", focus_listener);
g_object_unref (client);
exit (1);
retval = 1;
goto out;
}
}
#ifdef HAVE_ATSPI
if (focus == FOCUS_ATSPI || opt_keystroke) {
GSettings *settings = g_settings_new ("org.gnome.desktop.interface");
GSettings *desktop_settings =
g_settings_new ("org.gnome.desktop.interface");
gboolean accessibility_enabled =
g_settings_get_boolean (settings, "toolkit-accessibility");
g_object_unref (settings);
g_settings_get_boolean (desktop_settings, "toolkit-accessibility");
g_object_unref (desktop_settings);
if (accessibility_enabled) {
if (atspi_init () != 0) {
g_printerr ("Can't init AT-SPI 2\n");
g_object_unref (client);
exit (1);
retval = 1;
goto out;
}
if (focus == FOCUS_ATSPI &&
!eekboard_client_enable_atspi_focus (client)) {
!client_enable_atspi_focus (client)) {
g_printerr ("Can't register AT-SPI focus change event listeners\n");
g_object_unref (client);
exit (1);
retval = 1;
goto out;
}
if (opt_keystroke &&
!eekboard_client_enable_atspi_keystroke (client)) {
!client_enable_atspi_keystroke (client)) {
g_printerr ("Can't register AT-SPI keystroke event listeners\n");
g_object_unref (client);
exit (1);
retval = 1;
goto out;
}
} else {
g_printerr ("Desktop accessibility support is disabled\n");
g_object_unref (client);
exit (1);
retval = 1;
goto out;
}
}
#endif /* HAVE_ATSPI */
@ -245,58 +264,16 @@ main (int argc, char **argv)
if (focus == FOCUS_IBUS) {
ibus_init ();
if (focus == FOCUS_IBUS &&
!eekboard_client_enable_ibus_focus (client)) {
if (!client_enable_ibus_focus (client)) {
g_printerr ("Can't register IBus focus change event listeners\n");
g_object_unref (client);
exit (1);
retval = 1;
goto out;
}
}
#endif /* HAVE_IBUS */
if (opt_use_system_layout && (opt_keyboard || opt_model || opt_layouts || opt_options)) {
g_printerr ("Can't use --use-system-layout option with keyboard options\n");
g_object_unref (client);
exit (1);
}
if (!eekboard_client_enable_xkl (client)) {
g_printerr ("Can't register xklavier event listeners\n");
g_object_unref (client);
exit (1);
}
if (opt_use_system_layout || opt_model || opt_layouts || opt_options) {
if (!eekboard_client_load_keyboard_from_xkl (client,
opt_model,
opt_layouts,
opt_options)) {
g_printerr ("Can't load keyboard from xklavier config\n");
g_object_unref (client);
exit (1);
}
} else {
gchar *file;
gboolean success;
if (!opt_keyboard)
opt_keyboard = DEFAULT_LAYOUT;
if (g_str_has_suffix (opt_keyboard, ".xml"))
file = g_strdup (opt_keyboard);
else
file = g_strdup_printf ("%s/%s.xml", KEYBOARDDIR, opt_keyboard);
success = eekboard_client_load_keyboard_from_file (client, file);
g_free (file);
if (!success) {
g_printerr ("Can't load keyboard file %s\n", file);
g_object_unref (client);
exit (1);
}
}
#ifdef HAVE_XTEST
if (!eekboard_client_enable_xtest (client)) {
if (!client_enable_xtest (client)) {
g_printerr ("Can't init xtest\n");
g_object_unref (client);
exit (1);
@ -304,10 +281,11 @@ main (int argc, char **argv)
#endif /* HAVE_XTEST */
loop = g_main_loop_new (NULL, FALSE);
if (!opt_focus) {
g_object_get (client, "context", &context, NULL);
g_signal_connect (context, "notify::keyboard-visible",
G_CALLBACK(on_notify_keyboard_visible), loop);
g_signal_connect (context, "notify::visible",
G_CALLBACK(on_notify_visible), loop);
g_signal_connect (context, "destroyed",
G_CALLBACK(on_context_destroyed), loop);
g_object_unref (context);
@ -323,10 +301,25 @@ main (int argc, char **argv)
g_object_get (client, "eekboard", &eekboard, NULL);
g_signal_connect (eekboard, "destroyed",
G_CALLBACK(on_destroyed), loop);
g_object_unref (eekboard);
keyboard = g_settings_get_string (settings, "keyboard");
if (!set_keyboard (client, keyboard)) {
g_free (keyboard);
retval = 1;
goto out;
}
g_free (keyboard);
g_main_loop_run (loop);
g_main_loop_unref (loop);
g_object_unref (client);
return 0;
out:
if (loop)
g_main_loop_unref (loop);
if (client)
g_object_unref (client);
if (settings)
g_object_unref (settings);
return retval;
}

View File

@ -39,9 +39,10 @@
#include "eek/eek.h"
#include "eek/eek-xkl.h"
#include "eekboard/eekboard.h"
#include "eekboard/eekboard-client.h"
#include "eekboard/eekboard-xklutil.h"
#include "client.h"
#include "xklutil.h"
#include "preferences-dialog.h"
#include <string.h>
@ -56,19 +57,17 @@ enum {
PROP_LAST
};
typedef struct _EekboardClientClass EekboardClientClass;
typedef struct _ClientClass ClientClass;
struct _EekboardClient {
struct _Client {
GObject parent;
EekboardEekboard *eekboard;
EekboardClient *eekboard;
EekboardContext *context;
EekKeyboard *keyboard;
GSList *keyboards;
XklEngine *xkl_engine;
XklConfigRegistry *xkl_config_registry;
gboolean use_xkl_layout;
gint group;
gulong xkl_config_changed_handler;
gulong xkl_state_changed_handler;
@ -77,6 +76,7 @@ struct _EekboardClient {
gulong key_released_handler;
gboolean follows_focus;
guint hide_keyboard_timeout_id;
#ifdef HAVE_ATSPI
AtspiAccessible *acc;
@ -96,11 +96,17 @@ struct _EekboardClient {
GSettings *settings;
};
struct _EekboardClientClass {
struct _ClientClass {
GObjectClass parent_class;
};
G_DEFINE_TYPE (EekboardClient, eekboard_client, G_TYPE_OBJECT);
G_DEFINE_TYPE (Client, client, G_TYPE_OBJECT);
#if ENABLE_FOCUS_LISTENER
#define IS_KEYBOARD_VISIBLE(client) (!client->follows_focus)
#else /* ENABLE_FOCUS_LISTENER */
#define IS_KEYBOARD_VISIBLE(client) TRUE
#endif /* !ENABLE_FOCUS_LISTENER */
static GdkFilterReturn filter_xkl_event (GdkXEvent *xev,
GdkEvent *event,
@ -121,43 +127,38 @@ static void focus_listener_cb (const AtspiEvent *event,
static gboolean keystroke_listener_cb (const AtspiDeviceEvent *stroke,
void *user_data);
#endif /* HAVE_ATSPI */
static gboolean set_keyboard (EekboardClient *client,
gboolean show,
EekLayout *layout);
static gboolean set_keyboard_from_xkl (EekboardClient *client,
gboolean show,
const gchar *model,
const gchar *layouts,
const gchar *options);
static gboolean set_keyboard (Client *client,
const gchar *keyboard);
static gboolean set_keyboard_from_xkl (Client *client);
#ifdef HAVE_XTEST
static void update_modifier_keycodes
(EekboardClient *client);
(Client *client);
#endif /* HAVE_XTEST */
static void
eekboard_client_set_property (GObject *object,
client_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
EekboardClient *client = EEKBOARD_CLIENT(object);
Client *client = CLIENT(object);
GDBusConnection *connection;
switch (prop_id) {
case PROP_CONNECTION:
connection = g_value_get_object (value);
client->eekboard = eekboard_eekboard_new (connection, NULL);
client->eekboard = eekboard_client_new (connection, NULL);
if (client->eekboard != NULL) {
client->context =
eekboard_eekboard_create_context (client->eekboard,
eekboard_client_create_context (client->eekboard,
"eekboard",
NULL);
if (client->context == NULL) {
g_object_unref (client->eekboard);
client->eekboard = NULL;
} else
eekboard_eekboard_push_context (client->eekboard,
eekboard_client_push_context (client->eekboard,
client->context,
NULL);
}
@ -171,12 +172,12 @@ eekboard_client_set_property (GObject *object,
}
static void
eekboard_client_get_property (GObject *object,
client_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
EekboardClient *client = EEKBOARD_CLIENT(object);
Client *client = CLIENT(object);
switch (prop_id) {
case PROP_EEKBOARD:
@ -194,19 +195,19 @@ eekboard_client_get_property (GObject *object,
}
static void
eekboard_client_dispose (GObject *object)
client_dispose (GObject *object)
{
EekboardClient *client = EEKBOARD_CLIENT(object);
Client *client = CLIENT(object);
eekboard_client_disable_xkl (client);
client_disable_xkl (client);
#ifdef HAVE_ATSPI
eekboard_client_disable_atspi_focus (client);
eekboard_client_disable_atspi_keystroke (client);
client_disable_atspi_focus (client);
client_disable_atspi_keystroke (client);
#endif /* HAVE_ATSPI */
#ifdef HAVE_IBUS
eekboard_client_disable_ibus_focus (client);
client_disable_ibus_focus (client);
if (client->ibus_bus) {
g_object_unref (client->ibus_bus);
client->ibus_bus = NULL;
@ -214,12 +215,12 @@ eekboard_client_dispose (GObject *object)
#endif /* HAVE_IBUS */
#ifdef HAVE_XTEST
eekboard_client_disable_xtest (client);
client_disable_xtest (client);
#endif /* HAVE_XTEST */
if (client->context) {
if (client->eekboard) {
eekboard_eekboard_pop_context (client->eekboard, NULL);
eekboard_client_pop_context (client->eekboard, NULL);
}
g_object_unref (client->context);
@ -231,28 +232,39 @@ eekboard_client_dispose (GObject *object)
client->eekboard = NULL;
}
if (client->keyboard) {
g_object_unref (client->keyboard);
client->keyboard = NULL;
}
if (client->settings) {
g_object_unref (client->settings);
client->settings = NULL;
}
G_OBJECT_CLASS (eekboard_client_parent_class)->dispose (object);
G_OBJECT_CLASS (client_parent_class)->dispose (object);
}
static void
eekboard_client_class_init (EekboardClientClass *klass)
client_finalize (GObject *object)
{
Client *client = CLIENT(object);
if (client->keyboards) {
GSList *next = client->keyboards->next;
/* client->keyboards is a ring; break it before free */
client->keyboards->next = NULL;
g_slist_free (next);
}
G_OBJECT_CLASS (client_parent_class)->finalize (object);
}
static void
client_class_init (ClientClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GParamSpec *pspec;
gobject_class->set_property = eekboard_client_set_property;
gobject_class->get_property = eekboard_client_get_property;
gobject_class->dispose = eekboard_client_dispose;
gobject_class->set_property = client_set_property;
gobject_class->get_property = client_get_property;
gobject_class->dispose = client_dispose;
gobject_class->finalize = client_finalize;
pspec = g_param_spec_object ("connection",
"Connection",
@ -266,7 +278,7 @@ eekboard_client_class_init (EekboardClientClass *klass)
pspec = g_param_spec_object ("eekboard",
"Eekboard",
"Eekboard",
EEKBOARD_TYPE_EEKBOARD,
EEKBOARD_TYPE_CLIENT,
G_PARAM_READABLE);
g_object_class_install_property (gobject_class,
PROP_EEKBOARD,
@ -283,57 +295,28 @@ eekboard_client_class_init (EekboardClientClass *klass)
}
static void
eekboard_client_init (EekboardClient *client)
client_init (Client *client)
{
client->eekboard = NULL;
client->context = NULL;
client->xkl_engine = NULL;
client->xkl_config_registry = NULL;
client->keyboard = NULL;
client->key_pressed_handler = 0;
client->key_released_handler = 0;
client->xkl_config_changed_handler = 0;
client->xkl_state_changed_handler = 0;
#if ENABLE_FOCUS_LISTENER
client->follows_focus = FALSE;
#endif /* ENABLE_FOCUS_LISTENER */
#ifdef HAVE_ATSPI
client->keystroke_listener = NULL;
#endif /* HAVE_ATSPI */
#ifdef HAVE_IBUS
client->ibus_bus = NULL;
client->ibus_focus_message_filter = 0;
#endif /* HAVE_IBUS */
client->settings = g_settings_new ("org.fedorahosted.eekboard");
}
gboolean
eekboard_client_load_keyboard_from_xkl (EekboardClient *client,
const gchar *model,
const gchar *layouts,
const gchar *options)
client_set_keyboard (Client *client,
const gchar *keyboard)
{
client->use_xkl_layout = TRUE;
#if ENABLE_FOCUS_LISTENER
return set_keyboard_from_xkl (client,
!client->follows_focus,
model,
layouts,
options);
#else /* ENABLE_FOCUS_LISTENER */
return set_keyboard_from_xkl (client,
TRUE,
model,
layouts,
options);
#endif /* !ENABLE_FOCUS_LISTENER */
gboolean retval;
retval = set_keyboard (client, keyboard);
if (retval && IS_KEYBOARD_VISIBLE (client))
eekboard_context_show_keyboard (client->context, NULL);
return retval;
}
gboolean
eekboard_client_enable_xkl (EekboardClient *client)
client_enable_xkl (Client *client)
{
GdkDisplay *display = gdk_display_get_default ();
gboolean retval;
g_assert (display);
if (!client->xkl_engine) {
@ -362,20 +345,21 @@ eekboard_client_enable_xkl (EekboardClient *client)
(GdkFilterFunc) filter_xkl_event,
client);
client->use_xkl_layout = FALSE;
xkl_engine_start_listen (client->xkl_engine, XKLL_TRACK_KEYBOARD_STATE);
return TRUE;
retval = set_keyboard_from_xkl (client);
if (IS_KEYBOARD_VISIBLE (client))
eekboard_context_show_keyboard (client->context, NULL);
return retval;
}
void
eekboard_client_disable_xkl (EekboardClient *client)
client_disable_xkl (Client *client)
{
client->use_xkl_layout = FALSE;
if (client->xkl_engine)
if (client->xkl_engine) {
xkl_engine_stop_listen (client->xkl_engine, XKLL_TRACK_KEYBOARD_STATE);
if (g_signal_handler_is_connected (client->xkl_engine,
client->xkl_config_changed_handler))
g_signal_handler_disconnect (client->xkl_engine,
@ -384,11 +368,13 @@ eekboard_client_disable_xkl (EekboardClient *client)
client->xkl_state_changed_handler))
g_signal_handler_disconnect (client->xkl_engine,
client->xkl_state_changed_handler);
client->xkl_engine = NULL;
}
}
#ifdef HAVE_ATSPI
gboolean
eekboard_client_enable_atspi_focus (EekboardClient *client)
client_enable_atspi_focus (Client *client)
{
GError *error;
@ -415,7 +401,7 @@ eekboard_client_enable_atspi_focus (EekboardClient *client)
}
void
eekboard_client_disable_atspi_focus (EekboardClient *client)
client_disable_atspi_focus (Client *client)
{
GError *error;
@ -437,7 +423,7 @@ eekboard_client_disable_atspi_focus (EekboardClient *client)
}
gboolean
eekboard_client_enable_atspi_keystroke (EekboardClient *client)
client_enable_atspi_keystroke (Client *client)
{
GError *error;
@ -469,7 +455,7 @@ eekboard_client_enable_atspi_keystroke (EekboardClient *client)
}
void
eekboard_client_disable_atspi_keystroke (EekboardClient *client)
client_disable_atspi_keystroke (Client *client)
{
if (client->keystroke_listener) {
GError *error;
@ -497,7 +483,7 @@ static void
focus_listener_cb (const AtspiEvent *event,
void *user_data)
{
EekboardClient *client = user_data;
Client *client = user_data;
AtspiAccessible *accessible = event->source;
AtspiStateSet *state_set = atspi_accessible_get_state_set (accessible);
AtspiRole role;
@ -547,25 +533,18 @@ static gboolean
keystroke_listener_cb (const AtspiDeviceEvent *stroke,
void *user_data)
{
EekboardClient *client = user_data;
EekKey *key;
Client *client = user_data;
/* Ignore modifiers since the keystroke listener does not called
when a modifier key is released. */
key = eek_keyboard_find_key_by_keycode (client->keyboard,
stroke->hw_code);
if (key) {
EekSymbol *symbol = eek_key_get_symbol_with_fallback (key, 0, 0);
if (symbol && eek_symbol_is_modifier (symbol))
return FALSE;
switch (stroke->type) {
case ATSPI_KEY_PRESSED:
eekboard_context_press_keycode (client->context, stroke->hw_code, NULL);
break;
case ATSPI_KEY_RELEASED:
eekboard_context_release_keycode (client->context, stroke->hw_code, NULL);
break;
default:
g_return_val_if_reached (FALSE);
}
if (stroke->type == ATSPI_KEY_PRESSED) {
eekboard_context_press_key (client->context, stroke->hw_code, NULL);
} else {
eekboard_context_release_key (client->context, stroke->hw_code, NULL);
}
return TRUE;
}
#endif /* HAVE_ATSPI */
@ -592,24 +571,41 @@ add_match_rule (GDBusConnection *connection,
g_object_unref (message);
}
static gboolean
on_hide_keyboard_timeout (Client *client)
{
eekboard_context_hide_keyboard (client->context, NULL);
client->hide_keyboard_timeout_id = 0;
return FALSE;
}
static GDBusMessage *
focus_message_filter (GDBusConnection *connection,
GDBusMessage *message,
gboolean incoming,
gpointer user_data)
{
EekboardClient *client = user_data;
Client *client = user_data;
if (incoming &&
g_strcmp0 (g_dbus_message_get_interface (message),
IBUS_INTERFACE_INPUT_CONTEXT) == 0) {
IBUS_INTERFACE_PANEL) == 0) {
const gchar *member = g_dbus_message_get_member (message);
if (g_strcmp0 (member, "FocusIn") == 0) {
if (client->hide_keyboard_timeout_id > 0) {
g_source_remove (client->hide_keyboard_timeout_id);
client->hide_keyboard_timeout_id = 0;
}
eekboard_context_show_keyboard (client->context, NULL);
} else if (g_settings_get_boolean (client->settings, "auto-hide") &&
g_strcmp0 (member, "FocusOut") == 0) {
eekboard_context_hide_keyboard (client->context, NULL);
guint delay;
g_settings_get (client->settings, "auto-hide-delay", "u", &delay);
client->hide_keyboard_timeout_id =
g_timeout_add (delay,
(GSourceFunc)on_hide_keyboard_timeout,
client);
}
}
@ -619,18 +615,17 @@ focus_message_filter (GDBusConnection *connection,
static void
_ibus_connect_focus_handlers (IBusBus *bus, gpointer user_data)
{
EekboardClient *client = user_data;
Client *client = user_data;
GDBusConnection *connection;
GError *error;
connection = ibus_bus_get_connection (bus);
add_match_rule (connection,
"type='method_call',"
"interface='" IBUS_INTERFACE_INPUT_CONTEXT "',"
"interface='" IBUS_INTERFACE_PANEL "',"
"member='FocusIn'");
add_match_rule (connection,
"type='method_call',"
"interface='" IBUS_INTERFACE_INPUT_CONTEXT "',"
"interface='" IBUS_INTERFACE_PANEL "',"
"member='FocusOut'");
client->ibus_focus_message_filter =
g_dbus_connection_add_filter (connection,
@ -640,7 +635,7 @@ _ibus_connect_focus_handlers (IBusBus *bus, gpointer user_data)
}
gboolean
eekboard_client_enable_ibus_focus (EekboardClient *client)
client_enable_ibus_focus (Client *client)
{
if (!client->ibus_bus) {
client->ibus_bus = ibus_bus_new ();
@ -658,7 +653,7 @@ eekboard_client_enable_ibus_focus (EekboardClient *client)
}
void
eekboard_client_disable_ibus_focus (EekboardClient *client)
client_disable_ibus_focus (Client *client)
{
GDBusConnection *connection;
@ -676,10 +671,10 @@ eekboard_client_disable_ibus_focus (EekboardClient *client)
}
#endif /* HAVE_ATSPI */
EekboardClient *
eekboard_client_new (GDBusConnection *connection)
Client *
client_new (GDBusConnection *connection)
{
EekboardClient *client = g_object_new (EEKBOARD_TYPE_CLIENT,
Client *client = g_object_new (TYPE_CLIENT,
"connection", connection,
NULL);
if (client->context)
@ -692,7 +687,7 @@ filter_xkl_event (GdkXEvent *xev,
GdkEvent *event,
gpointer user_data)
{
EekboardClient *client = user_data;
Client *client = user_data;
XEvent *xevent = (XEvent *)xev;
xkl_engine_filter_events (client->xkl_engine, xevent);
@ -703,13 +698,11 @@ static void
on_xkl_config_changed (XklEngine *xklengine,
gpointer user_data)
{
EekboardClient *client = user_data;
Client *client = user_data;
gboolean retval;
if (client->use_xkl_layout) {
retval = set_keyboard_from_xkl (client, FALSE, NULL, NULL, NULL);
retval = set_keyboard_from_xkl (client);
g_return_if_fail (retval);
}
#ifdef HAVE_XTEST
update_modifier_keycodes (client);
@ -717,87 +710,68 @@ on_xkl_config_changed (XklEngine *xklengine,
}
static gboolean
set_keyboard (EekboardClient *client,
gboolean show,
EekLayout *layout)
set_keyboard (Client *client,
const gchar *keyboard)
{
gchar *keyboard_name;
static gint keyboard_serial = 0;
GSList *keyboards = NULL;
gchar **strv, **p;
g_return_val_if_fail (keyboard != NULL, FALSE);
g_return_val_if_fail (*keyboard != '\0', FALSE);
if (client->keyboards)
g_slist_free (client->keyboards);
strv = g_strsplit (keyboard, ",", -1);
for (p = strv; *p != NULL; p++) {
guint keyboard_id;
client->keyboard = eek_keyboard_new (layout, CSW, CSH);
eek_keyboard_set_modifier_behavior (client->keyboard,
EEK_MODIFIER_BEHAVIOR_LATCH);
keyboard_name = g_strdup_printf ("keyboard%d", keyboard_serial++);
eek_element_set_name (EEK_ELEMENT(client->keyboard), keyboard_name);
g_free (keyboard_name);
keyboard_id = eekboard_context_add_keyboard (client->context,
client->keyboard,
*p,
NULL);
if (keyboard_id == 0)
return FALSE;
keyboards = g_slist_prepend (keyboards,
GUINT_TO_POINTER(keyboard_id));
}
g_strfreev (strv);
/* make a cycle */
keyboards = g_slist_reverse (keyboards);
g_slist_last (keyboards)->next = keyboards;
client->keyboards = keyboards;
/* select the first keyboard */
eekboard_context_set_keyboard (client->context,
GPOINTER_TO_UINT(keyboards->data),
NULL);
eekboard_context_set_keyboard (client->context, keyboard_id, NULL);
if (show)
eekboard_context_show_keyboard (client->context, NULL);
return TRUE;
}
static gboolean
set_keyboard_from_xkl (EekboardClient *client,
gboolean show,
const gchar *model,
const gchar *layouts,
const gchar *options)
set_keyboard_from_xkl (Client *client)
{
EekLayout *layout;
gboolean retval;
if (client->keyboard)
g_object_unref (client->keyboard);
layout = eek_xkl_layout_new ();
if (model) {
if (!eek_xkl_layout_set_model (EEK_XKL_LAYOUT(layout), model)) {
g_object_unref (layout);
return FALSE;
}
}
if (layouts) {
XklConfigRec *rec;
gchar *layout, *keyboard;
guint keyboard_id;
rec = eekboard_xkl_config_rec_new_from_string (layouts);
if (!eek_xkl_layout_set_layouts (EEK_XKL_LAYOUT(layout),
rec->layouts)) {
rec = xkl_config_rec_new ();
xkl_config_rec_get_from_server (rec, client->xkl_engine);
layout = eekboard_xkl_config_rec_to_string (rec);
g_object_unref (rec);
g_object_unref (layout);
keyboard = g_strdup_printf ("xkb:%s", layout);
g_free (layout);
keyboard_id = eekboard_context_add_keyboard (client->context,
keyboard,
NULL);
g_free (keyboard);
if (keyboard_id == 0)
return FALSE;
}
eekboard_context_set_keyboard (client->context, keyboard_id, NULL);
if (!eek_xkl_layout_set_variants (EEK_XKL_LAYOUT(layout),
rec->variants)) {
g_object_unref (rec);
g_object_unref (layout);
return FALSE;
}
g_object_unref (rec);
}
if (options) {
gchar **_options;
_options = g_strsplit (options, ",", -1);
if (!eek_xkl_layout_set_options (EEK_XKL_LAYOUT(layout), _options)) {
g_strfreev (_options);
g_object_unref (layout);
return FALSE;
}
}
retval = set_keyboard (client, show, layout);
g_object_unref (layout);
return retval;
return TRUE;
}
static void
@ -807,17 +781,10 @@ on_xkl_state_changed (XklEngine *xklengine,
gboolean restore,
gpointer user_data)
{
EekboardClient *client = user_data;
Client *client = user_data;
if (type == GROUP_CHANGED && client->keyboard) {
if (client->use_xkl_layout) {
gint group = eek_element_get_group (EEK_ELEMENT(client->keyboard));
if (group != value) {
if (type == GROUP_CHANGED)
eekboard_context_set_group (client->context, value, NULL);
}
}
client->group = value;
}
}
#ifdef HAVE_XTEST
@ -829,7 +796,7 @@ on_xkl_state_changed (XklEngine *xklengine,
- get_keycode_from_gdk_keymap (Caribou: best_keycode_keyval_match)
*/
static guint
get_replaced_keycode (EekboardClient *client)
get_replaced_keycode (Client *client)
{
GdkDisplay *display = gdk_display_get_default ();
Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
@ -851,7 +818,7 @@ get_replaced_keycode (EekboardClient *client)
non-zero keycode), it simply changes the current map with the
specified KEYCODE and KEYSYM. */
static gboolean
replace_keycode (EekboardClient *client,
replace_keycode (Client *client,
guint *keycode,
guint *keysym)
{
@ -868,7 +835,7 @@ replace_keycode (EekboardClient *client,
if (replaced_keycode == 0)
return FALSE;
replaced_keysym = XKeycodeToKeysym (xdisplay, replaced_keycode, 0);
XFlush (xdisplay);
XSync (xdisplay, False);
offset = client->xkb->map->key_sym_map[replaced_keycode].offset;
client->xkb->map->syms[offset] = *keysym;
@ -878,7 +845,7 @@ replace_keycode (EekboardClient *client,
changes.num_key_syms = 1;
XkbChangeMap (xdisplay, client->xkb, &changes);
XFlush (xdisplay);
XSync (xdisplay, False);
*keycode = replaced_keycode;
*keysym = replaced_keysym;
@ -887,32 +854,36 @@ replace_keycode (EekboardClient *client,
}
static gboolean
get_keycode_from_gdk_keymap (EekboardClient *client,
get_keycode_from_gdk_keymap (Client *client,
guint keysym,
guint *keycode,
guint *modifiers)
{
GdkKeymap *keymap = gdk_keymap_get_default ();
GdkKeymapKey *keys, *best_match;
GdkKeymapKey *keys, *best_match = NULL;
gint n_keys, i;
if (!gdk_keymap_get_entries_for_keyval (keymap, keysym, &keys, &n_keys))
return FALSE;
for (i = 0; i < n_keys; i++)
if (keys[i].group == client->group)
if (keys[i].group == eekboard_context_get_group (client->context, NULL))
best_match = &keys[i];
if (!best_match) {
g_free (keys);
return FALSE;
}
*keycode = best_match->keycode;
*modifiers = best_match->level == 1 ? EEK_SHIFT_MASK : 0;
g_free (keys);
return TRUE;
}
static void
send_fake_modifier_key_event (EekboardClient *client,
send_fake_modifier_key_event (Client *client,
EekModifierType modifiers,
gboolean is_pressed)
{
@ -934,18 +905,16 @@ send_fake_modifier_key_event (EekboardClient *client,
}
static void
send_fake_key_event (EekboardClient *client,
EekKey *key,
send_fake_key_event (Client *client,
EekSymbol *symbol,
guint keyboard_modifiers,
gboolean is_pressed)
{
GdkDisplay *display = gdk_display_get_default ();
EekSymbol *symbol;
EekModifierType keyboard_modifiers, modifiers;
EekModifierType modifiers;
guint xkeysym;
guint keycode, replaced_keysym = 0;
symbol = eek_key_get_symbol_with_fallback (key, 0, 0);
/* Ignore special keys and modifiers */
if (!EEK_IS_KEYSYM(symbol) || eek_symbol_is_modifier (symbol))
return;
@ -964,10 +933,12 @@ send_fake_key_event (EekboardClient *client,
}
/* Clear level shift modifiers */
keyboard_modifiers = eek_keyboard_get_modifiers (client->keyboard);
keyboard_modifiers &= ~EEK_SHIFT_MASK;
keyboard_modifiers &= ~EEK_LOCK_MASK;
keyboard_modifiers &= ~eek_keyboard_get_alt_gr_mask (client->keyboard);
/* FIXME: may need to remap ISO_Level3_Shift and NumLock */
//keyboard_modifiers &= ~EEK_MOD5_MASK;
//keyboard_modifiers &= ~client->alt_gr_mask;
//keyboard_modifiers &= ~client->num_lock_mask;
modifiers |= keyboard_modifiers;
@ -989,24 +960,35 @@ send_fake_key_event (EekboardClient *client,
}
static void
on_key_pressed (EekKeyboard *keyboard,
EekKey *key,
on_key_pressed (EekboardContext *context,
const gchar *keyname,
EekSymbol *symbol,
guint modifiers,
gpointer user_data)
{
EekboardClient *client = user_data;
send_fake_key_event (client, key, TRUE);
send_fake_key_event (client, key, FALSE);
Client *client = user_data;
if (g_strcmp0 (eek_symbol_get_name (symbol), "cycle-keyboard") == 0) {
client->keyboards = g_slist_next (client->keyboards);
eekboard_context_set_keyboard (client->context,
GPOINTER_TO_UINT(client->keyboards->data),
NULL);
return;
}
if (g_strcmp0 (eek_symbol_get_name (symbol), "preferences") == 0) {
PreferencesDialog *dialog = preferences_dialog_new ();
preferences_dialog_run (dialog);
return;
}
send_fake_key_event (client, symbol, modifiers, TRUE);
send_fake_key_event (client, symbol, modifiers, FALSE);
}
static void
on_key_released (EekKeyboard *keyboard,
EekKey *key,
gpointer user_data)
{
}
static void
update_modifier_keycodes (EekboardClient *client)
update_modifier_keycodes (Client *client)
{
GdkDisplay *display = gdk_display_get_default ();
XModifierKeymap *mods;
@ -1023,10 +1005,11 @@ update_modifier_keycodes (EekboardClient *client)
}
}
}
XFreeModifiermap (mods);
}
gboolean
eekboard_client_enable_xtest (EekboardClient *client)
client_enable_xtest (Client *client)
{
GdkDisplay *display = gdk_display_get_default ();
int opcode, event_base, error_base, major_version, minor_version;
@ -1056,59 +1039,18 @@ eekboard_client_enable_xtest (EekboardClient *client)
update_modifier_keycodes (client);
client->key_pressed_handler =
g_signal_connect (client->keyboard, "key-pressed",
g_signal_connect (client->context, "key-pressed",
G_CALLBACK(on_key_pressed), client);
client->key_released_handler =
g_signal_connect (client->keyboard, "key-released",
G_CALLBACK(on_key_released), client);
return TRUE;
}
void
eekboard_client_disable_xtest (EekboardClient *client)
client_disable_xtest (Client *client)
{
if (client->xkb) {
XkbFreeKeyboard (client->xkb, 0, TRUE); /* free_all = TRUE */
client->xkb = NULL;
}
if (g_signal_handler_is_connected (client->keyboard,
client->key_pressed_handler))
g_signal_handler_disconnect (client->keyboard,
client->key_pressed_handler);
if (g_signal_handler_is_connected (client->keyboard,
client->key_released_handler))
g_signal_handler_disconnect (client->keyboard,
client->key_released_handler);
}
gboolean
eekboard_client_load_keyboard_from_file (EekboardClient *client,
const gchar *keyboard_file)
{
GFile *file;
GFileInputStream *input;
GError *error;
EekLayout *layout;
gboolean retval;
file = g_file_new_for_path (keyboard_file);
error = NULL;
input = g_file_read (file, NULL, &error);
if (input == NULL)
return FALSE;
layout = eek_xml_layout_new (G_INPUT_STREAM(input));
g_object_unref (input);
#if ENABLE_FOCUS_LISTENER
retval = set_keyboard (client, !client->follows_focus, layout);
#else /* ENABLE_FOCUS_LISTENER */
retval = set_keyboard (client, TRUE, layout);
#endif /* !ENABLE_FOCUS_LISTENER */
g_object_unref (layout);
return retval;
}
#endif /* HAVE_XTEST */

View File

@ -15,54 +15,41 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef EEKBOARD_CLIENT_H
#define EEKBOARD_CLIENT_H 1
#ifndef CLIENT_H
#define CLIENT_H 1
#include <gio/gio.h>
G_BEGIN_DECLS
#define EEKBOARD_TYPE_CLIENT (eekboard_client_get_type())
#define EEKBOARD_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEKBOARD_TYPE_CLIENT, EekboardClient))
#define EEKBOARD_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEKBOARD_TYPE_CLIENT, EekboardClientClass))
#define EEKBOARD_IS_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEKBOARD_TYPE_CLIENT))
#define EEKBOARD_IS_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEKBOARD_TYPE_CLIENT))
#define EEKBOARD_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEKBOARD_TYPE_CLIENT, EekboardClientClass))
#define TYPE_CLIENT (client_get_type())
#define CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_CLIENT, Client))
#define CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_CLIENT, ClientClass))
#define IS_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_CLIENT))
#define IS_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_CLIENT))
#define CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_CLIENT, ClientClass))
typedef struct _EekboardClient EekboardClient;
typedef struct _Client Client;
EekboardClient * eekboard_client_new (GDBusConnection *connection);
Client *client_new (GDBusConnection *connection);
gboolean eekboard_client_load_keyboard_from_file
(EekboardClient *client,
const gchar *file);
gboolean client_set_keyboard (Client *client,
const gchar *keyboard);
gboolean eekboard_client_load_keyboard_from_xkl
(EekboardClient *client,
const gchar *model,
const gchar *layouts,
const gchar *options);
gboolean client_enable_xkl (Client *client);
void client_disable_xkl (Client *client);
gboolean eekboard_client_enable_xkl (EekboardClient *client);
void eekboard_client_disable_xkl (EekboardClient *client);
gboolean client_enable_atspi_focus (Client *client);
void client_disable_atspi_focus (Client *client);
gboolean eekboard_client_enable_atspi_focus
(EekboardClient *client);
void eekboard_client_disable_atspi_focus
(EekboardClient *client);
gboolean client_enable_atspi_keystroke (Client *client);
void client_disable_atspi_keystroke (Client *client);
gboolean eekboard_client_enable_atspi_keystroke
(EekboardClient *client);
void eekboard_client_disable_atspi_keystroke
(EekboardClient *client);
gboolean client_enable_xtest (Client *client);
void client_disable_xtest (Client *client);
gboolean eekboard_client_enable_xtest (EekboardClient *client);
void eekboard_client_disable_xtest (EekboardClient *client);
gboolean eekboard_client_enable_ibus_focus
(EekboardClient *client);
void eekboard_client_disable_ibus_focus
(EekboardClient *client);
gboolean client_enable_ibus_focus (Client *client);
void client_disable_ibus_focus (Client *client);
G_END_DECLS
#endif /* EEKBOARD_CLIENT_H */
#endif /* CLIENT_H */

154
src/preferences-dialog.c Normal file
View File

@ -0,0 +1,154 @@
/*
* Copyright (C) 2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2011 Red Hat, Inc.
*
* 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/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#include <gtk/gtk.h>
#include "preferences-dialog.h"
struct _PreferencesDialog {
GtkWidget *dialog;
GtkWidget *repeat_toggle;
GtkWidget *repeat_delay_scale;
GtkWidget *repeat_speed_scale;
GtkWidget *auto_hide_toggle;
GtkWidget *auto_hide_delay_scale;
GtkWidget *start_fullscreen_toggle;
GtkWidget *keyboard_entry;
GSettings *settings;
};
static gboolean
get_rate (GValue *value,
GVariant *variant,
gpointer user_data)
{
int rate;
gdouble fraction;
rate = g_variant_get_uint32 (variant);
fraction = 1.0 / ((gdouble) rate / 1000.0);
g_value_set_double (value, fraction);
return TRUE;
}
static GVariant *
set_rate (const GValue *value,
const GVariantType *expected_type,
gpointer user_data)
{
gdouble rate;
int msecs;
rate = g_value_get_double (value);
msecs = (1 / rate) * 1000;
return g_variant_new_uint32 (msecs);
}
PreferencesDialog *
preferences_dialog_new (void)
{
PreferencesDialog *dialog;
gchar *ui_path;
GtkBuilder *builder;
GObject *object;
GError *error;
dialog = g_slice_new0 (PreferencesDialog);
dialog->settings = g_settings_new ("org.fedorahosted.eekboard");
builder = gtk_builder_new ();
gtk_builder_set_translation_domain (builder, "eekboard");
ui_path = g_strdup_printf ("%s/%s", PKGDATADIR, "preferences-dialog.ui");
error = NULL;
gtk_builder_add_from_file (builder, ui_path, &error);
g_free (ui_path);
object =
gtk_builder_get_object (builder, "dialog");
dialog->dialog = GTK_WIDGET(object);
object =
gtk_builder_get_object (builder, "repeat_toggle");
dialog->repeat_toggle = GTK_WIDGET(object);
g_settings_bind (dialog->settings, "repeat",
dialog->repeat_toggle, "active",
G_SETTINGS_BIND_DEFAULT);
object =
gtk_builder_get_object (builder, "repeat_delay_scale");
dialog->repeat_delay_scale = GTK_WIDGET(object);
g_settings_bind (dialog->settings, "repeat-delay",
gtk_range_get_adjustment (GTK_RANGE (dialog->repeat_delay_scale)), "value",
G_SETTINGS_BIND_DEFAULT);
object =
gtk_builder_get_object (builder, "repeat_speed_scale");
dialog->repeat_speed_scale = GTK_WIDGET(object);
g_settings_bind_with_mapping (dialog->settings, "repeat-interval",
gtk_range_get_adjustment (GTK_RANGE (gtk_builder_get_object (builder, "repeat_speed_scale"))), "value",
G_SETTINGS_BIND_DEFAULT,
get_rate, set_rate, NULL, NULL);
object =
gtk_builder_get_object (builder, "auto_hide_toggle");
dialog->auto_hide_toggle = GTK_WIDGET(object);
g_settings_bind (dialog->settings, "auto-hide",
dialog->auto_hide_toggle, "active",
G_SETTINGS_BIND_DEFAULT);
object =
gtk_builder_get_object (builder, "auto_hide_delay_scale");
dialog->auto_hide_delay_scale = GTK_WIDGET(object);
g_settings_bind (dialog->settings, "auto-hide-delay",
gtk_range_get_adjustment (GTK_RANGE (dialog->auto_hide_delay_scale)), "value",
G_SETTINGS_BIND_DEFAULT);
object =
gtk_builder_get_object (builder, "start_fullscreen_toggle");
dialog->start_fullscreen_toggle = GTK_WIDGET(object);
g_settings_bind (dialog->settings, "start-fullscreen",
dialog->start_fullscreen_toggle, "active",
G_SETTINGS_BIND_DEFAULT);
object =
gtk_builder_get_object (builder, "keyboard_entry");
dialog->keyboard_entry = GTK_WIDGET(object);
g_settings_bind (dialog->settings, "keyboard",
GTK_ENTRY(dialog->keyboard_entry), "text",
G_SETTINGS_BIND_DEFAULT);
return dialog;
}
void
preferences_dialog_run (PreferencesDialog *dialog)
{
gtk_window_present (GTK_WINDOW(dialog->dialog));
gtk_dialog_run (GTK_DIALOG(dialog->dialog));
gtk_widget_destroy (dialog->dialog);
}

View File

@ -15,12 +15,15 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef EEKBOARD_H
#define EEKBOARD_H 1
#ifndef PREFERENCES_DIALOG_H
#define PREFERENCES_DIALOG_H 1
#define __EEKBOARD_H_INSIDE__ 1
G_BEGIN_DECLS
#include "eekboard/eekboard-eekboard.h"
#include "eekboard/eekboard-context.h"
typedef struct _PreferencesDialog PreferencesDialog;
#endif /* EEKBOARD_H */
PreferencesDialog *preferences_dialog_new (void);
void preferences_dialog_run (PreferencesDialog *dialog);
G_END_DECLS
#endif /* PREFERENCES_DIALOG_H */

626
src/preferences-dialog.ui Normal file
View File

@ -0,0 +1,626 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.0 -->
<object class="GtkDialog" id="dialog">
<property name="can_focus">False</property>
<property name="border_width">5</property>
<property name="title" translatable="yes">Keyboard</property>
<property name="modal">True</property>
<property name="type_hint">dialog</property>
<child internal-child="vbox">
<object class="GtkBox" id="dialog-vbox4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkButtonBox" id="dialog-action_area5">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<object class="GtkButton" id="button1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="related_action">action1</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkNotebook" id="keyboard_notebook">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="border_width">10</property>
<child>
<object class="GtkVBox" id="general_page">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="border_width">12</property>
<property name="spacing">18</property>
<child>
<object class="GtkVBox" id="vbox22">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel" id="label300">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Repeat Keys</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkHBox" id="hbox19">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkLabel" id="label43">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label"> </property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkVBox" id="vbox100">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">6</property>
<child>
<object class="GtkCheckButton" id="repeat_toggle">
<property name="label" translatable="yes">Key presses _repeat when key is held down</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="use_underline">True</property>
<property name="xalign">0</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkTable" id="repeat_table">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="n_rows">2</property>
<property name="n_columns">4</property>
<child>
<object class="GtkLabel" id="repeat_speed_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">_Speed:</property>
<property name="use_underline">True</property>
<property name="justify">center</property>
<property name="mnemonic_widget">repeat_speed_scale</property>
</object>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_SHRINK</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="GtkLabel" id="delay_short_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="xpad">10</property>
<property name="label" translatable="yes">Short</property>
<attributes>
<attribute name="style" value="italic"/>
<attribute name="scale" value="0.82999999999999996"/>
</attributes>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="x_options">GTK_SHRINK</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="GtkLabel" id="repeat_slow_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="xpad">10</property>
<property name="label" translatable="yes">Slow</property>
<attributes>
<attribute name="style" value="italic"/>
<attribute name="scale" value="0.82999999999999996"/>
</attributes>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_SHRINK</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="GtkHScale" id="repeat_delay_scale">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="adjustment">repeat_delay_adjustment</property>
<property name="draw_value">False</property>
</object>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="GtkHScale" id="repeat_speed_scale">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="adjustment">repeat_speed_adjustment</property>
<property name="draw_value">False</property>
<child internal-child="accessible">
<object class="AtkObject" id="repeat_speed_scale-atkobject">
<property name="AtkObject::accessible-description" translatable="yes">Repeat keys speed</property>
</object>
</child>
</object>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="GtkLabel" id="delay_long_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Long</property>
<attributes>
<attribute name="style" value="italic"/>
<attribute name="scale" value="0.82999999999999996"/>
</attributes>
</object>
<packing>
<property name="left_attach">3</property>
<property name="right_attach">4</property>
<property name="x_options">GTK_SHRINK</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="GtkLabel" id="repeat_fast_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Fast</property>
<attributes>
<attribute name="style" value="italic"/>
<attribute name="scale" value="0.82999999999999996"/>
</attributes>
</object>
<packing>
<property name="left_attach">3</property>
<property name="right_attach">4</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_SHRINK</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="GtkLabel" id="repeat_delay_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">_Delay:</property>
<property name="use_underline">True</property>
<property name="justify">center</property>
<property name="mnemonic_widget">repeat_delay_scale</property>
</object>
<packing>
<property name="x_options">GTK_SHRINK</property>
<property name="y_options"></property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkVBox" id="vbox230">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel" id="label5">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Focus following</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkHBox" id="hbox20">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkLabel" id="label44">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label"> </property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkVBox" id="appearances_vbox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">6</property>
<child>
<object class="GtkCheckButton" id="auto_hide_toggle">
<property name="label" translatable="yes">Auto hide window when focus is out</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="use_underline">True</property>
<property name="xalign">0</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkTable" id="table1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="n_columns">4</property>
<child>
<object class="GtkLabel" id="auto_hide_delay_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">_Delay:</property>
<property name="use_underline">True</property>
<property name="justify">center</property>
<property name="mnemonic_widget">auto_hide_delay_scale</property>
</object>
<packing>
<property name="x_options">GTK_SHRINK</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="GtkLabel" id="auto_hide_delay_short_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="xpad">10</property>
<property name="label" translatable="yes">Short</property>
<attributes>
<attribute name="style" value="italic"/>
<attribute name="scale" value="0.82999999999999996"/>
</attributes>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="x_options">GTK_SHRINK</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="GtkHScale" id="auto_hide_delay_scale">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="adjustment">auto_hide_delay_adjustment</property>
<property name="draw_value">False</property>
</object>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="GtkLabel" id="auto_hide_delay_long_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Long</property>
<attributes>
<attribute name="style" value="italic"/>
<attribute name="scale" value="0.82999999999999996"/>
</attributes>
</object>
<packing>
<property name="left_attach">3</property>
<property name="right_attach">4</property>
<property name="x_options">GTK_SHRINK</property>
<property name="y_options"></property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkVBox" id="vbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Keyboard</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkHBox" id="hbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label"> </property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkVBox" id="appearances_vbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">6</property>
<child>
<object class="GtkCheckButton" id="start_fullscreen_toggle">
<property name="label" translatable="yes">Start in fullscreen mode</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="use_underline">True</property>
<property name="xalign">0</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkTable" id="table2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="n_columns">4</property>
<child>
<object class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Keyboard type: </property>
</object>
</child>
<child>
<object class="GtkEntry" id="keyboard_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">●</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">4</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
<child type="tab">
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Typing</property>
</object>
<packing>
<property name="tab_fill">False</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child type="tab">
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child type="tab">
<placeholder/>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
<action-widgets>
<action-widget response="0">button1</action-widget>
</action-widgets>
</object>
<object class="GtkAction" id="action1">
<property name="stock_id">gtk-close</property>
</object>
<object class="GtkAdjustment" id="repeat_delay_adjustment">
<property name="lower">100</property>
<property name="upper">2000</property>
<property name="value">500</property>
<property name="step_increment">10</property>
<property name="page_increment">10</property>
</object>
<object class="GtkAdjustment" id="repeat_speed_adjustment">
<property name="lower">0.5</property>
<property name="upper">50</property>
<property name="value">33.299999999999997</property>
<property name="step_increment">1</property>
<property name="page_increment">1</property>
</object>
<object class="GtkAdjustment" id="auto_hide_delay_adjustment">
<property name="lower">100</property>
<property name="upper">2000</property>
<property name="value">500</property>
<property name="step_increment">10</property>
<property name="page_increment">10</property>
</object>
</interface>

View File

@ -0,0 +1,499 @@
/*
* Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2010-2011 Red Hat, Inc.
*
* 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/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#include <gtk/gtk.h>
#include <glib/gi18n.h>
#include <X11/Xatom.h>
#include <gdk/gdkx.h>
#if HAVE_CLUTTER_GTK
#include <clutter-gtk/clutter-gtk.h>
#include "eek/eek-clutter.h"
#endif
#include "eek/eek-gtk.h"
#include "server-context-service.h"
enum {
PROP_0,
PROP_UI_TOOLKIT,
PROP_LAST
};
typedef enum {
UI_TOOLKIT_GTK,
UI_TOOLKIT_CLUTTER,
UI_TOOLKIT_DEFAULT = UI_TOOLKIT_GTK
} UIToolkitType;
typedef struct _ServerContextServiceClass ServerContextServiceClass;
struct _ServerContextService {
EekboardContextService parent;
gboolean was_visible;
GtkWidget *window;
GtkWidget *widget;
gulong notify_visible_handler;
GSettings *settings;
UIToolkitType ui_toolkit;
};
struct _ServerContextServiceClass {
EekboardContextServiceClass parent_class;
};
G_DEFINE_TYPE (ServerContextService, server_context_service, EEKBOARD_TYPE_CONTEXT_SERVICE);
static void update_widget (ServerContextService *context);
static void set_geometry (ServerContextService *context);
static void
on_monitors_changed (GdkScreen *screen,
gpointer user_data)
{
ServerContextService *context = user_data;
if (context->window)
set_geometry (context);
}
#if HAVE_CLUTTER_GTK
static void
on_allocation_changed (ClutterActor *stage,
ClutterActorBox *box,
ClutterAllocationFlags flags,
gpointer user_data)
{
ClutterActor *actor =
clutter_container_find_child_by_name (CLUTTER_CONTAINER(stage),
"keyboard");
clutter_actor_set_size (actor,
box->x2 - box->x1,
box->y2 - box->y1);
}
#endif
static void
on_destroy (GtkWidget *widget, gpointer user_data)
{
ServerContextService *context = user_data;
g_assert (widget == context->window);
context->window = NULL;
context->widget = NULL;
}
static void
on_notify_keyboard (GObject *object,
GParamSpec *spec,
gpointer user_data)
{
ServerContextService *context = user_data;
const EekKeyboard *keyboard;
keyboard = eekboard_context_service_get_keyboard (EEKBOARD_CONTEXT_SERVICE(context));
if (context->window) {
if (keyboard == NULL) {
gtk_widget_hide (context->window);
gtk_widget_destroy (context->widget);
} else {
gboolean was_visible = gtk_widget_get_visible (context->window);
/* avoid to send KeyboardVisibilityChanged */
g_signal_handler_block (context->window,
context->notify_visible_handler);
update_widget (context);
if (was_visible)
gtk_widget_show_all (context->window);
g_signal_handler_unblock (context->window,
context->notify_visible_handler);
}
}
}
static void
on_notify_fullscreen (GObject *object,
GParamSpec *spec,
gpointer user_data)
{
ServerContextService *context = user_data;
if (context->window)
set_geometry (context);
}
static void
on_notify_visible (GObject *object, GParamSpec *spec, gpointer user_data)
{
ServerContextService *context = user_data;
gboolean visible;
g_object_get (object, "visible", &visible, NULL);
g_object_set (context, "visible", visible, NULL);
}
static void
on_realize_set_dock (GtkWidget *widget,
gpointer user_data)
{
#ifdef HAVE_XDOCK
GdkWindow *window = gtk_widget_get_window (widget);
gint x, y, width, height;
#if !GTK_CHECK_VERSION(3,0,0)
gint depth;
#endif /* GTK_CHECK_VERSION(3,0,0) */
long vals[12];
/* set window type to dock */
gdk_window_set_type_hint (window, GDK_WINDOW_TYPE_HINT_DOCK);
/* set bottom strut */
#if GTK_CHECK_VERSION(3,0,0)
gdk_window_get_geometry (window, &x, &y, &width, &height);
#else
gdk_window_get_geometry (window, &x, &y, &width, &height, &depth);
#endif /* GTK_CHECK_VERSION(3,0,0) */
vals[0] = 0;
vals[1] = 0;
vals[2] = 0;
vals[3] = height;
vals[4] = 0;
vals[5] = 0;
vals[6] = 0;
vals[7] = 0;
vals[8] = 0;
vals[9] = 0;
vals[10] = x;
vals[11] = x + width;
XChangeProperty (GDK_WINDOW_XDISPLAY (window),
GDK_WINDOW_XID (window),
XInternAtom (GDK_WINDOW_XDISPLAY (window),
"_NET_WM_STRUT_PARTIAL", False),
XA_CARDINAL, 32, PropModeReplace,
(guchar *)vals, 12);
#endif /* HAVE_XDOCK */
}
static void
on_realize_set_non_maximizable (GtkWidget *widget,
gpointer user_data)
{
ServerContextService *context = user_data;
g_assert (context && context->window == widget);
/* make the window not maximizable */
gdk_window_set_functions (gtk_widget_get_window (widget),
GDK_FUNC_RESIZE |
GDK_FUNC_MOVE |
GDK_FUNC_MINIMIZE |
GDK_FUNC_CLOSE);
}
static void
set_geometry (ServerContextService *context)
{
GdkScreen *screen;
GdkWindow *root;
gint monitor;
GdkRectangle rect;
const EekKeyboard *keyboard;
EekBounds bounds;
screen = gdk_screen_get_default ();
root = gtk_widget_get_root_window (context->window);
monitor = gdk_screen_get_monitor_at_window (screen, root);
gdk_screen_get_monitor_geometry (screen, monitor, &rect);
keyboard = eekboard_context_service_get_keyboard (EEKBOARD_CONTEXT_SERVICE(context));
eek_element_get_bounds (EEK_ELEMENT(keyboard), &bounds);
g_signal_handlers_disconnect_by_func (context->window,
on_realize_set_dock,
context);
g_signal_handlers_disconnect_by_func (context->window,
on_realize_set_non_maximizable,
context);
if (eekboard_context_service_get_fullscreen (EEKBOARD_CONTEXT_SERVICE(context))) {
gint width = rect.width, height = rect.height / 2;
if (width * bounds.height > height * bounds.width)
width = (height / bounds.height) * bounds.width;
else
height = (width / bounds.width) * bounds.height;
gtk_widget_set_size_request (context->widget, width, height);
gtk_window_move (GTK_WINDOW(context->window),
(rect.width - width) / 2,
rect.height - height);
gtk_window_set_decorated (GTK_WINDOW(context->window), FALSE);
gtk_window_set_resizable (GTK_WINDOW(context->window), FALSE);
gtk_window_set_opacity (GTK_WINDOW(context->window), 0.8);
g_signal_connect_after (context->window, "realize",
G_CALLBACK(on_realize_set_dock),
context);
} else {
if (context->ui_toolkit == UI_TOOLKIT_CLUTTER) {
#if HAVE_CLUTTER_GTK
ClutterActor *stage =
gtk_clutter_embed_get_stage (GTK_CLUTTER_EMBED(context->widget));
clutter_stage_set_user_resizable (CLUTTER_STAGE(stage), TRUE);
clutter_stage_set_minimum_size (CLUTTER_STAGE(stage),
bounds.width / 3,
bounds.height / 3);
g_signal_connect (stage,
"allocation-changed",
G_CALLBACK(on_allocation_changed),
NULL);
#else
g_return_if_reached ();
#endif
}
gtk_widget_set_size_request (context->widget,
bounds.width,
bounds.height);
gtk_window_move (GTK_WINDOW(context->window),
MAX(rect.width - 20 - bounds.width, 0),
MAX(rect.height - 40 - bounds.height, 0));
g_signal_connect_after (context->window, "realize",
G_CALLBACK(on_realize_set_non_maximizable),
context);
}
}
static void
update_widget (ServerContextService *context)
{
EekKeyboard *keyboard;
const gchar *client_name;
EekBounds bounds;
gchar *theme_name, *theme_path;
EekTheme *theme;
#if HAVE_CLUTTER_GTK
ClutterActor *stage, *actor;
ClutterColor stage_color = { 0xff, 0xff, 0xff, 0xff };
#endif
if (context->widget)
gtk_widget_destroy (context->widget);
theme_name = g_settings_get_string (context->settings, "theme");
theme_path = g_strdup_printf ("%s/%s.css", THEMEDIR, theme_name);
g_free (theme_name);
theme = eek_theme_new (theme_path, NULL, NULL);
g_free (theme_path);
keyboard = eekboard_context_service_get_keyboard (EEKBOARD_CONTEXT_SERVICE(context));
eek_element_get_bounds (EEK_ELEMENT(keyboard), &bounds);
if (context->ui_toolkit == UI_TOOLKIT_CLUTTER) {
#if HAVE_CLUTTER_GTK
context->widget = gtk_clutter_embed_new ();
stage = gtk_clutter_embed_get_stage (GTK_CLUTTER_EMBED(context->widget));
actor = eek_clutter_keyboard_new (keyboard);
clutter_actor_set_name (actor, "keyboard");
eek_clutter_keyboard_set_theme (EEK_CLUTTER_KEYBOARD(actor), theme);
g_object_unref (theme);
clutter_container_add_actor (CLUTTER_CONTAINER(stage), actor);
clutter_stage_set_color (CLUTTER_STAGE(stage), &stage_color);
#else
g_return_if_reached ();
#endif
} else {
context->widget = eek_gtk_keyboard_new (keyboard);
eek_gtk_keyboard_set_theme (EEK_GTK_KEYBOARD(context->widget), theme);
g_object_unref (theme);
}
if (!context->window) {
context->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_signal_connect (context->window, "destroy",
G_CALLBACK(on_destroy), context);
context->notify_visible_handler =
g_signal_connect (context->window, "notify::visible",
G_CALLBACK(on_notify_visible), context);
gtk_widget_set_can_focus (context->window, FALSE);
g_object_set (G_OBJECT(context->window), "accept_focus", FALSE, NULL);
client_name = eekboard_context_service_get_client_name (EEKBOARD_CONTEXT_SERVICE(context));
gtk_window_set_title (GTK_WINDOW(context->window),
client_name ? client_name : _("Keyboard"));
gtk_window_set_icon_name (GTK_WINDOW(context->window), "eekboard");
gtk_window_set_keep_above (GTK_WINDOW(context->window), TRUE);
}
gtk_container_add (GTK_CONTAINER(context->window), context->widget);
set_geometry (context);
}
static void
server_context_service_real_show_keyboard (EekboardContextService *_context)
{
ServerContextService *context = SERVER_CONTEXT_SERVICE(_context);
if (!context->window)
update_widget (context);
g_assert (context->window);
gtk_widget_show_all (context->window);
}
static void
server_context_service_real_hide_keyboard (EekboardContextService *_context)
{
ServerContextService *context = SERVER_CONTEXT_SERVICE(_context);
if (context->window)
gtk_widget_hide (context->window);
}
static void
server_context_service_real_enabled (EekboardContextService *_context)
{
ServerContextService *context = SERVER_CONTEXT_SERVICE(_context);
if (context->was_visible && context->window)
gtk_widget_show_all (context->window);
}
static void
server_context_service_real_disabled (EekboardContextService *_context)
{
ServerContextService *context = SERVER_CONTEXT_SERVICE(_context);
if (context->window) {
context->was_visible =
gtk_widget_get_visible (context->window);
gtk_widget_hide (context->window);
}
}
static void
server_context_service_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
ServerContextService *context = SERVER_CONTEXT_SERVICE(object);
const gchar *ui_toolkit;
switch (prop_id) {
case PROP_UI_TOOLKIT:
ui_toolkit = g_value_get_string (value);
if (g_strcmp0 (ui_toolkit, "gtk") == 0)
context->ui_toolkit = UI_TOOLKIT_GTK;
#if HAVE_CLUTTER_GTK
else if (g_strcmp0 (ui_toolkit, "clutter") == 0)
context->ui_toolkit = UI_TOOLKIT_CLUTTER;
#endif /* HAVE_CLUTTER_GTK */
else
g_warning ("unknown UI toolkit %s", ui_toolkit);
break;
default:
g_object_set_property (object,
g_param_spec_get_name (pspec),
value);
break;
}
}
static void
server_context_service_dispose (GObject *object)
{
ServerContextService *context = SERVER_CONTEXT_SERVICE(object);
if (context->window) {
gtk_widget_destroy (context->window);
context->window = NULL;
}
G_OBJECT_CLASS (server_context_service_parent_class)->dispose (object);
}
static void
server_context_service_class_init (ServerContextServiceClass *klass)
{
EekboardContextServiceClass *context_class = EEKBOARD_CONTEXT_SERVICE_CLASS(klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GParamSpec *pspec;
context_class->show_keyboard = server_context_service_real_show_keyboard;
context_class->hide_keyboard = server_context_service_real_hide_keyboard;
context_class->enabled = server_context_service_real_enabled;
context_class->disabled = server_context_service_real_disabled;
gobject_class->set_property = server_context_service_set_property;
gobject_class->dispose = server_context_service_dispose;
pspec = g_param_spec_string ("ui-toolkit",
"UI toolkit",
"UI toolkit",
NULL,
G_PARAM_WRITABLE);
g_object_class_install_property (gobject_class,
PROP_UI_TOOLKIT,
pspec);
}
static void
server_context_service_init (ServerContextService *context)
{
GdkScreen *screen;
screen = gdk_screen_get_default ();
g_signal_connect (screen,
"monitors-changed",
G_CALLBACK(on_monitors_changed),
context);
g_signal_connect (context,
"notify::keyboard",
G_CALLBACK(on_notify_keyboard),
context);
g_signal_connect (context,
"notify::fullscreen",
G_CALLBACK(on_notify_fullscreen),
context);
context->settings = g_settings_new ("org.fedorahosted.eekboard");
g_settings_bind (context->settings, "ui-toolkit",
context, "ui-toolkit",
G_SETTINGS_BIND_GET);
}
ServerContextService *
server_context_service_new (const gchar *client_name,
const gchar *object_path,
GDBusConnection *connection)
{
return g_object_new (SERVER_TYPE_CONTEXT_SERVICE,
"client-name", client_name,
"object-path", object_path,
"connection", connection,
NULL);
}

Some files were not shown because too many files have changed in this diff Show More