Implement window-specific remaps

pull/1/head
Takashi Kokubun 8 years ago
parent adb27362c7
commit de6aab92fd

@ -1,5 +1,20 @@
module Xkremap
class Config
Key = Struct.new(:keysym, :modifier)
Remap = Struct.new(:from_key, :to_keys)
class Window < Struct.new(:class_only, :class_not)
def class_only
super ? Array(super) : []
end
def class_not
super ? Array(super) : []
end
end
AnyWindow = Window.new
# @param [String] filename
def self.load(filename)
unless File.exist?(filename)
@ -12,13 +27,29 @@ module Xkremap
config
end
attr_reader :remaps
attr_reader :remaps_by_window
def initialize
@remaps = []
@remaps_by_window = Hash.new { |h, k| h[k] = [] }
end
def remaps_for(display, window)
klass = XlibWrapper.fetch_window_class(display, window)
remaps_by_window[AnyWindow] + class_specific_remaps(klass)
end
Key = Struct.new(:keysym, :modifier)
Remap = Struct.new(:from_key, :to_keys)
private
def class_specific_remaps(klass)
@remaps_by_window.select do |window, _|
if !window.class_only.empty?
window.class_only.include?(klass)
elsif !window.class_not.empty?
!window.class_not.include?(klass)
else
false
end
end.map { |_, remaps| remaps }.flatten
end
end
end

@ -1,18 +1,24 @@
module Xkremap
class ConfigDSL
# @param [Xkremap::Config] config
def initialize(config)
def initialize(config, win = Config::AnyWindow)
@config = config
@window = win
end
def remap(from_str, options = {})
to_strs = Array(options.fetch(:to))
@config.remaps << Config::Remap.new(
@config.remaps_by_window[@window] << Config::Remap.new(
compile_exp(from_str),
to_strs.map { |str| compile_exp(str) }
)
end
def window(options = {}, &block)
win = Config::Window.new(options[:class_only], options[:class_not])
ConfigDSL.new(@config, win).instance_exec(&block)
end
private
def compile_exp(str)

@ -32,8 +32,9 @@ module Xkremap
private
def remap_keys
@key_press_handlers = @key_remap_compiler.compile
@grab_manager.grab_keys
window = @active_window.current_window
@key_press_handlers = @key_remap_compiler.compile_for(window)
@grab_manager.grab_keys_for(window)
puts 'remap keys!'
end
end

@ -7,9 +7,9 @@ module Xkremap
@display = display
end
def grab_keys
def grab_keys_for(window)
XlibWrapper.ungrab_keys(@display)
@config.remaps.each do |remap|
@config.remaps_for(@display, window).each do |remap|
from = remap.from_key
XlibWrapper.grab_key(@display, from.keysym, from.modifier)
end

@ -7,24 +7,22 @@ module Xkremap
end
# @return [Hash] : keycode(Fixnum) -> state(Fixnum) -> handler(Proc)
def compile
def compile_for(window)
result = Hash.new { |h, k| h[k] = {} }
set_handlers(result)
set_handlers_for(result, window)
result
end
private
def set_handlers(result)
display = @display
@config.remaps.each do |remap|
def set_handlers_for(result, window)
@config.remaps_for(@display, window).each do |remap|
from = remap.from_key
tos = remap.to_keys
result[to_keycode(from.keysym)][from.modifier] = Proc.new do
tos.each do |to|
XlibWrapper.input_key(display, to.keysym, to.modifier)
XlibWrapper.input_key(@display, to.keysym, to.modifier)
end
end
end

@ -1,9 +1,43 @@
#include <X11/Xatom.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include "mruby.h"
extern Display* extract_x_display(mrb_state *mrb, mrb_value display_obj);
mrb_value
mrb_xw_fetch_window_class(mrb_state *mrb, mrb_value self)
{
mrb_value display_obj;
mrb_int window;
mrb_get_args(mrb, "oi", &display_obj, &window);
Display *display = extract_x_display(mrb, display_obj);
Atom net_wm_name = XInternAtom(display, "WM_CLASS", True);
XTextProperty prop;
XGetTextProperty(display, window, &prop, net_wm_name);
mrb_value ret;
if (prop.nitems > 0 && prop.value) {
if (prop.encoding == XA_STRING) {
ret = mrb_str_new_cstr(mrb, (char *)prop.value);
} else {
char **l = NULL;
int count;
XmbTextPropertyToTextList(display, &prop, &l, &count);
if (count > 0 && *l) {
ret = mrb_str_new_cstr(mrb, *l);
} else {
ret = mrb_str_new_cstr(mrb, "");
}
XFreeStringList(l);
}
}
return ret;
}
Window
get_focused_window(Display *display)
{
@ -106,6 +140,7 @@ mrb_xkremap_xlib_wrapper_init(mrb_state *mrb, struct RClass *mXkremap)
mrb_define_class_method(mrb, cXlibWrapper, "input_key", mrb_xw_input_key, MRB_ARGS_REQ(3));
mrb_define_class_method(mrb, cXlibWrapper, "keysym_to_keycode", mrb_xw_keysym_to_keycode, MRB_ARGS_REQ(2));
mrb_define_class_method(mrb, cXlibWrapper, "fetch_active_window", mrb_xw_fetch_active_window, MRB_ARGS_REQ(1));
mrb_define_class_method(mrb, cXlibWrapper, "fetch_window_class", mrb_xw_fetch_window_class, MRB_ARGS_REQ(2));
mrb_define_class_method(mrb, cXlibWrapper, "grab_key", mrb_xw_grab_key, MRB_ARGS_REQ(3));
mrb_define_class_method(mrb, cXlibWrapper, "ungrab_keys", mrb_xw_ungrab_keys, MRB_ARGS_REQ(1));
}

Loading…
Cancel
Save