1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99

use gtk::prelude::*;
use gdk;
use gdk::EventKey;
use phf;
use neovim_lib::{Neovim, NeovimApi};

include!(concat!(env!("OUT_DIR"), "/key_map_table.rs"));


pub fn keyval_to_input_string(in_str: &str, in_state: gdk::ModifierType) -> String {
    let mut val = in_str;
    let mut state = in_state;
    let mut input = String::new();

    debug!("keyval -> {}", in_str);

    // CTRL-^ and CTRL-@ don't work in the normal way.
    if state.contains(gdk::ModifierType::CONTROL_MASK) && !state.contains(gdk::ModifierType::SHIFT_MASK) &&
        !state.contains(gdk::ModifierType::MOD1_MASK)
    {
        if val == "6" {
            val = "^";
        } else if val == "2" {
            val = "@";
        }
    }

    let chars: Vec<char> = in_str.chars().collect();

    if chars.len() == 1 {
        let ch = chars[0];

        // Remove SHIFT
        if ch.is_ascii() && !ch.is_alphanumeric() {
            state.remove(gdk::ModifierType::SHIFT_MASK);
        }
    }

    if val == "<" {
        val = "lt";
    }

    if state.contains(gdk::ModifierType::SHIFT_MASK) {
        input.push_str("S-");
    }
    if state.contains(gdk::ModifierType::CONTROL_MASK) {
        input.push_str("C-");
    }
    if state.contains(gdk::ModifierType::MOD1_MASK) {
        input.push_str("A-");
    }

    input.push_str(val);

    if input.chars().count() > 1 {
        format!("<{}>", input)
    } else {
        input
    }
}

pub fn convert_key(ev: &EventKey) -> Option<String> {
    let keyval = ev.get_keyval();
    let state = ev.get_state();
    if let Some(ref keyval_name) = gdk::keyval_name(keyval) {
        if let Some(cnvt) = KEYVAL_MAP.get(keyval_name as &str).cloned() {
            return Some(keyval_to_input_string(cnvt, state));
        }
    }

    if let Some(ch) = gdk::keyval_to_unicode(keyval) {
        Some(keyval_to_input_string(&ch.to_string(), state))
    } else {
        None
    }
}

pub fn im_input(nvim: &mut Neovim, input: &str) {
    debug!("nvim_input -> {}", input);

    let input: String = input
        .chars()
        .map(|ch| {
            keyval_to_input_string(&ch.to_string(), gdk::ModifierType::empty())
        })
        .collect();
    nvim.input(&input).expect("Error run input command to nvim");
}

pub fn gtk_key_press(nvim: &mut Neovim, ev: &EventKey) -> Inhibit {
    if let Some(input) = convert_key(ev) {
        debug!("nvim_input -> {}", input);
        nvim.input(&input).expect("Error run input command to nvim");
        Inhibit(true)
    } else {
        Inhibit(false)
    }
}