├── 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 | 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 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 |
バッファとファイル選択、削除、コピー・ペースト
C-x C-ffind-fileC-SPCset-mark-command
C-x C-ssave-bufferC-x hmark-whole-buffer
C-x C-wwrite-fileC-x C-pmark-page
C-x kkill-bufferC-ddelete-char
C-x C-ckill-emacsC-bdelete-backward-char
カーソル移動C-kkill-line
C-fforward-charC-wkill-region
C-bbackward-charM-wkill-ring-save
C-nnext-lineC-yyank
C-pprevious-line検索
M-fforward-char x 5 [*1]C-sisearch-forward [*2]
M-bbackward-char x 5 [*1]C-risearch-forward [*2]
M-nnext-line x 5 [*1]アンドゥ、キャンセル
M-pprevious-line x 5 [*1]C-/undo
C-amove-beginning-of-lineC-x uundo
C-emove-end-of-lineC-gkeyboard-quit
C-vscroll-downその他
M-vscroll-upC-mnew-line
M-<beginning-of-bufferC-iindent-for-tab-command
M->end-of-bufferC-jnew-line
言語入力システム切替C-oopen-line
C-x C-jtoggle-input-methodC-ttranspose-chars
C-\toggle-input-method
Microsoft Excel、Google スプレッドシート[*3]
C-c a選択されたセルを活性化しカーソルを最後に移す (Append) (F2)
C-c i選択されたセルを活性化しカーソルを最初に移す (Insert) (F2 + Home)
C-q プレフィックス: 一時的に Emacs キーバインディングを無効化[*4]
C-q C-a(すべて選択) [*5]C-q C-n(新規ウィンドウ) [*6]
C-q C-p(印刷)
C-M キー: 管理用キー
C-M-qスクリプト実行の停止と再開の切替
C-M-zフォーカスされているアプリケーションでキーバインドが有効化されるかどうかの確認
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 | 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 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 |
Buffers and FilesSelect, Delete, Copy & Paste
C-x C-ffind-fileC-SPCset-mark-command
C-x C-ssave-bufferC-x hmark-whole-buffer
C-x C-wwrite-fileC-x C-pmark-page
C-x kkill-bufferC-ddelete-char
C-x C-ckill-emacsC-bdelete-backward-char
Cursor MotionC-kkill-line
C-fforward-charC-wkill-region
C-bbackward-charM-wkill-ring-save
C-nnext-lineC-yyank
C-pprevious-lineSearch
M-fforward-char x 5 [*1]C-sisearch-forward [*2]
M-bbackward-char x 5 [*1]C-risearch-forward [*2]
M-nnext-line x 5 [*1]Undo, Cancel
M-pprevious-line x 5 [*1]C-/undo
C-amove-beginning-of-lineC-x uundo
C-emove-end-of-lineC-gkeyboard-quit
C-vscroll-downOthers
M-vscroll-upC-mnew-line
M-<beginning-of-bufferC-iindent-for-tab-command
M->end-of-bufferC-jnew-line
Input Method SwitchingC-oopen-line
C-x C-jtoggle-input-methodC-ttranspose-chars
C-\toggle-input-method
Microsoft Excel, Google Sheets [*3]
C-c aActivates the selected cell with the cursor at the end (Append) (F2)
C-c iActivates the selected cell with the cursor at the beginning (Insert) (F2 + Home)
C-q prefix: Temporarily disabling Emacs keybindings[*4]
C-q C-a(Select All) [*5]C-q C-n(New Window) [*6]
C-q C-p(Print)
C-M keys: Special keys for administration
C-M-qSuspends or resumes the execution of this script
C-M-zTells whether the implemented keybindings should be enabled or not for the application you are on
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 | --------------------------------------------------------------------------------