1namespace Caribou { 2 /** 3 * Object providing access to keyboard in scanning mode. 4 */ 5 public class Scanner : Object { 6 public bool bind_settings { get; construct; default=true; } 7 8 private ScanGrouping _scan_grouping; 9 public int scan_grouping { 10 get { 11 return (int) _scan_grouping; 12 } 13 14 set construct { 15 _scan_grouping = (ScanGrouping) value; 16 if (root_group != null) 17 root_group.scan_grouping = _scan_grouping; 18 reset (); 19 } 20 } 21 22 private bool _scan_enabled; 23 public bool scan_enabled { 24 get { return _scan_enabled; } 25 set construct { 26 _scan_enabled = value; 27 if (_scan_enabled) 28 enable (); 29 else 30 disable (); 31 } 32 } 33 34 private double _step_time; 35 public double step_time { 36 get { return _step_time; } 37 set construct { 38 _step_time = value; 39 if (scan_tid != 0) { 40 GLib.Source.remove (scan_tid); 41 scan_tid = GLib.Timeout.add ((int) (_step_time*1000), scan); 42 } 43 } 44 } 45 46 private string _switch_device; 47 public string switch_device { 48 get { return _switch_device; } 49 set construct { 50 _switch_device = value; 51 configure_switch (); 52 } 53 } 54 55 private string _keyboard_key; 56 public string keyboard_key { 57 get { return _keyboard_key; } 58 set construct { 59 _keyboard_key = value; 60 configure_switch (); 61 } 62 } 63 64 private int _mouse_button; 65 public int mouse_button { 66 get { return _mouse_button; } 67 set construct { 68 _mouse_button = value; 69 configure_switch (); 70 } 71 } 72 73 public int scan_cycles { get; set construct; default=1; } 74 public bool autorestart { get; set construct; default=false; } 75 public bool inverse_scanning { get; set construct; default=false; } 76 77 private delegate void UnconfigureSwitchFunc(); 78 private UnconfigureSwitchFunc unconfigure_switch_func; 79 80 private uint scan_tid; 81 private KeyboardModel keyboard; 82 private IScannableGroup root_group; 83 private bool started; 84 85 construct { 86 /* defaults */ 87 _scan_grouping = ScanGrouping.SUBGROUPS; 88 _step_time = 1.0; 89 _switch_device = "keyboard"; 90 91 if (bind_settings) 92 do_bind_settings (); 93 } 94 95 private void do_bind_settings () { 96 Settings caribou_settings = new Settings ("org.gnome.caribou"); 97 string[] settings = {"scan-grouping", "step-time", "scan-cycles", 98 "autorestart", "inverse-scanning", "switch-device", 99 "keyboard-key", "mouse-button", "scan-enabled"}; 100 101 foreach (string setting in settings) { 102 caribou_settings.bind (setting, this, setting, SettingsBindFlags.GET); 103 } 104 } 105 106 private bool select () { 107 IScannableItem? item = root_group.child_select (); 108 109 if (item is IScannableGroup) { 110 step (); 111 return true; 112 } else { 113 reset (); 114 return false; 115 } 116 } 117 118 private void switch_pressed (uint code, bool pressed) { 119 if (pressed) { 120 if (!started) { 121 step (); 122 start (); 123 return; 124 } 125 126 stop (); 127 128 if (inverse_scanning) { 129 step (); 130 start (); 131 } else { 132 if (select () || autorestart) 133 start (); 134 } 135 } 136 } 137 138 public void set_keyboard (KeyboardModel keyboard) { 139 GroupModel group = keyboard.get_group(keyboard.active_group); 140 this.keyboard = keyboard; 141 this.keyboard.notify["active-group"].connect(on_group_changed); 142 set_active_level (group.get_level (group.active_level)); 143 144 foreach (string group_name in keyboard.get_groups()) { 145 group = keyboard.get_group(group_name); 146 group.notify["active-level"].connect(on_level_changed); 147 } 148 } 149 150 private void on_level_changed (Object obj, ParamSpec prop) { 151 GroupModel group = (GroupModel) obj; 152 set_active_level (group.get_level (group.active_level)); 153 } 154 155 private void on_group_changed (Object obj, ParamSpec prop) { 156 GroupModel group = keyboard.get_group(keyboard.active_group); 157 set_active_level (group.get_level (group.active_level)); 158 } 159 160 private void set_active_level (LevelModel level) { 161 root_group = (IScannableGroup) level; 162 root_group.scan_grouping = _scan_grouping; 163 } 164 165 public void reset () { 166 if (root_group != null) 167 root_group.scan_reset (); 168 } 169 170 private void enable () { 171 configure_switch (); 172 } 173 174 private void disable () { 175 unconfigure_switch (); 176 } 177 178 private void start () { 179 if (started || root_group == null) 180 return; 181 182 started = true; 183 184 scan_tid = GLib.Timeout.add((int) (_step_time*1000), scan); 185 } 186 187 private void stop () { 188 if (!started) 189 return; 190 191 started = false; 192 if (scan_tid != 0) 193 GLib.Source.remove (scan_tid); 194 scan_tid = 0; 195 } 196 197 private IScannableItem? step () { 198 IScannableItem item = root_group.child_step (scan_cycles); 199 200 if (item == null) { 201 reset (); 202 } 203 204 return item; 205 } 206 207 private bool scan () { 208 if (inverse_scanning) 209 select (); 210 else 211 return (step () != null); 212 213 return true; 214 } 215 216 private void unconfigure_switch () { 217 if (unconfigure_switch_func != null) 218 unconfigure_switch_func (); 219 unconfigure_switch_func = null; 220 } 221 222 private void configure_switch () { 223 if (!scan_enabled) 224 return; 225 226 unconfigure_switch (); 227 228 DisplayAdapter xadapter = DisplayAdapter.get_default(); 229 if (switch_device == "keyboard" && keyboard_key != null) { 230 uint keyval = Gdk.keyval_from_name (keyboard_key); 231 xadapter.register_key_func (keyval, switch_pressed); 232 unconfigure_switch_func = () => { 233 xadapter.register_key_func (keyval, null); 234 }; 235 } else if (switch_device == "mouse" && mouse_button != 0) { 236 xadapter.register_button_func (mouse_button, switch_pressed); 237 unconfigure_switch_func = () => { 238 xadapter.register_key_func (mouse_button, null); 239 }; 240 } 241 } 242 } 243}