summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Pellicer <davidpellicermartin@gmail.com>2010-12-07 09:19:56 -0800
committerEitan Isaacson <eitan@monotonous.org>2010-12-07 09:20:23 -0800
commitc35d19ab7d43328c33e9b1916f8508df944c2fc3 (patch)
treef364c59fe88ee4b3a8c3c9e66831daf992d968ef
parent8d0fc8934626783e05f55a5c4235924faed9d1df (diff)
downloadcaribou-c35d19ab7d43328c33e9b1916f8508df944c2fc3.tar.gz
Added scanning support.
-rw-r--r--caribou/common/const.py22
-rw-r--r--caribou/ui/Makefile.am1
-rw-r--r--caribou/ui/__init__.py2
-rw-r--r--caribou/ui/keyboard.py241
-rw-r--r--caribou/ui/main.py7
-rw-r--r--caribou/ui/scan.py438
-rw-r--r--caribou/ui/window.py6
-rw-r--r--data/caribou-prefs.ui309
8 files changed, 1020 insertions, 6 deletions
diff --git a/caribou/common/const.py b/caribou/common/const.py
index 202bc16..ecb61da 100644
--- a/caribou/common/const.py
+++ b/caribou/common/const.py
@@ -56,3 +56,25 @@ KEY_MASKS = {'shift': gtk.gdk.SHIFT_MASK,
'button3': gtk.gdk.BUTTON3_MASK,
'button4': gtk.gdk.BUTTON4_MASK,
'button5': gtk.gdk.BUTTON5_MASK}
+
+# Scan constans
+BUTTON = 'button'
+ROW = '1'
+BLOCK = '0'
+CANCEL = 'cancel'
+REVERSE = 'reverse'
+MOUSE_SWITCH_TYPE = 'mouse'
+KEYBOARD_SWITCH_TYPE = 'keyboard'
+KEYBOARD_KEY_LIST = {"Shift R" : "Shift_R",
+ "Shift L" : "Shift_L",
+ "Alt Gr" : "ISO_Level3_Shift",
+ "Num Lock": "Num_Lock"}
+DEFAULT_KEYBOARD_KEY = 'Shift R'
+DEFAULT_MOUSE_BUTTON = '1'
+MIN_STEP_TIME = 50
+MAX_STEP_TIME = 5000
+TIME_SINGLE_INCREMENT = 1
+TIME_MULTI_INCREMENT = 10
+DEFAULT_STEP_TIME = 1000
+DEFAULT_SCANNING_TYPE = ROW
+DEFAULT_SWITCH_TYPE = KEYBOARD_SWITCH_TYPE
diff --git a/caribou/ui/Makefile.am b/caribou/ui/Makefile.am
index f4a352d..27046b4 100644
--- a/caribou/ui/Makefile.am
+++ b/caribou/ui/Makefile.am
@@ -5,6 +5,7 @@ caribou_ui_PYTHON = \
animation.py \
i18n.py \
keyboard.py \
+ scan.py \
main.py \
opacity.py \
window.py
diff --git a/caribou/ui/__init__.py b/caribou/ui/__init__.py
index 8d1c8b6..8b13789 100644
--- a/caribou/ui/__init__.py
+++ b/caribou/ui/__init__.py
@@ -1 +1 @@
-
+
diff --git a/caribou/ui/keyboard.py b/caribou/ui/keyboard.py
index ace93b0..e395af8 100644
--- a/caribou/ui/keyboard.py
+++ b/caribou/ui/keyboard.py
@@ -23,6 +23,7 @@
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import caribou.common.const as const
+import caribou.ui.scan as scan
import gconf
import gobject
import gtk
@@ -31,6 +32,7 @@ import sys
import virtkey
import os
import traceback
+from caribou.ui.i18n import _
try:
import json
except ImportError:
@@ -119,6 +121,150 @@ class KeyboardPreferences:
self._on_default_font_toggled,
client, key_font_button)
+ reverse_scanning_checkbox = builder.get_object(
+ "reverse_scanning_checkbox")
+
+ reverse_scanning = client.get_bool(const.CARIBOU_GCONF +
+ "/reverse_scanning")
+ if reverse_scanning is None:
+ reverse_scanning is False
+ reverse_scanning_checkbox.set_active(reverse_scanning)
+ reverse_scanning_checkbox.connect('toggled',
+ self._on_reverse_scanning_toggled,
+ client)
+
+ block_scanning_color_button = builder.get_object("block_scanning_color_button")
+ block_scanning_color_string = client.get_string(const.CARIBOU_GCONF +
+ "/block_scanning_color") or "purple"
+ block_scanning_color = gtk.gdk.Color(block_scanning_color_string)
+ block_scanning_color_button.set_color(block_scanning_color)
+ block_scanning_color_button.connect("color-set",
+ self._on_block_scanning_color_set,
+ client)
+
+ row_scanning_color_button = builder.get_object("row_scanning_color_button")
+ row_scanning_color_string = client.get_string(const.CARIBOU_GCONF +
+ "/row_scanning_color") or "blue"
+ row_scanning_color = gtk.gdk.Color(row_scanning_color_string)
+ row_scanning_color_button.set_color(row_scanning_color)
+ row_scanning_color_button.connect("color-set",
+ self._on_row_scanning_color_set,
+ client)
+
+ button_scanning_color_button = builder.get_object("button_scanning_color_button")
+ button_scanning_color_string = client.get_string(const.CARIBOU_GCONF +
+ "/button_scanning_color") or "green"
+ button_scanning_color = gtk.gdk.Color(button_scanning_color_string)
+ button_scanning_color_button.set_color(button_scanning_color)
+ button_scanning_color_button.connect("color-set",
+ self._on_button_scanning_color_set,
+ client)
+
+ cancel_scanning_color_button = builder.get_object(
+ "cancel_scanning_color_button")
+ cancel_scanning_color_string = client.get_string(const.CARIBOU_GCONF +
+ "/cancel_scanning_color") or "red"
+ cancel_scanning_color = gtk.gdk.Color(cancel_scanning_color_string)
+ cancel_scanning_color_button.set_color(cancel_scanning_color)
+ cancel_scanning_color_button.connect("color-set",
+ self._on_cancel_scanning_color_set,
+ client)
+ scanning_type_combo = builder.get_object("scanning_type_combo")
+ scanning_type_combo.connect("changed",
+ self._on_scanning_type_combo_changed,
+ client)
+ types = [_("block"), _("row")]
+ for type in types:
+ scanning_type_combo.append_text(type)
+ type = client.get_string(const.CARIBOU_GCONF + "/scanning_type")
+ try:
+ scanning_type_combo.set_active(int(type))
+ except:
+ scanning_type_combo.set_active(0)
+
+
+ mouse_button_combo = builder.get_object("mouse_button_combo")
+ mouse_button_combo.connect("changed",
+ self._on_mouse_button_combo_changed,
+ client)
+ mouse_buttons = [_("Left"), _("Center"), _("Right")]
+ for button in mouse_buttons:
+ mouse_button_combo.append_text(button)
+ button = client.get_string(const.CARIBOU_GCONF + "/mouse_button")
+ try:
+ mouse_button_combo.set_active(int(button)-1)
+ except:
+ mouse_button_combo.set_active(0)
+
+
+ keyboard_key_combo = builder.get_object("keyboard_key_combo")
+ keyboard_keys = const.KEYBOARD_KEY_LIST.keys()
+ keyboard_values = const.KEYBOARD_KEY_LIST.values()
+ for key in keyboard_keys:
+ keyboard_key_combo.append_text(key)
+ key = client.get_string(const.CARIBOU_GCONF + "/keyboard_key")
+ try:
+ keyboard_key_combo.set_active(keyboard_values.index(key))
+ except:
+ keyboard_key_combo.set_active(0)
+
+ keyboard_key_combo.connect("changed",
+ self._on_keyboard_key_combo_changed,
+ client)
+
+ mouse_switch_radio = builder.get_object("mouse_switch_radio")
+ keyboard_switch_radio = builder.get_object("keyboard_switch_radio")
+ mouse_switch_radio.connect("toggled", self._on_switch_radio_toggled,
+ client, mouse_button_combo,
+ keyboard_key_combo)
+
+ switch_type = client.get_string(const.CARIBOU_GCONF + "/switch_type")
+ if switch_type == const.KEYBOARD_SWITCH_TYPE:
+ keyboard_switch_radio.set_active(True)
+ else:
+ mouse_switch_radio.set_active(True)
+
+ step_time_spin = builder.get_object("step_time_spin")
+ step_time_spin.set_value(client.get_int(const.CARIBOU_GCONF +
+ "/step_time"))
+ step_time_spin.connect("value_changed",
+ self._on_step_time_spin_changed, client)
+
+ scan_enabled_checkbox = builder.get_object("scan_enabled_checkbox")
+ scan_enabled = client.get_bool(const.CARIBOU_GCONF + "/scan_enabled")
+ if scan_enabled is None:
+ scan_enabled is False
+
+ scan_enabled_checkbox.set_active(scan_enabled)
+
+ self._on_scan_enabled_toggled(scan_enabled_checkbox,
+ client, reverse_scanning_checkbox,
+ row_scanning_color_button,
+ button_scanning_color_button,
+ block_scanning_color_button,
+ cancel_scanning_color_button,
+ mouse_switch_radio,
+ keyboard_switch_radio,
+ mouse_button_combo,
+ keyboard_key_combo,
+ scanning_type_combo,
+ step_time_spin)
+
+ scan_enabled_checkbox.connect('toggled',
+ self._on_scan_enabled_toggled, client,
+ reverse_scanning_checkbox,
+ row_scanning_color_button,
+ block_scanning_color_button,
+ button_scanning_color_button,
+ cancel_scanning_color_button,
+ mouse_switch_radio,
+ keyboard_switch_radio,
+ mouse_button_combo,
+ keyboard_key_combo,
+ scanning_type_combo,
+ step_time_spin)
+
+
kbds = self._fetch_keyboards()
for kbddef in kbds:
layout_combo.append_text(kbddef)
@@ -149,6 +295,36 @@ class KeyboardPreferences:
normal_color_button.set_sensitive(not use_defaults)
mouse_over_color_button.set_sensitive(not use_defaults)
+ def _on_scan_enabled_toggled(self, scan_enabled_checkbox,
+ gconf_client, *args):
+ scan_enabled = scan_enabled_checkbox.get_active()
+ gconf_client.set_bool(const.CARIBOU_GCONF + "/scan_enabled", scan_enabled)
+ for arg in args:
+ arg.set_sensitive(scan_enabled)
+
+ def _on_reverse_scanning_toggled(self, reverse_scanning_checkbox,
+ gconf_client):
+ reverse_scanning = reverse_scanning_checkbox.get_active()
+ gconf_client.set_bool(const.CARIBOU_GCONF + "/reverse_scanning",
+ reverse_scanning)
+ def _on_switch_radio_toggled(self, mouse_switch_radio,
+ gconf_client, mouse_button_combo,
+ keyboard_key_combo):
+ mouse_switch = mouse_switch_radio.get_active()
+ if mouse_switch:
+ gconf_client.set_string(const.CARIBOU_GCONF + "/switch_type",
+ const.MOUSE_SWITCH_TYPE)
+ else:
+ gconf_client.set_string(const.CARIBOU_GCONF + "/switch_type",
+ const.KEYBOARD_SWITCH_TYPE)
+ mouse_button_combo.set_sensitive(mouse_switch)
+ keyboard_key_combo.set_sensitive(not mouse_switch)
+
+ def _on_step_time_spin_changed(self, step_time_spin, gconf_client):
+ gconf_client.set_int(const.CARIBOU_GCONF + "/step_time",
+ step_time_spin.get_value_as_int())
+
+
def destroy(self, widget, data = None):
self.window.destroy()
@@ -167,13 +343,46 @@ class KeyboardPreferences:
def _on_layout_changed(self, combobox, client):
kbdname = combobox.get_active_text()
- if kbdname:
+ actual_layout = client.get_string("/apps/caribou/osk/layout")
+ if kbdname and kbdname != actual_layout:
client.set_string("/apps/caribou/osk/layout", kbdname)
+ def _on_scanning_type_combo_changed(self, scanning_type_combo, gconf_client):
+ value = str(scanning_type_combo.get_active())
+ if value:
+ gconf_client.set_string(const.CARIBOU_GCONF + "/scanning_type", value)
+
+ def _on_mouse_button_combo_changed(self, mouse_button_combo, client):
+ value = mouse_button_combo.get_active() + 1
+ if value:
+ client.set_string(const.CARIBOU_GCONF + "/mouse_button", str(value))
+
+ def _on_keyboard_key_combo_changed(self, keyboard_key_combo, client):
+ value = keyboard_key_combo.get_active_text()
+ if value:
+ client.set_string(const.CARIBOU_GCONF + "/keyboard_key",
+ const.KEYBOARD_KEY_LIST[value])
+
def _on_normal_state_color_set(self, colorbutton, client):
color = colorbutton.get_color().to_string()
client.set_string(const.CARIBOU_GCONF + "/normal_color", color)
+ def _on_block_scanning_color_set(self, colorbutton, client):
+ color = colorbutton.get_color().to_string()
+ client.set_string(const.CARIBOU_GCONF + "/block_scanning_color", color)
+
+ def _on_row_scanning_color_set(self, colorbutton, client):
+ color = colorbutton.get_color().to_string()
+ client.set_string(const.CARIBOU_GCONF + "/row_scanning_color", color)
+
+ def _on_button_scanning_color_set(self, colorbutton, client):
+ color = colorbutton.get_color().to_string()
+ client.set_string(const.CARIBOU_GCONF + "/button_scanning_color", color)
+
+ def _on_cancel_scanning_color_set(self, colorbutton, client):
+ color = colorbutton.get_color().to_string()
+ client.set_string(const.CARIBOU_GCONF + "/cancel_scanning_color", color)
+
def _on_mouse_over_color_set(self, colorbutton, client):
color = colorbutton.get_color().to_string()
client.set_string(const.CARIBOU_GCONF + "/mouse_over_color", color)
@@ -433,10 +642,14 @@ class CaribouKeyboard(gtk.Notebook):
self._gconf_connections.append(self.client.notify_add(
const.CARIBOU_GCONF + "/key_font",
self._key_font_changed))
+ self._gconf_connections.append(self.client.notify_add(
+ const.CARIBOU_GCONF + "/scan_enabled",
+ self._scan_enabled))
self.connect('size-allocate', self._on_size_allocate)
self.row_height = -1
+ self.scan_enabled = False
self.keyboard_preferences = KeyboardPreferences()
def reset_row_height(self):
@@ -466,6 +679,7 @@ class CaribouKeyboard(gtk.Notebook):
layouts = kb_deserializer.deserialize(kb_location)
self._set_layouts(layouts)
self._update_key_style()
+ self._enable_scanning()
def _set_layouts(self, layout_list):
self._clear()
@@ -486,6 +700,9 @@ class CaribouKeyboard(gtk.Notebook):
key.connect('clicked',
self._pressed_normal_key)
+ def _scan_enabled(self, client, connection_id, entry, args):
+ self._enable_scanning()
+
def _colors_changed(self, client, connection_id, entry, args):
self._update_key_style()
@@ -543,6 +760,8 @@ class CaribouKeyboard(gtk.Notebook):
def show_all(self):
self.set_current_page(self.current_page)
gtk.Notebook.show_all(self)
+ if self.scan_enabled:
+ self.scan_service.start()
def is_preferences_open(self):
if self.keyboard_preferences.window.window and \
@@ -554,7 +773,24 @@ class CaribouKeyboard(gtk.Notebook):
def _pressed_preferences_key(self, key):
self.keyboard_preferences.window.show_all()
+ def _enable_scanning(self):
+ enable = self.client.get_bool(const.CARIBOU_GCONF + '/scan_enabled')
+ if enable:
+ current_layout = self.get_nth_page(self.current_page)
+ if current_layout and not self.scan_enabled:
+ self.scan_service = scan.Scan_service(current_layout.rows,
+ self.get_parent().get_parent())
+ self.scan_enabled = True
+ elif self.scan_enabled:
+ self.scan_service.destroy()
+ self.scan_service = None
+ self.scan_enabled = False
+ else:
+ self.scan_enabled = False
+
def destroy(self):
+ if self.scan_enabled:
+ self.scan_service.destroy()
for id in self._gconf_connections:
self.client.notify_remove(id)
super(gtk.Notebook, self).destroy()
@@ -565,4 +801,7 @@ class CaribouKeyboard(gtk.Notebook):
if self.get_nth_page(i).layout_name == name:
self.set_current_page(i)
self.current_page = i
+ if self.scan_enabled:
+ self.scan_service.change_keyboard(
+ self.get_nth_page(i).rows)
break
diff --git a/caribou/ui/main.py b/caribou/ui/main.py
index 0f99398..013cabf 100644
--- a/caribou/ui/main.py
+++ b/caribou/ui/main.py
@@ -131,9 +131,10 @@ class Caribou:
if debug == True:
print "leave entry widget in", event.host_application.name
else:
- print _("WARNING - Caribou: unhandled editable widget:"), event.source
+ if debug == True:
+ print _("WARNING - Caribou: unhandled editable widget:"), event.source
- # Firefox does report leave entry widget events.
+ # Firefox does not report leave entry widget events.
# This could be a way to get the entry widget leave events.
#else:
# if event.detail1 == 1:
@@ -180,3 +181,5 @@ class Caribou:
if debug == True:
print "deregisterKeystrokeListener"
gtk.main_quit()
+
+
diff --git a/caribou/ui/scan.py b/caribou/ui/scan.py
new file mode 100644
index 0000000..0964af1
--- /dev/null
+++ b/caribou/ui/scan.py
@@ -0,0 +1,438 @@
+import gobject
+import pyatspi
+import gtk
+import caribou.common.const as const
+import gconf
+
+class Scan_service():
+ def __init__(self, keyboard, root_window):
+ self.keyboard = keyboard
+ self.root_window = root_window
+ self.selected_row = None
+ self.selected_button = None
+ self.button_index = 0
+ self.row_index = 0
+ self.index_i = 0
+ self.index_j = 0
+ self.is_stop = True
+ self.timerid = None
+ self.reverse = False
+ self.selected_block = []
+ self.client = gconf.client_get_default()
+ self._gconf_connections = []
+ self._gconf_connections.append(self.client.notify_add(
+ const.CARIBOU_GCONF + "/scanning_type",
+ self._on_scanning_type_changed))
+ self._gconf_connections.append(self.client.notify_add(
+ const.CARIBOU_GCONF + "/step_time",
+ self._on_scanning_type_changed))
+ self._gconf_connections.append(self.client.notify_add(
+ const.CARIBOU_GCONF + "/reverse_scanning",
+ self._on_scanning_type_changed))
+ self._gconf_connections.append(self.client.notify_add(
+ const.CARIBOU_GCONF + "/switch_type",
+ self._on_switch_changed))
+ self._gconf_connections.append(self.client.notify_add(
+ const.CARIBOU_GCONF + "/mouse_button",
+ self._on_switch_changed))
+ self._gconf_connections.append(self.client.notify_add(
+ const.CARIBOU_GCONF + "/keyboard_key",
+ self._on_switch_changed))
+
+ self._gconf_connections.append(self.client.notify_add(
+ const.CARIBOU_GCONF + "/default_colors",
+ self._on_color_changed))
+ self._gconf_connections.append(self.client.notify_add(
+ const.CARIBOU_GCONF + "/normal_color",
+ self._on_color_changed))
+ self._gconf_connections.append(self.client.notify_add(
+ const.CARIBOU_GCONF + "/mouse_over_color",
+ self._on_color_changed))
+ self._gconf_connections.append(self.client.notify_add(
+ const.CARIBOU_GCONF + "/row_scanning_color",
+ self._on_color_changed))
+ self._gconf_connections.append(self.client.notify_add(
+ const.CARIBOU_GCONF + "/button_scanning_color",
+ self._on_color_changed))
+ self._gconf_connections.append(self.client.notify_add(
+ const.CARIBOU_GCONF + "/cancel_scanning_color",
+ self._on_color_changed))
+ self._gconf_connections.append(self.client.notify_add(
+ const.CARIBOU_GCONF + "/block_scanning_color",
+ self._on_color_changed))
+ self._configure_scanning()
+ self._set_colors()
+ self._configure_switch()
+
+ def destroy(self):
+ self.stop()
+ self.clean()
+ self._deregister_events()
+ for id in self._gconf_connections:
+ self.client.notify_remove(id)
+
+
+
+ def _configure_switch(self):
+ self.switch_type = self.client.get_string(const.CARIBOU_GCONF +
+ "/switch_type") or "mouse"
+ if self.switch_type == const.MOUSE_SWITCH_TYPE:
+ self.switch_key = self.client.get_string(const.CARIBOU_GCONF +
+ "/mouse_button") or "2"
+ elif self.switch_type == const.KEYBOARD_SWITCH_TYPE:
+ self.switch_key = self.client.get_string(const.CARIBOU_GCONF +
+ "/keyboard_key") or "Shift_L"
+ try:
+ pyatspi.Registry.registerKeystrokeListener(self._on_key_pressed,
+ mask=None, kind=(pyatspi.KEY_PRESSED_EVENT,))
+ pyatspi.Registry.registerKeystrokeListener(self._on_key_released,
+ mask=None, kind=(pyatspi.KEY_RELEASED_EVENT,))
+ except:
+ print "Error while registering keyboard events in scan.py"
+
+ def _deregister_events(self):
+ try:
+ pyatspi.Registry.deregisterKeystrokeListener(self._on_key_pressed,
+ mask=None, kind=(pyatspi.KEY_PRESSED_EVENT,))
+ pyatspi.Registry.deregisterKeystrokeListener(
+ self._on_key_released,
+ mask=None, kind=(pyatspi.KEY_RELEASED_EVENT,))
+ except:
+ print "Error while deregistering keyboard events in scan.py"
+
+ def _on_switch_changed(self, client, connection_id, entry, args):
+ self._deregister_events()
+ self._configure_switch()
+
+ def _on_color_changed(self, client, connection_id, entry, args):
+ self._set_colors()
+
+ def _on_scanning_type_changed(self, client, connection_id, entry, args):
+ self._configure_scanning()
+
+ def _configure_scanning(self):
+ if not self.is_stop:
+ self._stop()
+ self.scanning_type = self.client.get_string(const.CARIBOU_GCONF +
+ "/scanning_type") or "0"
+ self.reverse = self.client.get_bool(const.CARIBOU_GCONF +
+ "/reverse_scanning") or False
+ self.step_time = self.client.get_int(const.CARIBOU_GCONF +
+ "/step_time") or 1000
+ if self.scanning_type == const.BLOCK:
+ self.selected_block = []
+ else:
+ self.selected_block = self.keyboard
+ self.scanning = self.scanning_type
+
+ def _set_colors(self):
+ self.default_colors = self.client.get_bool(
+ const.CARIBOU_GCONF + "/default_colors") \
+ or True
+ self.normal_color = self.client.get_string(
+ const.CARIBOU_GCONF + "/normal_color") \
+ or "gray80"
+ self.mouse_over_color = self.client.get_string(
+ const.CARIBOU_GCONF + "/mouse_over_color") \
+ or "yellow"
+
+ self.row_scanning_color = self.client.get_string(
+ const.CARIBOU_GCONF + "/row_scanning_color") \
+ or "green"
+ self.button_scanning_color = self.client.get_string(
+ const.CARIBOU_GCONF + "/button_scanning_color") \
+ or "cyan"
+ self.cancel_scanning_color = self.client.get_string(
+ const.CARIBOU_GCONF + "/cancel_scanning_color") \
+ or "red"
+ self.block_scanning_color = self.client.get_string(
+ const.CARIBOU_GCONF + "/block_scanning_color") \
+ or "purple"
+
+
+ # public start
+ def start(self, scanning=None):
+ self.scanning = scanning or self.scanning_type
+ self.clean()
+ if self.root_window and \
+ self.switch_type == const.MOUSE_SWITCH_TYPE:
+ self._grab_mouse_events()
+
+ if not self.reverse:
+ self.reset(self.scanning)
+
+ # public stop
+ def stop(self):
+ if self.switch_type == const.MOUSE_SWITCH_TYPE:
+ self._ungrab_mouse_events()
+ self.clean()
+ self._stop()
+
+ #private start
+ def _start(self, scanning=const.ROW):
+ if self.is_stop == True and self.timerid == None:
+ self.is_stop = False
+ self.button_index = -1
+ self.row_index = -1
+ if scanning == const.ROW:
+ self.selected_row = []
+ self.timerid = gobject.timeout_add(self.step_time, self._scan_row)
+ elif scanning == const.BUTTON:
+ self.selected_button = None
+ self.timerid = gobject.timeout_add(self.step_time, self._scan_button)
+ elif scanning == const.BLOCK:
+ self.selected_block = []
+ self.selected_row = []
+ self.clean()
+ self.index_i = 2
+ self.index_j = 1
+ self.timerid = gobject.timeout_add(self.step_time, self._scan_block)
+
+ # private stop
+ def _stop(self):
+ self.is_stop = True
+ if self.timerid:
+ gobject.source_remove(self.timerid)
+ self.timerid = None
+
+ def reset(self, scanning=const.ROW):
+ self._stop()
+ self._start(scanning)
+
+ def clean(self):
+ for row in self.keyboard:
+ for button in row:
+ self.select_button(button, False)
+
+
+ def change_keyboard(self, keyboard):
+ if not self.is_stop:
+ self._stop()
+ self.keyboard = keyboard
+ self.scanning = self.scanning_type
+ self.start(self.scanning_type)
+ if self.scanning == const.ROW:
+ self.selected_block = keyboard
+
+
+ def _grab_mouse_events(self):
+ gtk.gdk.event_handler_set(self._mouse_handler)
+
+ def _ungrab_mouse_events(self):
+ gtk.gdk.event_handler_set(gtk.main_do_event)
+
+ def _mouse_handler(self, event):
+ if self.root_window.window.is_visible():
+ if event.type == gtk.gdk.BUTTON_PRESS and \
+ str(event.button) == self.switch_key:
+ self._handle_press()
+ elif event.type == gtk.gdk.BUTTON_RELEASE and \
+ str(event.button) == self.switch_key:
+ self._handle_release()
+ elif not event.type == gtk.gdk.ENTER_NOTIFY:
+ gtk.main_do_event(event)
+ else:
+ gtk.main_do_event(event)
+
+ def _scan_block(self):
+ if self.is_stop:
+ return False
+ # Clean the previous block
+ self.select_block(self.selected_block, False)
+ # Update indexes, three horizontal blocks, and two vertical
+ if self.index_j < 2:
+ self.index_j += 1
+ elif self.index_i < 1:
+ self.index_i += 1
+ self.index_j = 0
+ else:
+ self.index_j = 0
+ self.index_i = 0
+
+ self.selected_block = []
+ width = self.root_window.size_request()[0]
+ height = self.root_window.size_request()[1]
+ root_x = self.root_window.get_position()[0]
+ root_y = self.root_window.get_position()[1]
+ offset_w = self.index_j*(width/3)
+ offset_h = self.index_i*(height/2)
+
+ block_window = gtk.gdk.Rectangle(root_x + offset_w,
+ root_y + offset_h,
+ width/3,
+ height/2)
+ empty_r = gtk.gdk.Rectangle()
+ try:
+ for row in self.keyboard:
+ line = []
+ for button in row:
+ abs_b_x = button.get_allocation()[0] + \
+ button.window.get_position()[0]
+ abs_b_y = button.get_allocation()[1] + \
+ button.window.get_position()[1]
+ abs_b_r = gtk.gdk.Rectangle(abs_b_x,
+ abs_b_y,
+ button.size_request()[0],
+ button.size_request()[1])
+
+ # If button rectangle is inside the block:
+ intersect = block_window.intersect(abs_b_r)
+ # If the intersected rectangle != empty
+ if intersect != empty_r:
+ # If the witdth of intersection is bigger than half
+ # of button width and height, we append button to line
+ if (intersect.width > (abs_b_r.width / 2)) and \
+ (intersect.height > (abs_b_r.height / 2)):
+ line.append(button)
+
+
+ if len(line) > 0:
+ self.selected_block.append(line)
+
+ except Exception as e:
+ self.is_stop = True
+ return False
+
+ self.select_block(self.selected_block, True,
+ self.block_scanning_color)
+ return True
+
+
+
+ def _scan_row(self):
+ if self.is_stop:
+ return False
+
+ else:
+ self.select_row(self.selected_row,
+ self.scanning_type == const.BLOCK,
+ self.block_scanning_color)
+ self.row_index += 1
+ if self.row_index >= len(self.selected_block):
+ self.row_index = 0
+ self.selected_row = self.selected_block[self.row_index]
+ self.select_row(self.selected_row, True, self.row_scanning_color)
+ return True
+
+ def _scan_button(self):
+ if self.scanning == const.CANCEL:
+ self.scanning = const.BUTTON
+ self.selected_button = None
+ self.select_row(self.selected_row, True, self.row_scanning_color)
+ return True
+ else:
+ if self.selected_button and self.selected_button in self.selected_row:
+ self.select_button(self.selected_button, True, self.row_scanning_color)
+
+ if self.is_stop:
+ return False
+
+ self.button_index += 1
+ if self.button_index >= len(self.selected_row):
+ self.select_row(self.selected_row, True, self.cancel_scanning_color)
+ self.button_index = -1
+ self.scanning = const.CANCEL
+ return True
+
+ self.selected_button = self.selected_row[self.button_index]
+ while self.selected_button.key_type == const.DUMMY_KEY_TYPE:
+ self.button_index += 1
+ if self.button_index >= len(self.selected_row):
+ self.select_row(self.selected_row, True, self.cancel_scanning_color)
+ self.button_index = -1
+ self.scanning = const.CANCEL
+ return True
+
+ self.selected_button = self.selected_row[self.button_index]
+ self.select_button(self.selected_button, True, self.button_scanning_color)
+ return True
+
+ def select_block(self, block, state, color=None):
+ for row in block:
+ self.select_row(row, state, color)
+
+ def select_row(self, row, state, color=None):
+ for button in row:
+ self.select_button(button, state, color)
+
+ def select_button(self, button, state, color=None):
+ if state:
+ button.set_color(color, self.mouse_over_color)
+ elif self.default_colors:
+ button.reset_color()
+ else:
+ button.set_color(self.normal_color, self.mouse_over_color)
+
+
+ def _on_key_pressed(self, event):
+ if event.event_string == "Escape":
+ self.stop()
+ elif self.switch_type == const.KEYBOARD_SWITCH_TYPE and \
+ self.switch_key == event.event_string:
+ self._handle_press()
+
+ def _on_key_released(self, event):
+ if self.switch_type == const.KEYBOARD_SWITCH_TYPE and \
+ self.switch_key == event.event_string:
+ self._handle_release()
+ elif event.event_string != "Escape":
+ self._stop()
+ self.start()
+
+ def _handle_press(self):
+ if self.reverse:
+ self._start(self.scanning)
+
+ def _handle_release(self):
+ if self.reverse:
+ if not self.is_stop:
+ if self.scanning == const.ROW and \
+ len(self.selected_row) > 0:
+ self.scanning = const.BUTTON
+ elif self.scanning == const.BLOCK and \
+ len(self.selected_block) > 0:
+ self.scanning = const.ROW
+ elif self.scanning == const.BUTTON and \
+ self.selected_button:
+ self.clean()
+ if self.selected_button.key_type == const.PREFERENCES_KEY_TYPE:
+ self.stop()
+ self.selected_button.clicked()
+ self.selected_button = None
+ self.scanning = self.scanning_type
+ self.reset()
+
+ elif self.scanning == const.CANCEL:
+ self.clean()
+ self.scanning = self.scanning_type
+ self._stop()
+
+ else:
+ if not self.is_stop:
+ if self.scanning == const.ROW and \
+ len(self.selected_row) > 0:
+ self.scanning = const.BUTTON
+ self.reset(const.BUTTON)
+
+ elif self.scanning == const.BLOCK and \
+ len(self.selected_block) > 0:
+ self.scanning = const.ROW
+ self.reset(const.ROW)
+ elif self.scanning == const.BUTTON and \
+ self.selected_button:
+ self.selected_button.clicked()
+ self.scanning = const.ROW
+ if self.selected_button.key_type \
+ == const.PREFERENCES_KEY_TYPE:
+ self.selected_button = None
+ self.stop()
+ else:
+ self.selected_button = None
+ self.scanning = self.scanning_type
+
+ elif self.scanning == const.CANCEL:
+ self.scanning = self.scanning_type
+ self.clean()
+ self.reset(self.scanning_type)
+
+
diff --git a/caribou/ui/window.py b/caribou/ui/window.py
index 08d3e2f..0ed5c90 100644
--- a/caribou/ui/window.py
+++ b/caribou/ui/window.py
@@ -59,6 +59,11 @@ class CaribouWindow(gtk.Window):
self.connect('show', self._on_window_show)
+ def destroy(self):
+ self.keyboard.destroy()
+ super(gtk.Window, self).destroy()
+
+
def set_cursor_location(self, cursor_location):
self._cursor_location = cursor_location
self._update_position()
@@ -225,6 +230,7 @@ class CaribouWindowEntry(CaribouWindow):
CaribouWindow.__init__(self, text_entry_mech, placement, min_alpha=0.075,
max_alpha=0.8)
+
def _calculate_axis(self, axis_placement, root_bbox):
offset = CaribouWindow._calculate_axis(self, axis_placement, root_bbox)
diff --git a/data/caribou-prefs.ui b/data/caribou-prefs.ui
index 97fcec0..bdc75e9 100644
--- a/data/caribou-prefs.ui
+++ b/data/caribou-prefs.ui
@@ -322,10 +322,290 @@
</packing>
</child>
<child>
- <placeholder/>
+ <object class="GtkHBox" id="hbox4">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkTable" id="table3">
+ <property name="visible">True</property>
+ <property name="n_rows">10</property>
+ <property name="n_columns">2</property>
+ <child>
+ <object class="GtkCheckButton" id="scan_enabled_checkbox">
+ <property name="label" translatable="yes">_Scan enabled</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="right_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="reverse_scanning_checkbox">
+ <property name="label" translatable="yes">Re_verse scanning</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label11">
+ <property name="visible">True</property>
+ <property name="xalign">0.05000000074505806</property>
+ <property name="label" translatable="yes">Ste_p time:</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="top_attach">9</property>
+ <property name="bottom_attach">10</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="step_time_spin">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">&#x25CF;</property>
+ <property name="adjustment">adjustment1</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">9</property>
+ <property name="bottom_attach">10</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="keyboard_switch_radio">
+ <property name="label" translatable="yes">_Keyboard switch</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">mouse_switch_radio</property>
+ </object>
+ <packing>
+ <property name="top_attach">8</property>
+ <property name="bottom_attach">9</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="keyboard_key_combo">
+ <property name="visible">True</property>
+ <property name="model">liststore4</property>
+ <child>
+ <object class="GtkCellRendererCombo" id="cellrenderertext4"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">8</property>
+ <property name="bottom_attach">9</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="mouse_button_combo">
+ <property name="visible">True</property>
+ <property name="model">liststore3</property>
+ <child>
+ <object class="GtkCellRendererCombo" id="cellrenderertext3"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">7</property>
+ <property name="bottom_attach">8</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="mouse_switch_radio">
+ <property name="label" translatable="yes">_Mouse switch</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="top_attach">7</property>
+ <property name="bottom_attach">8</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="scanning_type_combo">
+ <property name="visible">True</property>
+ <property name="model">liststore2</property>
+ <child>
+ <object class="GtkCellRendererCombo" id="cellrenderertext2"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">6</property>
+ <property name="bottom_attach">7</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label10">
+ <property name="visible">True</property>
+ <property name="xalign">0.05000000074505806</property>
+ <property name="label" translatable="yes">Scanning _type: </property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="top_attach">6</property>
+ <property name="bottom_attach">7</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkColorButton" id="cancel_scanning_color_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="color">#000000000000</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">5</property>
+ <property name="bottom_attach">6</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label9">
+ <property name="visible">True</property>
+ <property name="xalign">0.05000000074505806</property>
+ <property name="label" translatable="yes">_Cancel color: </property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="top_attach">5</property>
+ <property name="bottom_attach">6</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkColorButton" id="button_scanning_color_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="color">#000000000000</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label8">
+ <property name="visible">True</property>
+ <property name="xalign">0.05000000074505806</property>
+ <property name="label" translatable="yes">_Button color: </property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkColorButton" id="row_scanning_color_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="color">#000000000000</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label6">
+ <property name="visible">True</property>
+ <property name="xalign">0.05000000074505806</property>
+ <property name="label" translatable="yes">_Row color: </property>
+ <property name="use_underline">True</property>
+ <property name="ellipsize">start</property>
+ </object>
+ <packing>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label12">
+ <property name="visible">True</property>
+ <property name="xalign">0.05000000074505806</property>
+ <property name="label" translatable="yes">B_lock color: </property>
+ <property name="use_underline">True</property>
+ <property name="ellipsize">start</property>
+ </object>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkColorButton" id="block_scanning_color_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="color">#000000000000</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">3</property>
+ </packing>
</child>
<child type="tab">
- <placeholder/>
+ <object class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Scanning</property>
+ </object>
+ <packing>
+ <property name="position">3</property>
+ <property name="tab_fill">False</property>
+ </packing>
</child>
</object>
<packing>
@@ -368,4 +648,29 @@
<action-widget response="0">button_close</action-widget>
</action-widgets>
</object>
+ <object class="GtkListStore" id="liststore2">
+ <columns>
+ <!-- column-name gchararray1 -->
+ <column type="gchararray"/>
+ </columns>
+ </object>
+ <object class="GtkListStore" id="liststore3">
+ <columns>
+ <!-- column-name gchararray1 -->
+ <column type="gchararray"/>
+ </columns>
+ </object>
+ <object class="GtkListStore" id="liststore4">
+ <columns>
+ <!-- column-name gchararray1 -->
+ <column type="gchararray"/>
+ </columns>
+ </object>
+ <object class="GtkAdjustment" id="adjustment1">
+ <property name="value">1000</property>
+ <property name="lower">100</property>
+ <property name="upper">10000</property>
+ <property name="step_increment">10</property>
+ <property name="page_increment">100</property>
+ </object>
</interface>