1stバージョン追加
@@ -0,0 +1,147 @@ | ||
1 | +#!/usr/bin/env ruby | |
2 | + | |
3 | +require 'optparse' | |
4 | +require File.join(File.dirname(__FILE__), 'keyboard_data') | |
5 | +require File.join(File.dirname(__FILE__), 'emacs_history') | |
6 | + | |
7 | +Version = "0.0.1" | |
8 | + | |
9 | +class EmacsKeybind | |
10 | + def initialize(keyboard, filter, history) | |
11 | + # キーバインドデータ | |
12 | + src = [] | |
13 | + | |
14 | + while line = gets | |
15 | + src << line.chomp.split(/\t+/) | |
16 | + end | |
17 | + | |
18 | + @keybind = src | |
19 | + | |
20 | + # キーボードデータ | |
21 | + @keyboard = keyboard | |
22 | + | |
23 | + # フィルター名 | |
24 | + @filter = filter | |
25 | + | |
26 | + # 履歴データ | |
27 | + @history = history | |
28 | + end | |
29 | + | |
30 | + def functions(regexp) | |
31 | + funcs = [] | |
32 | + @keybind.each do |data| | |
33 | + funcs << data if data[0] =~ regexp | |
34 | + end | |
35 | + funcs | |
36 | + end | |
37 | + | |
38 | + def print_keybind(title, prefix, suffix, link_name='') | |
39 | + puts %Q{<h3><a name=\"#{link_name}\">#{title}</a></h3>} if (@filter == 'html') | |
40 | + puts %Q{*** #{title}} if (@filter == 'hatena') | |
41 | + | |
42 | + puts %Q{<table cellspacing="2" cellpadding="0" border="1">} | |
43 | + @keyboard.each do |row| | |
44 | + puts %Q{<tr>} | |
45 | + row.each do |key| | |
46 | + funcs = [] | |
47 | + | |
48 | + if (key.size == 2) | |
49 | + key[1].each do |s| | |
50 | + f = functions(Regexp.new("#{prefix}#{s}#{suffix}")) | |
51 | + f.each {|a| a[1] += "(#{s.sub(/\\/, '')})" if (a[1] !~ /\(.\)$/) } | |
52 | + funcs.concat f | |
53 | + end | |
54 | + end | |
55 | + | |
56 | + puts %Q{<td #{td_attr(key, funcs)}><p align="center">#{p_value(key, funcs)}</p></td>} | |
57 | + end | |
58 | + puts %Q{</tr>} | |
59 | + end | |
60 | + puts %Q{</table>} | |
61 | + end | |
62 | + | |
63 | + def td_attr(key, funcs) | |
64 | + attr = [] | |
65 | + color = '#80ff00' | |
66 | + color = @history.color(funcs[0][1].sub(/\(.*\)$/, '')) if (!funcs.empty? and @history) | |
67 | + attr << "bgcolor=\"#{color}\"" if (funcs.size > 0) | |
68 | + attr.join(' ') | |
69 | + end | |
70 | + | |
71 | + def p_value(key, funcs) | |
72 | + str = "#{key[0]}" | |
73 | + | |
74 | + funcs.each do |func| | |
75 | + str += "<br><b><font size=\"-1\" color=\"#7F00FF\">#{func[1]}</font></b>" | |
76 | + end | |
77 | + | |
78 | + str | |
79 | + end | |
80 | + | |
81 | + def print_standard_keybind | |
82 | + print_keybind("?", '^', '$', 'self') | |
83 | + print_keybind("C-?", '^C-', '$', 'control') | |
84 | + print_keybind("M-?", '^M-', '$', 'alt') | |
85 | + print_keybind("C-M-?", '^C-M-', '$', 'control_alt') | |
86 | + print_keybind("C-x C-?", '^C-x C-', '$', 'control_x_control') | |
87 | + print_keybind("C-x ?", '^C-x ', '$', 'control_x') | |
88 | + print_keybind("C-c C-?", '^C-c C-', '$', 'control_c_control') | |
89 | + print_keybind("C-c ?", '^C-c ', '$', 'control_c') | |
90 | + end | |
91 | +end | |
92 | + | |
93 | +if __FILE__ == $0 | |
94 | + keyboard_kind = nil | |
95 | + filter = 'html' | |
96 | + history_file_name = nil | |
97 | + | |
98 | + opt = OptionParser.new('Usage: emacs_keybind [options] input_file') | |
99 | + opt.on('-k', '--keyboard (ascii, japanese)') {|v| keyboard_kind = v } | |
100 | + opt.on('-f', '--filter (html, hatena)') {|v| filter = v } | |
101 | + opt.on('-h', '--history HISTORY_FILE_NAME') {|v| history_file_name = v } | |
102 | + opt.parse!(ARGV) | |
103 | + | |
104 | + case keyboard_kind | |
105 | + when 'ascii' | |
106 | + keyboard = KeyboardAscii | |
107 | + when 'japanese' | |
108 | + keyboard = KeyboardJapanese | |
109 | + else | |
110 | + if (keyboard_kind) | |
111 | + abort "#{keyboard_kind} is not support. please set keyboard kind(ascci or japanese)" | |
112 | + else | |
113 | + abort "please set keyboard kind(ascci or japanese)" | |
114 | + end | |
115 | + end | |
116 | + | |
117 | + case filter | |
118 | + when 'html' | |
119 | + when 'hatena' | |
120 | + else | |
121 | + abort "#{keyboard_kind} is not support. please set keyboard kind(ascci or japanese)" | |
122 | + end | |
123 | + | |
124 | + # セットアップ | |
125 | + history = EmacsHistory.new(history_file_name) if (history_file_name) | |
126 | + keybind = EmacsKeybind.new(keyboard, filter, history) | |
127 | + | |
128 | + # HTML出力 | |
129 | + print Header if (filter == 'html') | |
130 | + print HeaderHatena if (filter == 'hatena') | |
131 | + | |
132 | + if (history) | |
133 | + puts %Q{<h1><a name="frequency">Frequency in use</a></h3>} | |
134 | + | |
135 | + puts %Q{<table cellspacing="2" cellpadding="0" border="1">} | |
136 | + puts %Q{<tr><td><b>Ranking</b></td><td><b>Use Count</b></td><td><b>Emacs Command</b></td></tr>} | |
137 | + history.ranking.each do |a| | |
138 | + puts %Q{<tr><td>#{a[1].ranking}</td><td>#{a[1].use_count}</td><td bgcolor=#{history.color(a[0])}>#{a[0]}</td></tr>} | |
139 | + end | |
140 | + puts %Q{</table>} | |
141 | + end | |
142 | + | |
143 | + puts %Q{<h1><a name="keybind">Keybind</a></h1>} | |
144 | + keybind.print_standard_keybind | |
145 | + | |
146 | + print Footer if (filter == 'html') | |
147 | +end |
@@ -0,0 +1,94 @@ | ||
1 | +;;; emacs-keybind.el | |
2 | + | |
3 | +;;; Commentary: | |
4 | +;; 全てのコマンド実行履歴をファイルに保存する | |
5 | + | |
6 | +;;; 設定用変数 | |
7 | +(defvar emacs-keybind-program-file | |
8 | + "~/.emacs.d/emacs_keybind.rb" | |
9 | + "Place of emacs_keybind.rb") | |
10 | + | |
11 | +(defvar emacs-keybind-keyboard-kind | |
12 | + "ascii" | |
13 | + "ascii or japanese") | |
14 | + | |
15 | +(defvar emacs-keybind-work-dir | |
16 | + "~/.emacs.d" | |
17 | + "") | |
18 | + | |
19 | +(defvar emacs-keybind-history-save-file-name | |
20 | + "emacs-keybind-history-save-file" | |
21 | + "Name of file where history information is stored.") | |
22 | + | |
23 | +(defvar emacs-keybind-show-file-name | |
24 | + "emacs-keybind.html" | |
25 | + "") | |
26 | + | |
27 | +(defvar emacs-keybind-show-with-history-file-name | |
28 | + "emacs-keybind-with-history.html" | |
29 | + "") | |
30 | + | |
31 | +;; ユーティリティ関数 | |
32 | +(defun emacs-keybind-make-path (fname) | |
33 | + (concat emacs-keybind-work-dir "/" fname)) | |
34 | + | |
35 | +;;; ヒストリの追加と保存 | |
36 | +(setq emacs-keybind-history-work nil) | |
37 | + | |
38 | +(defun emacs-keybind-history-save () | |
39 | + "Save history information to file given by `emacs-keybind-history-save-file-name'." | |
40 | + (interactive) | |
41 | + (with-temp-buffer | |
42 | + (insert ";; " (format-time-string "%Y/%m/%d %H:%M" (current-time)) "\n") | |
43 | + (prin1 emacs-keybind-history-work (current-buffer)) | |
44 | + (insert ?\n) | |
45 | + (write-region (point-min) (point-max) (emacs-keybind-make-path emacs-keybind-history-save-file-name) t))) | |
46 | + | |
47 | +(defun emacs-keybind-history-add (&optional arg) | |
48 | + "The command history is added to `emacs-keybind-history-work'." | |
49 | + (setq emacs-keybind-history-work (append (list this-command) emacs-keybind-history-work))) | |
50 | + | |
51 | +(add-hook 'kill-emacs-hook 'emacs-keybind-history-save) | |
52 | +(add-hook 'pre-command-hook 'emacs-keybind-history-add) | |
53 | + | |
54 | +;;; キーバインドレポートの表示 | |
55 | +(defun emacs-keybind-show () | |
56 | + "The key bind report is displayed." | |
57 | + (interactive) | |
58 | + (describe-bindings) | |
59 | + (switch-to-buffer "*Help*") | |
60 | + (call-process-region | |
61 | + (point-min) (point-max) | |
62 | + emacs-keybind-program-file | |
63 | + nil | |
64 | + (generate-new-buffer "*emacs-report*") | |
65 | + nil | |
66 | + "-k" emacs-keybind-keyboard-kind | |
67 | + "-f" "html") | |
68 | + (switch-to-buffer "*emacs-report*") | |
69 | + (let ((file-name (emacs-keybind-make-path emacs-keybind-show-file-name))) | |
70 | + (write-file file-name) | |
71 | + (browse-url-of-file file-name) | |
72 | + (kill-buffer (current-buffer)))) | |
73 | + | |
74 | +(defun emacs-keybind-show-with-history () | |
75 | + "The key bind report is displayed including history information." | |
76 | + (interactive) | |
77 | + (describe-bindings) | |
78 | + (switch-to-buffer "*Help*") | |
79 | + (call-process-region | |
80 | + (point-min) (point-max) | |
81 | + emacs-keybind-program-file | |
82 | + nil | |
83 | + (generate-new-buffer "*emacs-report*") | |
84 | + nil | |
85 | + "-k" emacs-keybind-keyboard-kind | |
86 | + "-h" (emacs-keybind-make-path emacs-keybind-history-save-file-name) | |
87 | + "-f" "html") | |
88 | + (switch-to-buffer "*emacs-report*") | |
89 | + (let ((file-name (emacs-keybind-make-path emacs-keybind-show-with-history-file-name))) | |
90 | + (write-file file-name) | |
91 | + (browse-url-of-file file-name) | |
92 | + (kill-buffer (current-buffer)))) | |
93 | + | |
94 | +(provide 'emacs-keybind) |
@@ -0,0 +1,154 @@ | ||
1 | +require 'matrix' | |
2 | + | |
3 | +class String | |
4 | + def to_sexp | |
5 | + array = self.chomp.split(/([()])| /).delete_if{|c| c.size == 0} | |
6 | + raise "The expression doesn't close." if array[-1] != ')' | |
7 | + array.parse_sexp | |
8 | + end | |
9 | + | |
10 | + def to_s_sexp | |
11 | + self | |
12 | + end | |
13 | +end | |
14 | + | |
15 | +class Array | |
16 | + def to_s_sexp | |
17 | + str="" | |
18 | + str += '(' | |
19 | + self.each do |s| | |
20 | + str += ( s.class == Array ? s.to_s_sexp : s.to_s ) | |
21 | + str += ' ' | |
22 | + end | |
23 | + str += ')' | |
24 | + str | |
25 | + end | |
26 | + | |
27 | + def parse_sexp | |
28 | + q = [] | |
29 | + q << '[' | |
30 | + self.each do |l| | |
31 | + case l | |
32 | + when '(' | |
33 | + q << '[' | |
34 | + when ')' | |
35 | + q << '],' | |
36 | + else | |
37 | + q << '"' + l + '",' | |
38 | + end | |
39 | + end | |
40 | + q << ']' | |
41 | + return eval( q.join ) | |
42 | + end | |
43 | +end | |
44 | + | |
45 | +class Vector | |
46 | + def []=(i,x) | |
47 | + @elements[i]=x | |
48 | + end | |
49 | +end | |
50 | + | |
51 | +class Color | |
52 | + attr_accessor :vector | |
53 | + | |
54 | + def initialize(r, g, b) | |
55 | + @vector = Vector[r, g, b] | |
56 | + end | |
57 | + | |
58 | + def +(rhs) | |
59 | + color = clone | |
60 | + color.vector += rhs.vector | |
61 | + color.limit | |
62 | + end | |
63 | + | |
64 | + def *(rhs) | |
65 | + color = clone | |
66 | + color.vector *= rhs | |
67 | + color.limit | |
68 | + end | |
69 | + | |
70 | + def limit | |
71 | + color = clone | |
72 | + color.vector[0] = 255 if (color.vector[0] > 255) | |
73 | + color.vector[1] = 255 if (color.vector[1] > 255) | |
74 | + color.vector[2] = 255 if (color.vector[2] > 255) | |
75 | + color | |
76 | + end | |
77 | + | |
78 | + def to_html | |
79 | + "##{format("%02x", @vector[0])}#{format("%02x", @vector[1])}#{format("%02x", @vector[2])}" | |
80 | + end | |
81 | +end | |
82 | + | |
83 | +class EmacsHistoryData | |
84 | + attr_accessor :use_count, :ranking | |
85 | + | |
86 | + def initialize | |
87 | + @use_count = 0 | |
88 | + @ranking = 0 | |
89 | + end | |
90 | +end | |
91 | + | |
92 | +class EmacsHistory | |
93 | + def initialize(file_name) | |
94 | + @hash = Hash.new | |
95 | + parse(file_name) | |
96 | + setup_ranking | |
97 | + end | |
98 | + | |
99 | + def parse(file_name) | |
100 | + open(file_name).each do |line| | |
101 | + next if (line =~ /^;/) | |
102 | + | |
103 | + line.chomp.to_sexp[0].each do |name| | |
104 | + s_exp = name.to_s_sexp | |
105 | + @hash[s_exp] = EmacsHistoryData.new if !@hash.key? s_exp | |
106 | + @hash[s_exp].use_count += 1 | |
107 | + end | |
108 | + end | |
109 | + end | |
110 | + | |
111 | + def setup_ranking | |
112 | + @ranking = @hash.to_a.sort {|a, b| (b[1].use_count <=> a[1].use_count).nonzero? or a[0] <=> b[0] } | |
113 | + | |
114 | + current = 1 | |
115 | + prev = @ranking[0] | |
116 | + | |
117 | + @ranking.each do |a| | |
118 | + current += 1 if (a[1].use_count != prev[1].use_count) | |
119 | + a[1].ranking = current | |
120 | + prev = a | |
121 | + end | |
122 | + | |
123 | + @ranking_total = current | |
124 | + end | |
125 | + | |
126 | + def count(name) | |
127 | + @hash.fetch(name) {|| 0 } | |
128 | + end | |
129 | + | |
130 | + def ranking | |
131 | + @ranking | |
132 | + end | |
133 | + | |
134 | + def color(s_exp) | |
135 | + color1 = Color.new(255, 0, 0) | |
136 | + color2 = Color.new(255, 255, 0) | |
137 | + color3 = Color.new(0, 0, 255) | |
138 | + | |
139 | + return color3.to_html if (!@hash.key?(s_exp)) | |
140 | + | |
141 | + data = @hash[s_exp] | |
142 | + | |
143 | + index = data.ranking - 1 | |
144 | + half = @ranking_total / 2 | |
145 | + | |
146 | + if (index < half) | |
147 | + rate = index.to_f / half | |
148 | + (color1 * (1.0 - rate) + color2 * (rate)).to_html | |
149 | + else | |
150 | + rate = (index.to_f - half) / half | |
151 | + (color2 * (1.0 - rate) + color3 * (rate)).to_html | |
152 | + end | |
153 | + end | |
154 | +end |
@@ -0,0 +1,251 @@ | ||
1 | +Header = <<EOF | |
2 | +<html> | |
3 | +<head> | |
4 | +<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> | |
5 | +<title></title> | |
6 | +</head> | |
7 | +<body> | |
8 | +<p> | |
9 | +<h1>Index</h1> | |
10 | +<ol> | |
11 | + <li><a href="#frequency">frequency</a></li> | |
12 | + <li><a href="#keybind">keybind</a></li> | |
13 | + <ol> | |
14 | + <li><a href="#self">?</a></li> | |
15 | + <li><a href="#control">C-?</a></li> | |
16 | + <li><a href="#alt">M-?</a></li> | |
17 | + <li><a href="#control_alt">C-M-?</a></li> | |
18 | + <li><a href="#control_x_control">C-x C-?</a></li> | |
19 | + <li><a href="#control_x">C-x ?</a></li> | |
20 | + <li><a href="#control_c_control">C-c C-?</a></li> | |
21 | + <li><a href="#control_c">C-c ?</a></li> | |
22 | + </ol> | |
23 | +</ol> | |
24 | +EOF | |
25 | + | |
26 | +Footer = <<EOF | |
27 | +</p> | |
28 | +</body> | |
29 | +</html> | |
30 | +EOF | |
31 | + | |
32 | +HeaderHatena = <<EOF | |
33 | +**Emacs Keybind | |
34 | +EOF | |
35 | + | |
36 | +KeyboardAscii = | |
37 | + [ | |
38 | + # ESC 〜 DEL | |
39 | + [ | |
40 | + ['ESC'], | |
41 | + ['F1'], | |
42 | + ['F2'], | |
43 | + ['F3'], | |
44 | + ['F4'], | |
45 | + ['F5'], | |
46 | + ['F6'], | |
47 | + ['F7'], | |
48 | + ['F8'], | |
49 | + ['F9'], | |
50 | + ['F10'], | |
51 | + ['F11'], | |
52 | + ['F12'], | |
53 | + ['INS'], | |
54 | + ['DEL'], | |
55 | + ], | |
56 | + # 半角/全角 〜 Backspace | |
57 | + [ | |
58 | + ['`~', %w(` ~)], | |
59 | + ['1!', %w(1 !)], | |
60 | + ['2@', %w(2 @)], | |
61 | + ['3#', %w(3 #)], | |
62 | + ['4$', %w(4 \$)], | |
63 | + ['5%', %w(5 %)], | |
64 | + ['6^', %w(6 ^)], | |
65 | + ["7&", %w(7 &)], | |
66 | + ['8*', %w(8 \*)], | |
67 | + ['9(', %w(9 \\\()], | |
68 | + ['0)', %w(0 \\\))], | |
69 | + ['-_', %w(- _)], | |
70 | + ['= +', %w(= \+)], | |
71 | + ['BS'], | |
72 | + ], | |
73 | + # TAB 〜 RET | |
74 | + [ | |
75 | + ['TAB', %w(TAB)], | |
76 | + ['Q', %w(q Q)], | |
77 | + ['W', %w(w W)], | |
78 | + ['E', %w(e E)], | |
79 | + ['R', %w(r R)], | |
80 | + ['T', %w(t T)], | |
81 | + ['Y', %w(y Y)], | |
82 | + ['U', %w(u U)], | |
83 | + ['I', %w(i I)], | |
84 | + ['O', %w(o O)], | |
85 | + ['P', %w(p P)], | |
86 | + ['[{', %w(\[ \{)], | |
87 | + [']}', %w(\] \})], | |
88 | + ['\|', %w(\\\\ \|)], | |
89 | + ], | |
90 | + # Caps 〜 RET | |
91 | + [ | |
92 | + ['Caps'], | |
93 | + ['A', %w(a A)], | |
94 | + ['S', %w(s S)], | |
95 | + ['D', %w(d D)], | |
96 | + ['F', %w(f F)], | |
97 | + ['G', %w(g G)], | |
98 | + ['H', %w(h H)], | |
99 | + ['J', %w(j J)], | |
100 | + ['K', %w(k K)], | |
101 | + ['L', %w(l L)], | |
102 | + [';:', %w(; :)], | |
103 | + ["'\"", %w(' ")], | |
104 | + [''], | |
105 | + ['RET', %w(RET)], | |
106 | + ], | |
107 | + # Shift 〜 Shift | |
108 | + [ | |
109 | + ['Shift'], | |
110 | + ['Z', %w(z Z)], | |
111 | + ['X', %w(x X)], | |
112 | + ['C', %w(c C)], | |
113 | + ['V', %w(v V)], | |
114 | + ['B', %w(b B)], | |
115 | + ['N', %w(n N)], | |
116 | + ['M', %w(m M)], | |
117 | + [',<', %w(, <)], | |
118 | + ['.>', %w(\. >)], | |
119 | + ['/?', %w(\/ \?)], | |
120 | + [''], | |
121 | + [''], | |
122 | + ['Shift'], | |
123 | + ], | |
124 | + # Ctrl 〜 [right] | |
125 | + [ | |
126 | + ['Ctrl'], | |
127 | + ['Alt'], | |
128 | + [''], | |
129 | + [''], | |
130 | + ['SPC', %w(SPC)], | |
131 | + [''], | |
132 | + [''], | |
133 | + [''], | |
134 | + ['Alt'], | |
135 | + ['Ctrl'], | |
136 | + ['[up]'], | |
137 | + ['[down]'], | |
138 | + ['[left]'], | |
139 | + ['[right]'], | |
140 | + ], | |
141 | + ] | |
142 | + | |
143 | +KeyboardJapanese = | |
144 | + [ | |
145 | + # ESC 〜 DEL | |
146 | + [ | |
147 | + ['ESC'], | |
148 | + ['F1'], | |
149 | + ['F2'], | |
150 | + ['F3'], | |
151 | + ['F4'], | |
152 | + ['F5'], | |
153 | + ['F6'], | |
154 | + ['F7'], | |
155 | + ['F8'], | |
156 | + ['F9'], | |
157 | + ['F10'], | |
158 | + ['F11'], | |
159 | + ['F12'], | |
160 | + ['INS'], | |
161 | + ['DEL'], | |
162 | + ], | |
163 | + # 半角/全角 〜 Backspace | |
164 | + [ | |
165 | + ['one byte/two byte'], | |
166 | + ['1!', %w(1 !)], | |
167 | + ['2"', %w(2 ")], | |
168 | + ['3#', %w(3 #)], | |
169 | + ['4$', %w(4 \$)], | |
170 | + ['5%', %w(5 %)], | |
171 | + ['6&', %w(6 &)], | |
172 | + ["7'", %w(7 ')], | |
173 | + ['8(', %w(8 \\\()], | |
174 | + ['9)', %w(9 \\\))], | |
175 | + ['0', %w(0)], | |
176 | + ['-=', %w(- =)], | |
177 | + ['^~', %w(^ ~)], | |
178 | + ['\|', %w(\\\\ \|)], | |
179 | + ['BS'], | |
180 | + ], | |
181 | + # TAB 〜 RET | |
182 | + [ | |
183 | + ['TAB', %w(TAB)], | |
184 | + ['Q', %w(q Q)], | |
185 | + ['W', %w(w W)], | |
186 | + ['E', %w(e E)], | |
187 | + ['R', %w(r R)], | |
188 | + ['T', %w(t T)], | |
189 | + ['Y', %w(y Y)], | |
190 | + ['U', %w(u U)], | |
191 | + ['I', %w(i I)], | |
192 | + ['O', %w(o O)], | |
193 | + ['P', %w(p P)], | |
194 | + ['@`', %w(@ `)], | |
195 | + ['[{', %w(\[ \{)], | |
196 | + [''], | |
197 | + ['RET', %w(RET)], | |
198 | + ], | |
199 | + # Caps 〜 RET | |
200 | + [ | |
201 | + ['Caps'], | |
202 | + ['A', %w(a A)], | |
203 | + ['S', %w(s S)], | |
204 | + ['D', %w(d D)], | |
205 | + ['F', %w(f F)], | |
206 | + ['G', %w(g G)], | |
207 | + ['H', %w(h H)], | |
208 | + ['J', %w(j J)], | |
209 | + ['K', %w(k K)], | |
210 | + ['L', %w(l L)], | |
211 | + [';+', %w(; \+)], | |
212 | + [':*', %w(: \*)], | |
213 | + [']}', %w(\] \})], | |
214 | + [''], | |
215 | + [''], # RETのみ特殊で二列で表示する | |
216 | + ], | |
217 | + # Shift 〜 Shift | |
218 | + [ | |
219 | + ['Shift'], | |
220 | + ['Z', %w(z Z)], | |
221 | + ['X', %w(x X)], | |
222 | + ['C', %w(c C)], | |
223 | + ['V', %w(v V)], | |
224 | + ['B', %w(b B)], | |
225 | + ['N', %w(n N)], | |
226 | + ['M', %w(m M)], | |
227 | + [',<', %w(, <)], | |
228 | + ['.>', %w(\. >)], | |
229 | + ['/?', %w(\/ \?)], | |
230 | + ['\_', %w(\\\\ _)], | |
231 | + [''], | |
232 | + [''], | |
233 | + ['Shift'], | |
234 | + ], | |
235 | + # Ctrl 〜 [right] | |
236 | + [ | |
237 | + ['Ctrl'], | |
238 | + [''], | |
239 | + ['Alt'], | |
240 | + ['No conversion'], | |
241 | + ['SPC', %w(SPC)], | |
242 | + ['Conversion'], | |
243 | + ['Alt'], | |
244 | + ['Ctrl'], | |
245 | + ['[up]'], | |
246 | + ['[down]'], | |
247 | + ['[left]'], | |
248 | + ['[right]'], | |
249 | + ], | |
250 | + ] | |
251 | + |