Complete basic remap implementation

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

@ -2,10 +2,13 @@ current_dir := $(shell pwd)
CSRCS := $(wildcard tools/xkremap/*.[ch])
MRBSRCS := $(wildcard mrblib/xkremap/*.rb)
MRBCSRCS := $(wildcard src/*.[ch])
.PHONY: all
.PHONY: all clean
all: xkremap
clean:
rm -rf mruby/build/host
xkremap: mruby/build/host/bin/xkremap
cp mruby/build/host/bin/xkremap xkremap

@ -5,4 +5,7 @@ MRuby::Gem::Specification.new('xkremap') do |spec|
spec.bins = ['xkremap']
spec.add_dependency 'mruby-eval', core: 'mruby-eval'
spec.add_dependency 'mruby-io', mgem: 'mruby-io'
spec.add_dependency 'mruby-onig-regexp', mgem: 'mruby-onig-regexp'
end

@ -1,16 +1,24 @@
module Xkremap
class Config
# @param [String] dsl
def self.load(dsl)
# @param [String] filename
def self.load(filename)
unless File.exist?(filename)
raise "Config file does not exist!: #{filename.inspect}"
exit 1
end
config = self.new
ConfigContext.new(config).instance_eval(dsl)
ConfigDSL.new(config).instance_eval(File.read(filename))
config
end
attr_reader :remaps
def initialize
@remaps = []
end
attr_reader :remaps
Key = Struct.new(:keysym, :modifier)
Remap = Struct.new(:from_key, :to_keys)
end
end

@ -1,8 +0,0 @@
module Xkremap
class ConfigContext
# @param [Xkremap::Config] config
def initialize(config)
@config = config
end
end
end

@ -0,0 +1,22 @@
module Xkremap
class ConfigDSL
# @param [Xkremap::Config] config
def initialize(config)
@config = config
end
def remap(from_str, options = {})
to_strs = Array(options.fetch(:to))
@config.remaps << Config::Remap.new(
compile_exp(from_str),
to_strs.map { |str| compile_exp(str) }
)
end
private
def compile_exp(str)
KeyExpression.compile(str)
end
end
end

@ -4,7 +4,7 @@ module Xkremap
# @param [Xkremap::Display] display
def initialize(config, display)
@active_window = ActiveWindow.new(display)
@grab_manager = GrabManager.new(display)
@grab_manager = GrabManager.new(config, display)
@key_remap_compiler = KeyRemapCompiler.new(config, display)
remap_keys
end

@ -1,13 +1,18 @@
module Xkremap
class GrabManager
# @param [Xkremap::Config] config
# @param [Xkremap::Display] display
def initialize(display)
def initialize(config, display)
@config = config
@display = display
end
def grab_keys
XlibWrapper.ungrab_keys(@display)
XlibWrapper.grab_key(@display, 0x0062, 1<<2) # C-b
@config.remaps.each do |remap|
from = remap.from_key
XlibWrapper.grab_key(@display, from.keysym, from.modifier)
end
end
end
end

@ -0,0 +1,40 @@
module Xkremap
module KeyExpression
class << self
# @param [String] exp
# @return [Xkremap::Config::Key] key
def compile(exp)
case exp
when /\A(?<keyexp>[^-]+)\z/
Config::Key.new(to_keysym(Regexp.last_match[:keyexp]), X11::NoModifier)
when /\AC-(?<keyexp>[^-]+)\z/
Config::Key.new(to_keysym(Regexp.last_match[:keyexp]), X11::ControlMask)
when /\A(M|Alt)-(?<keyexp>[^-]+)\z/
Config::Key.new(to_keysym(Regexp.last_match[:keyexp]), X11::Mod1Mask)
else
raise "unexpected key expression pattern!: #{exp.inspect}"
end
end
private
def to_keysym(keyexp)
X11.const_get(x11_const_name(keyexp))
end
def x11_const_name(keyexp)
if keyexp.length == 1
"XK_#{keyexp.downcase}"
else
"XK_#{capitalize(keyexp)}"
end
end
def capitalize(str)
result = str.downcase
result[0] = str[0].upcase
result
end
end
end
end

@ -3,6 +3,7 @@ module Xkremap
def initialize(config, display)
@config = config
@display = display
puts "Config loaded: #{@config.inspect}"
end
# @return [Hash] : keycode(Fixnum) -> state(Fixnum) -> handler(Proc)
@ -17,9 +18,15 @@ module Xkremap
def set_handlers(result)
display = @display
# C-b -> Left
result[to_keycode(X11::XK_b)][X11::ControlMask] = Proc.new do
XlibWrapper.input_key(display, X11::XK_Left, X11::NoModifier)
@config.remaps.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)
end
end
end
end

@ -3,47 +3,15 @@
#include <string.h>
#include <mruby.h>
FILE*
open_file(char *filename)
{
if (!strcmp(filename, "-"))
return stdin;
FILE *file = fopen(filename, "r");
if (!file) {
fprintf(stderr, "Failed to open: '%s'\n", filename);
exit(1);
}
return file;
}
char*
read_file(char *filename)
{
FILE *fp = open_file(filename);
fseek(fp, 0L, SEEK_END);
long size = ftell(fp);
rewind(fp);
char *ret = malloc(size * sizeof(char));
fread(ret, sizeof(char), size, fp);
fclose(fp);
return ret;
}
mrb_value
load_config(mrb_state *mrb, char *filename)
{
char *dsl = read_file(filename);
struct RClass *mXkremap = mrb_module_get(mrb, "Xkremap");
struct RClass *cConfig = mrb_class_get_under(mrb, mXkremap, "Config");
mrb_value config = mrb_funcall(mrb, mrb_obj_value(cConfig), "load", 1, mrb_str_new_cstr(mrb, dsl));
mrb_value config = mrb_funcall(mrb, mrb_obj_value(cConfig), "load", 1, mrb_str_new_cstr(mrb, filename));
if (mrb->exc) {
mrb_print_error(mrb);
}
free(dsl);
return config;
}

Loading…
Cancel
Save