├── LICENSE
├── MyEmacsKeymap.ahk
├── README.ja.md
└── README.md
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 oneh
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/MyEmacsKeymap.ahk:
--------------------------------------------------------------------------------
1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2 | ;; MyEmacsKeymap.ahk
3 | ;; - An AutoHotkey script to simulate Emacs keybindings on Windows
4 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5 |
6 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
7 | ;; Settings for testing
8 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
9 | ;; enable warning
10 | ;#Warn All, MsgBox
11 | ;; replace the existing process with the newly started one without prompt
12 | ;#SingleInstance force
13 |
14 | ;;--------------------------------------------------------------------------
15 | ;; Important hotkey prefix symbols
16 | ;; Help > Basic Usage and Syntax > Hotkeys
17 | ;; # -> Win
18 | ;; ! -> Alt
19 | ;; ^ -> Control
20 | ;; + -> Shift
21 | ;;--------------------------------------------------------------------------
22 |
23 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
24 | ;; General configuration
25 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
26 | ;; These settings are required for this script to work.
27 | #InstallKeybdHook
28 | #UseHook
29 |
30 | ;; What does this actually do?
31 | SetKeyDelay 0
32 |
33 | ;; Just to play with non-default send modes
34 | ;SendMode Input
35 | ;SendMode Play
36 |
37 | ;; Matching behavior of the WinTitle parameter
38 | ;; 1: from the start, 2: anywhere, 3: exact match
39 | ;; or RegEx: regular expressions
40 | SetTitleMatchMode 2
41 |
42 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
43 | ;; Global variables
44 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
45 | ;; mark status. 1 = set, 0 = not set
46 | global m_Mark := 0
47 |
48 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
49 | ;; Control functions
50 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
51 | ;; Determines if this script should be enabled based on "ahk_class" of the
52 | ;; active window. "ahk_class" can be identified using Window Spy
53 | ;; (right-click on the AutoHotkey icon in the task bar)
54 | m_IsEnabled() {
55 | global
56 | ;; List of applications to be ignored by this script
57 | ;; (Add applications as needed)
58 | ;; Emacs - NTEmacs
59 | ;; Vim - GVim
60 | ;; mintty - Cygwin
61 | m_IgnoreList := ["Emacs", "Vim", "mintty"]
62 | for index, element in m_IgnoreList
63 | {
64 | IfWinActive ahk_class %element%
65 | Return 0
66 | }
67 | IfWinActive ahk_class ConsoleWindowClass ; Command Prompt
68 | {
69 | IfWinActive ahk_exe bash.exe
70 | Return 0
71 | }
72 | Return 1
73 | }
74 | ;; Checks if the active window is MS Excel. The main things it does:
75 | ;; C-c a Activates the selected cell and move the cursor to the end
76 | ;; This key stroke sends {F12}. The "a" is for Append.
77 | ;; C-c i Activates the selected cell and move the cursor to the beginning
78 | ;; This key stroke sends {F12]{Home}. The "i" is for Insert.
79 | ;; Note: In Excel 2013, you may want to disable the quick analysis feature
80 | ;; (Options > General > Show Quick Analysis options on selection).
81 | m_IsMSExcel() {
82 | global
83 | IfWinActive ahk_class XLMAIN
84 | Return 1
85 | Return 0
86 | }
87 | m_IsNotMSExcel() {
88 | global
89 | IfWinNotActive ahk_class XLMAIN
90 | Return 1
91 | Return 0
92 | }
93 | ;; Checks if the active window is Google Sheets.
94 | ;; The main purpose is to provide keybindings to edit cells as does with MS
95 | ;; Excel.
96 | m_IsGoogleSheets() {
97 | global
98 | ;IfWinActive Google Sheets ahk_class MozillaWindowsClass
99 | IfWinActive ahk_class MozillaWindowClass ; FireFox
100 | Return 1
101 | IfWinActive Google Sheets ahk_class Chrome_WidgetWin_1 ; Chrome
102 | Return 1
103 | Return 0
104 | }
105 | ;; Checks if the active window is MS Word. The main things it does:
106 | ;; "kill-line" sends "+{End}+{Left}^c{Del}" instead of "+{End}^c{Del}".
107 | ;; This is to cut out the line feed mark which is usually configured to
108 | ;; be displayed in the View options in MS Word.
109 | m_IsMSWord() {
110 | global
111 | IfWinActive ahk_class OpusApp
112 | Return 1
113 | Return 0
114 | }
115 |
116 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
117 | ;; Prefix key processing
118 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
119 | ;; These functions just return without any processing.
120 | ;; The purpose of these functions is to make sure the hotkey is mapped to
121 | ;; the A_PriorHotkey built-in variable when the prefix key is pressed.
122 | ;; Ex) To detect whether C-x is pressed as the prefix key:
123 | ;; if (A_PriorHotkey = "^x")
124 | m_EnableControlCPrefix() {
125 | Return
126 | }
127 | m_EnableControlXPrefix() {
128 | Return
129 | }
130 | m_EnableControlQPrefix() {
131 | Return
132 | }
133 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
134 | ;; Emacs simulating functions
135 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
136 | ;; Buffers and Files ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
137 | ;; C-x C-f
138 | m_FindFile() {
139 | Send ^o
140 | global m_Mark := 0
141 | }
142 | ;; C-x C-s
143 | m_SaveBuffer() {
144 | Send ^s
145 | global m_Mark := 0
146 | }
147 | ;; C-x C-w
148 | m_WriteFile() {
149 | Send !fa
150 | global m_Mark := 0
151 | }
152 | ;; C-x k
153 | m_KillBuffer() {
154 | m_KillEmacs()
155 | }
156 | ;; C-x C-c
157 | m_KillEmacs() {
158 | Send !{F4}
159 | global m_Mark := 0
160 | }
161 | ;; Cursor Motion ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
162 | ;; C-f
163 | m_ForwardChar() {
164 | global
165 | if (m_Mark) {
166 | Send +{Right}
167 | } else {
168 | Send {Right}
169 | }
170 | }
171 | ;; C-b
172 | m_BackwardChar() {
173 | global
174 | if (m_Mark) {
175 | Send +{Left}
176 | } else {
177 | Send {Left}
178 | }
179 | }
180 | ;; C-n
181 | m_NextLine() {
182 | global
183 | if (m_Mark) {
184 | Send +{Down}
185 | } else {
186 | Send {Down}
187 | }
188 | }
189 | ;; C-p
190 | m_PreviousLine() {
191 | global
192 | if (m_Mark) {
193 | Send +{Up}
194 | } else {
195 | Send {Up}
196 | }
197 | }
198 | ;; M-f
199 | m_ForwardWord() {
200 | global
201 | if (m_Mark) {
202 | Loop 5
203 | Send +{Right}
204 | } else {
205 | Loop, 5
206 | Send {Right}
207 | }
208 | }
209 | ;; M-b
210 | m_BackwardWord() {
211 | global
212 | if (m_Mark) {
213 | Loop, 5
214 | Send +{Left}
215 | } else {
216 | Loop, 5
217 | Send {Left}
218 | }
219 | }
220 | ;; M-n
221 | m_MoreNextLines() {
222 | global
223 | if (m_Mark) {
224 | Loop, 5
225 | Send +{Down}
226 | } else {
227 | Loop, 5
228 | Send {Down}
229 | }
230 | }
231 | ;; M-p
232 | m_MorePreviousLines() {
233 | global
234 | if (m_Mark) {
235 | Loop, 5
236 | Send +{Up}
237 | } else {
238 | Loop, 5
239 | Send {Up}
240 | }
241 | }
242 | ;; C-a
243 | m_MoveBeginningOfLine() {
244 | global
245 | if (m_Mark) {
246 | Send +{Home}
247 | } else {
248 | Send {Home}
249 | }
250 | }
251 | ;; C-e
252 | m_MoveEndOfLine() {
253 | global
254 | if (m_Mark) {
255 | Send +{End}
256 | } else {
257 | Send {End}
258 | }
259 | }
260 | ;; C-v
261 | m_ScrollDown() {
262 | global
263 | if (m_Mark) {
264 | Send +{PgDn}
265 | } else {
266 | Send {PgDn}
267 | }
268 | }
269 | ;; M-v
270 | m_ScrollUp() {
271 | global
272 | if (m_Mark) {
273 | Send +{PgUp}
274 | } else {
275 | Send {PgUp}
276 | }
277 | }
278 | ;; M-<
279 | m_BeginningOfBuffer() {
280 | global
281 | if (m_Mark) {
282 | Send ^+{Home}
283 | } else {
284 | Send ^{Home}
285 | }
286 | }
287 | ;; M->
288 | m_EndOfBuffer() {
289 | global
290 | if (m_Mark) {
291 | Send ^+{End}
292 | } else {
293 | Send ^{End}
294 | }
295 | }
296 | ;; Select, Delete, Copy & Paste ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
297 | ;; C-spc
298 | m_SetMarkCommand() {
299 | global
300 | if (m_Mark) {
301 | m_Mark := 0
302 | m_ForwardChar()
303 | m_BackwardChar()
304 | m_Mark := 1
305 | } else {
306 | m_Mark := 1
307 | }
308 | }
309 | ;; C-x h
310 | m_MarkWholeBuffer() {
311 | Send ^{End}^+{Home}
312 | global m_Mark := 1
313 | }
314 | ;; C-x C-p
315 | m_MarkPage() {
316 | m_MarkWholeBuffer()
317 | }
318 | ;; C-d
319 | m_DeleteChar() {
320 | Send {Del}
321 | global m_Mark := 0
322 | }
323 | ;; C-b
324 | m_DeleteBackwardChar() {
325 | Send {BS}
326 | global m_Mark := 0
327 | }
328 | ;; C-k
329 | m_KillLine() {
330 | If (m_IsMSWord()) {
331 | ;Send +{End}+{Left}^c{Del}
332 | Send +{End}+{Left}^x
333 | } else {
334 | ;Send +{End}^c{Del}
335 | Send +{End}^x
336 | }
337 | global m_Mark := 0
338 | }
339 | ;; C-w
340 | m_KillRegion() {
341 | Send ^x
342 | global m_Mark := 0
343 | }
344 | ;; M-w
345 | m_KillRingSave() {
346 | Send ^c
347 | global m_Mark := 0
348 | }
349 | ;; C-y
350 | m_Yank() {
351 | if (m_IsMSExcel()) {
352 | Send ^v
353 | ; Tried to suppress the "Paste Options" hovering menu with {Esc}, but it
354 | ; turned out this would cancel out the pasting action when it is done
355 | ; when the cell being edited.
356 | ; To close the hovering menu, it would be better to simply type the {Esc}
357 | ; key or C-g
358 | ;Send ^v{Esc}
359 | } else if (m_IsMSWord()) {
360 | ;Send ^v{Esc}{Esc}{Esc}
361 | Send ^v
362 | } else {
363 | Send ^v
364 | }
365 | global m_Mark := 0
366 | }
367 | ;; Search ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
368 | ;; C-s
369 | m_ISearchForward() {
370 | Send ^f
371 | global m_Mark := 0
372 | }
373 | ;; C-r
374 | m_ISearchBackward() {
375 | m_IsearchForward()
376 | }
377 | ;; Undo and Cancel ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
378 | ;; C-/
379 | m_Undo() {
380 | Send ^z
381 | global m_Mark := 0
382 | }
383 | ;; C-g
384 | m_KeyboardQuit() {
385 | ; MS Excel will ignore "{Esc}" generated by AHK in some cases(?)
386 | ;if (m_isNotMSExcel())
387 | ;Send {Esc}
388 | Send {Esc}
389 | global m_Mark := 0
390 | }
391 |
392 | ;; Input Method ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
393 | ;; C-x C-j
394 | m_ToggleInputMethod() {
395 | Send {vkF3sc029}
396 | global m_Mark := 0
397 | }
398 | ;; Others ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
399 | ;; C-m, C-j
400 | m_NewLine() {
401 | Send {Enter}
402 | global m_Mark := 0
403 | }
404 | ;; (C-o)
405 | m_OpenLine() {
406 | Send {Enter}{Up}
407 | global m_Mark := 0
408 | }
409 | ;; C-i
410 | m_IndentForTabCommand() {
411 | Send {Tab}
412 | global m_Mark := 0
413 | }
414 | ;; C-t
415 | m_TransposeChars() {
416 | m_SetMarkCommand()
417 | m_ForwardChar()
418 | m_KillRegion()
419 | m_BackwardChar()
420 | m_Yank()
421 | }
422 | ;; Keys to send as they are when followed by C-q ;;;;;;;;;;;;;;;;;;;;;;;;;;;
423 | ;; C-q C-a
424 | ;; For MS Paint
425 | m_RawSelectAll() {
426 | Send %A_ThisHotkey%
427 | }
428 | ;; C-q C-n
429 | ;; For Web browsers
430 | m_RawNewWindow() {
431 | Send %A_ThisHotkey%
432 | }
433 | ;; C-q C-p
434 | m_RawPrintBuffer() {
435 | Send %A_ThisHotkey%
436 | }
437 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
438 | ;; Keybindings
439 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
440 | ^Space::
441 | if (m_IsEnabled()) {
442 | m_SetMarkCommand()
443 | } else {
444 | Send {CtrlDown}{Space}{CtrlUp}
445 | ;Send %A_ThisHotkey% ; this ends up with messed up key strokes
446 | }
447 | Return
448 | ^/::
449 | if (m_IsEnabled()) {
450 | m_Undo()
451 | } else {
452 | Send %A_ThisHotkey%
453 | }
454 | Return
455 | !<::
456 | if (m_IsEnabled()) {
457 | m_BeginningOfBuffer()
458 | } else {
459 | Send %A_ThisHotkey%
460 | }
461 | Return
462 | !>::
463 | if (m_IsEnabled()) {
464 | m_EndOfBuffer()
465 | } else {
466 | Send %A_ThisHotkey%
467 | }
468 | Return
469 | ^\::
470 | if (m_IsEnabled()) {
471 | m_ToggleInputMethod()
472 | } else {
473 | Send %A_ThisHotkey%
474 | }
475 | Return
476 | a::
477 | if (m_IsMSExcel() or m_IsGoogleSheets() ) {
478 | if (A_PriorHotkey = "^c") {
479 | Send {F2}
480 | } else {
481 | Send %A_ThisHotkey%
482 | }
483 | } else {
484 | Send %A_ThisHotkey%
485 | }
486 | Return
487 | ^a::
488 | if (m_IsEnabled()) {
489 | if (A_PriorHotkey = "^q") {
490 | m_RawSelectAll()
491 | } else {
492 | m_MoveBeginningOfLine()
493 | }
494 | } else {
495 | Send %A_ThisHotkey%
496 | }
497 | Return
498 | ^b::
499 | if (m_IsEnabled()) {
500 | m_BackwardChar()
501 | } else {
502 | Send %A_ThisHotkey%
503 | }
504 | Return
505 | !b::
506 | if (m_IsEnabled()) {
507 | m_BackwardWord()
508 | } else {
509 | Send %A_ThisHotkey%
510 | }
511 | Return
512 | ^c::
513 | if (m_IsEnabled()) {
514 | if (A_PriorHotkey = "^x") {
515 | m_KillEmacs()
516 | } else if (m_IsMSExcel() or m_IsGoogleSheets()) {
517 | m_EnableControlCPrefix()
518 | } else {
519 | Send %A_ThisHotkey%
520 | }
521 | } else {
522 | Send %A_ThisHotkey%
523 | }
524 | Return
525 | ^d::
526 | if (m_IsEnabled()) {
527 | m_DeleteChar()
528 | } else {
529 | Send %A_ThisHotkey%
530 | }
531 | Return
532 | ^e::
533 | if (m_IsEnabled()) {
534 | m_MoveEndOfLine()
535 | } else {
536 | Send %A_ThisHotkey%
537 | }
538 | Return
539 | ^f::
540 | if (m_IsEnabled()) {
541 | if (A_PriorHotkey = "^x") {
542 | m_FindFile()
543 | } else {
544 | m_ForwardChar()
545 | }
546 | } else {
547 | Send %A_ThisHotkey%
548 | }
549 | Return
550 | !f::
551 | if (m_IsEnabled()) {
552 | m_ForwardWord()
553 | } else {
554 | Send %A_ThisHotkey%
555 | }
556 | Return
557 | ^g::
558 | if (m_IsEnabled()) {
559 | m_KeyboardQuit()
560 | } else {
561 | Send %A_ThisHotkey%
562 | }
563 | Return
564 | h::
565 | if (m_IsEnabled()) {
566 | if (A_PriorHotkey = "^x") {
567 | m_MarkWholeBuffer()
568 | } else {
569 | Send %A_ThisHotkey%
570 | }
571 | } else {
572 | Send %A_ThisHotkey%
573 | }
574 | Return
575 | ^h::
576 | if (m_IsEnabled()) {
577 | m_DeleteBackwardChar()
578 | } else {
579 | Send %A_ThisHotkey%
580 | }
581 | Return
582 | i::
583 | if (m_IsMSExcel() or m_IsGoogleSheets()) {
584 | if (A_PriorHotkey = "^c") {
585 | Send {F2}{Home}
586 | } else {
587 | Send %A_ThisHotkey%
588 | }
589 | } else {
590 | Send %A_ThisHotkey%
591 | }
592 | Return
593 | ^j::
594 | if (m_IsEnabled()) {
595 | if (A_PriorHotkey = "^x") {
596 | m_ToggleInputMethod()
597 | } else {
598 | m_NewLine()
599 | }
600 | } else {
601 | Send %A_ThisHotkey%
602 | }
603 | Return
604 | k::
605 | if (m_IsEnabled()) {
606 | if (A_PriorHotkey = "^x") {
607 | m_KillBuffer()
608 | } else {
609 | Send %A_ThisHotkey%
610 | }
611 | } else {
612 | Send %A_ThisHotkey%
613 | }
614 | Return
615 | ^k::
616 | if (m_IsEnabled()) {
617 | m_KillLine()
618 | } else {
619 | Send %A_ThisHotkey%
620 | }
621 | Return
622 | ^m::
623 | if (m_IsEnabled()) {
624 | m_NewLine()
625 | } else {
626 | Send %A_ThisHotkey%
627 | }
628 | Return
629 | ^n::
630 | if (m_IsEnabled()) {
631 | if (A_PriorHotkey = "^q") {
632 | m_RawNewWindow()
633 | } else {
634 | m_NextLine()
635 | }
636 | } else {
637 | Send %A_ThisHotkey%
638 | }
639 | Return
640 | !n::
641 | if (m_IsEnabled()) {
642 | m_MoreNextLines()
643 | } else {
644 | Send %A_ThisHotkey%
645 | }
646 | Return
647 | ^o::
648 | if (m_IsEnabled()) {
649 | ;m_ToggleInputMethod()
650 | m_OpenLine()
651 | } else {
652 | Send %A_ThisHotkey%
653 | }
654 | Return
655 | ^p::
656 | if (m_IsEnabled()) {
657 | if (A_PriorHotkey = "^x") {
658 | m_MarkPage()
659 | } else if (A_PriorHotkey = "^q") {
660 | m_RawPrintBuffer()
661 | } else {
662 | m_PreviousLine()
663 | }
664 | } else {
665 | Send %A_ThisHotkey%
666 | }
667 | Return
668 | !p::
669 | if (m_IsEnabled()) {
670 | m_MorePreviousLines()
671 | } else {
672 | Send %A_ThisHotkey%
673 | }
674 | Return
675 | ^q::
676 | if (m_IsEnabled()) {
677 | m_EnableControlQPrefix()
678 | } else {
679 | Send %A_ThisHotkey%
680 | }
681 | Return
682 | ^r::
683 | if (m_IsEnabled()) {
684 | m_ISearchBackward()
685 | } else {
686 | Send %A_ThisHotkey%
687 | }
688 | Return
689 | ^s::
690 | if (m_IsEnabled()) {
691 | if (A_PriorHotkey = "^x") {
692 | m_SaveBuffer()
693 | } else {
694 | m_ISearchForward()
695 | }
696 | } else {
697 | Send %A_ThisHotkey%
698 | }
699 | Return
700 | ^t::
701 | if (m_IsEnabled()) {
702 | m_TransposeChars()
703 | } else {
704 | Send %A_ThisHotkey%
705 | }
706 | Return
707 | u::
708 | if (m_IsEnabled()) {
709 | if (A_PriorHotkey = "^x") {
710 | m_Undo()
711 | } else {
712 | Send %A_ThisHotkey%
713 | }
714 | } else {
715 | Send %A_ThisHotkey%
716 | }
717 | Return
718 | ^v::
719 | if (m_IsEnabled()) {
720 | m_ScrollDown()
721 | } else {
722 | Send %A_ThisHotkey%
723 | }
724 | Return
725 | !v::
726 | if (m_IsEnabled()) {
727 | m_ScrollUp()
728 | } else {
729 | Send %A_ThisHotkey%
730 | }
731 | Return
732 | ^w::
733 | if (m_IsEnabled()) {
734 | if (A_PriorHotkey = "^x") {
735 | m_WriteFile()
736 | } else {
737 | m_KillRegion()
738 | }
739 | } else {
740 | Send %A_ThisHotkey%
741 | }
742 | Return
743 | !w::
744 | if (m_IsEnabled()) {
745 | m_KillRingSave()
746 | } else {
747 | Send %A_ThisHotkey%
748 | }
749 | Return
750 | ^x::
751 | if (m_IsEnabled()) {
752 | m_EnableControlXPrefix()
753 | } else {
754 | Send %A_ThisHotkey%
755 | }
756 | Return
757 | ^y::
758 | if (m_IsEnabled()) {
759 | m_Yank()
760 | } else {
761 | Send %A_ThisHotkey%
762 | }
763 | Return
764 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
765 | ;; Administration
766 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
767 | ^!q::
768 | Suspend, Toggle
769 | Return
770 | ^!z::
771 | if (m_IsEnabled()) {
772 | MsgBox, AutoHotkey emacs keymap is Enabled.
773 | } else {
774 | MsgBox, AutoHotkey emacs keymap is Disabled.
775 | }
776 | Return
777 |
--------------------------------------------------------------------------------
/README.ja.md:
--------------------------------------------------------------------------------
1 | # AutoHotkey を使って Windows で Emacs キーバインド
2 |
3 | このスクリプト `MyEmacsKeymap.ahk` は、Windows の操作に Emacs キーバインドを割り当てた AutHotkey スクリプトで、私が Windows を快適に操作するために個人的に使用しているものです。
4 |
5 | このスクリプトは以下のサイトで公開されているものを参考に、自分用に編集したものです。
6 |
7 | * WindowsでEmacs風キーバインド
8 | * https://github.com/usi3/emacs.ahk
9 | * Windows の操作を emacs のキーバインドで行うための設定(AutoHotKey版)
10 | * http://www49.atwiki.jp/ntemacs/pages/20.html
11 |
12 | ## 設定済みのキーバインド
13 |
14 | 個人的に「これだけあればまあ快適かな」と思える範囲でカバーしています。
15 |
16 |
17 |
18 | バッファとファイル | 選択、削除、コピー・ペースト |
19 |
20 |
21 | C-x C-f | find-file | C-SPC | set-mark-command |
22 |
23 |
24 | C-x C-s | save-buffer | C-x h | mark-whole-buffer |
25 |
26 |
27 | C-x C-w | write-file | C-x C-p | mark-page |
28 |
29 |
30 | C-x k | kill-buffer | C-d | delete-char |
31 |
32 |
33 | C-x C-c | kill-emacs | C-b | delete-backward-char |
34 |
35 |
36 | カーソル移動 | C-k | kill-line |
37 |
38 |
39 | C-f | forward-char | C-w | kill-region |
40 |
41 |
42 | C-b | backward-char | M-w | kill-ring-save |
43 |
44 |
45 | C-n | next-line | C-y | yank |
46 |
47 |
48 | C-p | previous-line | 検索 |
49 |
50 |
51 | M-f | forward-char x 5 [*1] | C-s | isearch-forward [*2] |
52 |
53 |
54 | M-b | backward-char x 5 [*1] | C-r | isearch-forward [*2] |
55 |
56 |
57 | M-n | next-line x 5 [*1] | アンドゥ、キャンセル |
58 |
59 |
60 | M-p | previous-line x 5 [*1] | C-/ | undo |
61 |
62 |
63 | C-a | move-beginning-of-line | C-x u | undo |
64 |
65 |
66 | C-e | move-end-of-line | C-g | keyboard-quit |
67 |
68 |
69 | C-v | scroll-down | その他 |
70 |
71 |
72 | M-v | scroll-up | C-m | new-line |
73 |
74 |
75 | M-< | beginning-of-buffer | C-i | indent-for-tab-command |
76 |
77 |
78 | M-> | end-of-buffer | C-j | new-line |
79 |
80 |
81 | 言語入力システム切替 | C-o | open-line |
82 |
83 |
84 | C-x C-j | toggle-input-method | C-t | transpose-chars |
85 |
86 |
87 | C-\ | toggle-input-method | | |
88 |
89 |
90 | Microsoft Excel、Google スプレッドシート[*3] |
91 |
92 |
93 | C-c a | 選択されたセルを活性化しカーソルを最後に移す (Append) (F2 ) |
94 |
95 |
96 | C-c i | 選択されたセルを活性化しカーソルを最初に移す (Insert) (F2 + Home ) |
97 |
98 |
99 | C-q プレフィックス: 一時的に Emacs キーバインディングを無効化[*4] |
100 |
101 |
102 | C-q C-a | (すべて選択) [*5] | C-q C-n | (新規ウィンドウ) [*6] |
103 |
104 |
105 | C-q C-p | (印刷) | | |
106 |
107 |
108 | C-M キー: 管理用キー |
109 |
110 |
111 | C-M-q | スクリプト実行の停止と再開の切替 |
112 |
113 |
114 | C-M-z | フォーカスされているアプリケーションでキーバインドが有効化されるかどうかの確認 |
115 |
116 |
117 |
118 | \*1. 単語単位ではなく5回分移動します。例えば `M-f`、`M-b` はカーソルを5回移動します。`M-n`、`M-p` は Emacs のキーバインドには存在しませんが、Web ブラウジングをするときなどに、ページ単位だと進みすぎるが1回のスクロールでは遅すぎるといった場合に便利です。
119 | \*2. 検索はインクリメンタルではありません。後方検索もなしです。
120 | \*3. 操作対象が Google スプレッドシートかどうかの判断は `m_IsGoogleSheets()` 関数の `IfWinActive` で行っています。私の場合、大雑把に FireFox か Google Chrome であれば `true` としていますが、より適切な判断をしたい場合はスクリプトを編集してください。
121 | \*4. `C-q` でツールを一時的に無効にするのは、かつて使用していた XKeymacs に慣らったものです。私は XKaymecs を長年使用していたため、印刷する時に `C-q C-p` と打つのが体に染み付いています。
122 | \*5. 私の場合、Microsoft Paint では `C-x h` や `C-x C-p` が効かないため替わりにこれを使用することがあります。
123 | \*6. 私の場合、Web ブラウザでこれを使用することがあります。
124 |
125 | ## 使い方
126 |
127 | AutoHotkey (http://ahkscript.org) を起動して、このスクリプト `MyEmacsKeymap.ahk` をロードします。AutoHotkey を新規インストールした場合、次の手順で使うことができます。
128 |
129 | 1) インストールディレクトリに `AutoHotkey.ahk` の名前で空のファイルを作成し、次の行を追加します:
130 | ```ahk
131 | #include %A_ScriptDir%\MyEmacsKeymap.ahk
132 | ```
133 | 2) `MyEmacsKeymap.ahk` を同ディレクトリにコピーします。
134 |
135 | 3) `AutHotkey.exe` を実行します。
136 |
137 | 補足: AutoHotkey をスクリプトファイルを指定せずに実行した場合、プログラムは最初に AutoHotkey の実行ファイルが置かれているディレクトリの `AutoHotkey.ahk` を探します。このディレクトリは `A_ScriptDir` ビルトイン変数に保持されており、`%A_ScriptDir%` で参照できます。
138 |
139 | * AutoHotkey Biginner Tutorial
140 | * https://autohotkey.com/docs/Tutorial.htm
141 | * AutoHotkey Wiki (日本語) - 使用方法
142 | * http://ahkwiki.net/Usage
143 |
144 | ## 使用上の注意
145 |
146 | ### キーを押し続けた時にキーが slip する
147 |
148 | 環境によってはキーを押し続けたときにキーが slip してしまうかもしれません。例えば `C-f` を押し続けたときに、`f` が単独で出力されたり、オリジナルのキーマップで判定されて検索ボックスが表示されたりします。この現象は、Windows コントロールパネルでキーボードの「表示の間隔(Repeat Rate)」を遅くすることで抑制することが可能です。
149 |
150 | ちなみに、AutoHotkey の `SendMode` の指定を変更することで現象を抑制できないか試したのですが、私が試した範囲では完全な対策にはなりませんでした。
151 |
152 | ### 特定のアプリケーションを操作対象から除外したい
153 |
154 | `m_IsEnabled` 関数の `m_IgnoreList` に、除外したいアプリケーションの `ahk_class` を追加してください。各アプリケーションにおける `ahk_class` の値は AutoHotkey 付属の Window Spy (`AU3_Spy.exe`) を使用して特定することができます。
155 |
156 | デフォルトでは、`Emacs`、`Vim` (GVim)、`mintty` (Cygwin Terminal) が操作対象から除外されています。
157 |
158 | ```ahk
159 | m_IsEnabled() {
160 | global
161 | ;; List of applications to be ignored by this script
162 | ;; (Add applications as needed)
163 | ;; Emacs - NTEmacs
164 | ;; Vim - GVim
165 | ;; mintty - Cygwin
166 | m_IgnoreList := ["Emacs", "Vim", "mintty"]
167 | for index, element in m_IgnoreList
168 | {
169 | IfWinActive ahk_class %element%
170 | Return 0
171 | }
172 | ```
173 | ### スクリプト実行を一時的に停止したい
174 |
175 | `C-M-q` がスクリプト実行の停止と再開を制御するスイッチとして働きます。これはタスクバーの AutoHotkey アイコンで右クリックメニューから "Suspend Hotkeys" を選択するのと同じ働きをします。
176 |
177 | ### 一部のアプリケーションで期待通りに動作しないキーがある
178 |
179 | 個人的には、これはそういうものだと割り切って使用しています。ニーズに合わせてスクリプトは自由に編集してください。
180 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Emacs Keybindings on Windows with AutoHotkey
2 |
3 | `MyEmacsKeymap.ahk` is an AutoHotkey script to simulate Emacs keybindings on Windows.
4 |
5 | This script is made largely based on the scripts provided in the following web sites.
6 |
7 | * WindowsでEmacs風キーバインド
8 | * https://github.com/usi3/emacs.ahk
9 | * Windows の操作を emacs のキーバインドで行うための設定(AutoHotKey版)
10 | * http://www49.atwiki.jp/ntemacs/pages/20.html
11 |
12 | ## Implemented Keybindings
13 |
14 |
15 |
16 | Buffers and Files | Select, Delete, Copy & Paste |
17 |
18 |
19 | C-x C-f | find-file | C-SPC | set-mark-command |
20 |
21 |
22 | C-x C-s | save-buffer | C-x h | mark-whole-buffer |
23 |
24 |
25 | C-x C-w | write-file | C-x C-p | mark-page |
26 |
27 |
28 | C-x k | kill-buffer | C-d | delete-char |
29 |
30 |
31 | C-x C-c | kill-emacs | C-b | delete-backward-char |
32 |
33 |
34 | Cursor Motion | C-k | kill-line |
35 |
36 |
37 | C-f | forward-char | C-w | kill-region |
38 |
39 |
40 | C-b | backward-char | M-w | kill-ring-save |
41 |
42 |
43 | C-n | next-line | C-y | yank |
44 |
45 |
46 | C-p | previous-line | Search |
47 |
48 |
49 | M-f | forward-char x 5 [*1] | C-s | isearch-forward [*2] |
50 |
51 |
52 | M-b | backward-char x 5 [*1] | C-r | isearch-forward [*2] |
53 |
54 |
55 | M-n | next-line x 5 [*1] | Undo, Cancel |
56 |
57 |
58 | M-p | previous-line x 5 [*1] | C-/ | undo |
59 |
60 |
61 | C-a | move-beginning-of-line | C-x u | undo |
62 |
63 |
64 | C-e | move-end-of-line | C-g | keyboard-quit |
65 |
66 |
67 | C-v | scroll-down | Others |
68 |
69 |
70 | M-v | scroll-up | C-m | new-line |
71 |
72 |
73 | M-< | beginning-of-buffer | C-i | indent-for-tab-command |
74 |
75 |
76 | M-> | end-of-buffer | C-j | new-line |
77 |
78 |
79 | Input Method Switching | C-o | open-line |
80 |
81 |
82 | C-x C-j | toggle-input-method | C-t | transpose-chars |
83 |
84 |
85 | C-\ | toggle-input-method | | |
86 |
87 |
88 | Microsoft Excel, Google Sheets [*3] |
89 |
90 |
91 | C-c a | Activates the selected cell with the cursor at the end (Append) (F2 ) |
92 |
93 |
94 | C-c i | Activates the selected cell with the cursor at the beginning (Insert) (F2 + Home ) |
95 |
96 |
97 | C-q prefix: Temporarily disabling Emacs keybindings[*4] |
98 |
99 |
100 | C-q C-a | (Select All) [*5] | C-q C-n | (New Window) [*6] |
101 |
102 |
103 | C-q C-p | (Print) | | |
104 |
105 |
106 | C-M keys: Special keys for administration |
107 |
108 |
109 | C-M-q | Suspends or resumes the execution of this script |
110 |
111 |
112 | C-M-z | Tells whether the implemented keybindings should be enabled or not for the application you are on |
113 |
114 |
115 |
116 | \*1. `M-f` and `M-b` move the cursor 5 times instead of moving through words. While `M-n` and `M-p` do not exist in Emacs keybindings, they can be a good middle ground when `C-n` / `C-p` are too slow and `C-v` / `M-v` are too fast for page scrolling.
117 | \*2. Search is not incremental. Backward search is not implemented, either.
118 | \*3. Whether the active application is Google Sheets is determined at `IfWinActive` in the `m_IsGoogleSheets()` function. The condition I set is very rough and it returns `true` whenever I am using FireFox or Google Chrome. You may want to modify the code to set a more suitable condition.
119 | \*4. The idea of using `C-q` to temporarily turn off the tool is from XKeymacs, another keybinding tool I used to use. I have used XKeymacs for so long that it has become almost a reflex to type `C-q C-p` for printing.
120 | \*5. Personally I use `C-q C-a` with Microsoft Paint, where `C-x h` and `C-x C-p` both do not work.
121 | \*6. Personally I use `C-q C-n` with Web browsers.
122 |
123 | ## Usage
124 |
125 | Launch AutoHotkey (http://ahkscript.org) and load `MyEmacsKeymap.ahk`. If you have a fresh installation of AutoHotkey, follow the steps below.
126 |
127 | 1) Create an empty file named `AutoHotkey.ahk` in the installation directory and add the following line to the file:
128 | ```ahk
129 | #include %A_ScriptDir%\MyEmacsKeymap.ahk
130 | ```
131 | 2) Copy `MyEmacsKeymap.ahk` in the same directory
132 |
133 | 3) Start `AutHotkey.exe`
134 |
135 | Note: If you run AutoHotkey without specifying a script file, the program will first look for `AutoHotkey.ahk` in the directory where the AutoHotkey executable resides. The path to this directory is stored in the `A_ScriptDir` built-in variable, and can be referenced as `%A_ScriptDir%`.
136 |
137 | Refer to the following link for a tutorial on how to use AutoHotkey:
138 |
139 | * AutoHotkey Biginner Tutorial
140 | * https://autohotkey.com/docs/Tutorial.htm
141 |
142 | ## Notes
143 |
144 | ### How to prevent "key slips" when holding down keys
145 |
146 | "Key slips" may occur when holding down keys. For example, when holding down `C-f`, the letter `f` may slip and appear on its own in the output, or the original Windows keymap gets incorrectly passed and the search box may pop up. These symptoms can be suppressed by lowering the Repeat Rate of the keyboard in Control Panel.
147 |
148 | ### How to prevent certain applications from getting affected by this script
149 |
150 | Add the `ahk_class` value of such applications to the `m_IgnoreList` list in the `m_IsEnabled` function. The `ahk_class` value of each application can be identified using Window Spy (`AU3_Spy.exe`) that comes with AutoHotkey.
151 |
152 | The default ignore list includes `Emacs`, `Vim` (GVim), and `mintty` (Cygwin Terminal).
153 |
154 | ```ahk
155 | m_IsEnabled() {
156 | global
157 | ;; List of applications to be ignored by this script
158 | ;; (Add applications as needed)
159 | ;; Emacs - NTEmacs
160 | ;; Vim - GVim
161 | ;; mintty - Cygwin
162 | m_IgnoreList := ["Emacs", "Vim", "mintty"]
163 | for index, element in m_IgnoreList
164 | {
165 | IfWinActive ahk_class %element%
166 | Return 0
167 | }
168 | ```
169 |
170 | ### How to suspend and resume the execution of this script
171 |
172 | `C-M-q` works as a toggle switch to suspend and resume the execution of this script. Pressing `C-M-q` is the same as selecting "Suspend Hotkeys" from the right-click menu in the AutoHotkey task bar icon.
173 |
174 | ### Sometimes it may not work as expected...
175 |
176 | It is a limitation of this script. The porpuse of this script is just to make Windows a little more comfortable to use, not to perfectly emulate Emacs functionality. Also feel free to modify this script as fits your needs.
177 |
--------------------------------------------------------------------------------