xtonhasvim.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  1. /* Copyright 2015-2017 Christon DeWan
  2. *
  3. * This program is free software: you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation, either version 2 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include "xtonhasvim.h"
  17. /************************************
  18. * helper foo
  19. ************************************/
  20. #define PRESS(kc) register_code(kc)
  21. #define RELEASE(kc) unregister_code(kc)
  22. static void TAP(uint16_t keycode) {
  23. PRESS(keycode);
  24. RELEASE(keycode);
  25. }
  26. static void CMD(uint16_t keycode) {
  27. PRESS(KC_LGUI);
  28. TAP(keycode);
  29. RELEASE(KC_LGUI);
  30. }
  31. static void CTRL(uint16_t keycode) {
  32. PRESS(KC_LCTRL);
  33. TAP(keycode);
  34. RELEASE(KC_LCTRL);
  35. }
  36. static void SHIFT(uint16_t keycode) {
  37. PRESS(KC_LSHIFT);
  38. TAP(keycode);
  39. RELEASE(KC_LSHIFT);
  40. }
  41. static void ALT(uint16_t keycode) {
  42. PRESS(KC_LALT);
  43. TAP(keycode);
  44. RELEASE(KC_LALT);
  45. }
  46. uint16_t vstate = VIM_START;
  47. bool yank_was_lines = false;
  48. bool SHIFTED = false;
  49. uint32_t mod_override_layer_state = 0;
  50. uint16_t mod_override_triggering_key = 0;
  51. bool do_check_kb_clear = false;
  52. void vim_reset(void) {
  53. vstate = VIM_START;
  54. SHIFTED = false;
  55. yank_was_lines = false;
  56. }
  57. void edit(void) { vstate = VIM_START; layer_on(_EDIT); layer_off(_CMD); }
  58. #define EDIT edit()
  59. void simple_movement(uint16_t keycode) {
  60. switch(keycode) {
  61. case VIM_B:
  62. PRESS(KC_LALT);
  63. SHIFT(KC_LEFT); // select to start of this word
  64. RELEASE(KC_LALT);
  65. break;
  66. case VIM_E:
  67. PRESS(KC_LALT);
  68. SHIFT(KC_RIGHT); // select to end of this word
  69. RELEASE(KC_LALT);
  70. break;
  71. case VIM_H:
  72. SHIFT(KC_LEFT);
  73. break;
  74. case VIM_J:
  75. CMD(KC_LEFT);
  76. SHIFT(KC_DOWN);
  77. SHIFT(KC_DOWN);
  78. break;
  79. case VIM_K:
  80. CMD(KC_LEFT);
  81. TAP(KC_DOWN);
  82. SHIFT(KC_UP);
  83. SHIFT(KC_UP);
  84. break;
  85. case VIM_L:
  86. SHIFT(KC_RIGHT);
  87. break;
  88. case VIM_W:
  89. PRESS(KC_LALT);
  90. SHIFT(KC_RIGHT); // select to end of this word
  91. SHIFT(KC_RIGHT); // select to end of next word
  92. SHIFT(KC_LEFT); // select to start of next word
  93. RELEASE(KC_LALT);
  94. break;
  95. }
  96. }
  97. bool process_record_xtonhasvim(uint16_t keycode, keyrecord_t *record) {
  98. if(record->event.pressed && layer_state_is(_CMD) && IS_MOD(keycode)) {
  99. mod_override_layer_state = layer_state;
  100. mod_override_triggering_key = keycode;
  101. layer_clear();
  102. return true; // let the event fall through...
  103. }
  104. if(mod_override_layer_state && !record->event.pressed && keycode == mod_override_triggering_key) {
  105. layer_state_set(mod_override_layer_state);
  106. mod_override_layer_state = 0;
  107. mod_override_triggering_key = 0;
  108. return true;
  109. }
  110. if (VIM_START <= keycode && keycode <= VIM_ESC) {
  111. if(keycode == VIM_SHIFT) {
  112. SHIFTED = record->event.pressed;
  113. return false;
  114. }
  115. if (record->event.pressed) {
  116. if(keycode == VIM_START) {
  117. // entry from anywhere
  118. layer_on(_CMD);
  119. vstate = VIM_START;
  120. return false;
  121. }
  122. switch(vstate) {
  123. case VIM_START:
  124. switch(keycode){
  125. /*****************************
  126. * ground state
  127. *****************************/
  128. case VIM_A:
  129. if(SHIFTED) {
  130. // CMD(KC_RIGHT);
  131. CTRL(KC_E);
  132. } else {
  133. TAP(KC_RIGHT);
  134. }
  135. EDIT;
  136. break;
  137. case VIM_B:
  138. PRESS(KC_LALT);
  139. PRESS(KC_LEFT);
  140. break;
  141. case VIM_C:
  142. if(SHIFTED) {
  143. PRESS(KC_LSHIFT);
  144. CMD(KC_RIGHT);
  145. RELEASE(KC_LSHIFT);
  146. CMD(KC_X);
  147. yank_was_lines = false;
  148. EDIT;
  149. } else {
  150. vstate = VIM_C;
  151. }
  152. break;
  153. case VIM_D:
  154. if(SHIFTED) {
  155. TAP(KC_K);
  156. } else {
  157. vstate = VIM_D;
  158. }
  159. break;
  160. case VIM_E:
  161. PRESS(KC_LALT);
  162. PRESS(KC_RIGHT);
  163. break;
  164. case VIM_G:
  165. if(SHIFTED) {
  166. TAP(KC_END);
  167. } else {
  168. vstate = VIM_G;
  169. }
  170. break;
  171. case VIM_H:
  172. PRESS(KC_LEFT);
  173. break;
  174. case VIM_I:
  175. if(SHIFTED){
  176. CTRL(KC_A);
  177. }
  178. EDIT;
  179. break;
  180. case VIM_J:
  181. if(SHIFTED) {
  182. CMD(KC_RIGHT);
  183. TAP(KC_DEL);
  184. } else {
  185. PRESS(KC_DOWN);
  186. }
  187. break;
  188. case VIM_K:
  189. PRESS(KC_UP);
  190. break;
  191. case VIM_L:
  192. PRESS(KC_RIGHT);
  193. break;
  194. case VIM_O:
  195. if(SHIFTED) {
  196. CMD(KC_LEFT);
  197. TAP(KC_ENTER);
  198. TAP(KC_UP);
  199. EDIT;
  200. } else {
  201. CMD(KC_RIGHT);
  202. TAP(KC_ENTER);
  203. EDIT;
  204. }
  205. break;
  206. case VIM_P:
  207. if(SHIFTED) {
  208. CMD(KC_LEFT);
  209. CMD(KC_V);
  210. } else {
  211. if(yank_was_lines) {
  212. CMD(KC_RIGHT);
  213. TAP(KC_RIGHT);
  214. CMD(KC_V);
  215. } else {
  216. CMD(KC_V);
  217. }
  218. }
  219. break;
  220. case VIM_S:
  221. // s for substitute?
  222. if(SHIFTED) {
  223. CMD(KC_LEFT);
  224. PRESS(KC_LSHIFT);
  225. CMD(KC_RIGHT);
  226. RELEASE(KC_LSHIFT);
  227. CMD(KC_X);
  228. yank_was_lines = false;
  229. EDIT;
  230. } else {
  231. SHIFT(KC_RIGHT);
  232. CMD(KC_X);
  233. yank_was_lines = false;
  234. EDIT;
  235. }
  236. break;
  237. case VIM_U:
  238. if(SHIFTED) {
  239. PRESS(KC_LSFT);
  240. CMD(KC_Z);
  241. RELEASE(KC_LSHIFT);
  242. } else {
  243. CMD(KC_Z);
  244. }
  245. break;
  246. case VIM_V:
  247. if(SHIFTED) {
  248. CMD(KC_LEFT);
  249. SHIFT(KC_DOWN);
  250. vstate = VIM_VS;
  251. } else {
  252. vstate = VIM_V;
  253. }
  254. break;
  255. case VIM_W:
  256. PRESS(KC_LALT);
  257. TAP(KC_RIGHT);
  258. TAP(KC_RIGHT);
  259. TAP(KC_LEFT);
  260. RELEASE(KC_LALT);
  261. break;
  262. case VIM_X:
  263. // SHIFT(KC_RIGHT);
  264. // CMD(KC_X);
  265. PRESS(KC_DEL);
  266. break;
  267. case VIM_Y:
  268. if(SHIFTED) {
  269. CMD(KC_LEFT);
  270. SHIFT(KC_DOWN);
  271. CMD(KC_C);
  272. TAP(KC_RIGHT);
  273. yank_was_lines = true;
  274. } else {
  275. vstate = VIM_Y;
  276. }
  277. break;
  278. case VIM_COMMA:
  279. if(SHIFTED) {
  280. // indent
  281. CMD(KC_LBRACKET);
  282. } else {
  283. // toggle comment
  284. CMD(KC_SLASH);
  285. }
  286. break;
  287. case VIM_PERIOD:
  288. if(SHIFTED) {
  289. // outdent
  290. CMD(KC_RBRACKET);
  291. }
  292. break;
  293. }
  294. break;
  295. case VIM_C:
  296. /*****************************
  297. * c- ...for change. I never use this...
  298. *****************************/
  299. switch(keycode) {
  300. case VIM_B:
  301. case VIM_E:
  302. case VIM_H:
  303. case VIM_J:
  304. case VIM_K:
  305. case VIM_L:
  306. case VIM_W:
  307. simple_movement(keycode);
  308. CMD(KC_X);
  309. yank_was_lines = false;
  310. EDIT;
  311. break;
  312. case VIM_C:
  313. CMD(KC_LEFT);
  314. PRESS(KC_LSHIFT);
  315. CMD(KC_RIGHT);
  316. RELEASE(KC_LSHIFT);
  317. CMD(KC_X);
  318. yank_was_lines = false;
  319. EDIT;
  320. break;
  321. case VIM_I:
  322. vstate = VIM_CI;
  323. break;
  324. default:
  325. vstate = VIM_START;
  326. break;
  327. }
  328. break;
  329. case VIM_CI:
  330. /*****************************
  331. * ci- ...change inner word
  332. *****************************/
  333. switch(keycode) {
  334. case VIM_W:
  335. ALT(KC_LEFT);
  336. PRESS(KC_LSHIFT);
  337. ALT(KC_RIGHT);
  338. RELEASE(KC_LSHIFT);
  339. CMD(KC_X);
  340. yank_was_lines = false;
  341. EDIT;
  342. default:
  343. vstate = VIM_START;
  344. break;
  345. }
  346. break;
  347. case VIM_D:
  348. /*****************************
  349. * d- ...delete stuff
  350. *****************************/
  351. switch(keycode) {
  352. case VIM_B:
  353. case VIM_E:
  354. case VIM_H:
  355. case VIM_J:
  356. case VIM_K:
  357. case VIM_L:
  358. case VIM_W:
  359. simple_movement(keycode);
  360. CMD(KC_X);
  361. yank_was_lines = false;
  362. break;
  363. case VIM_D:
  364. CMD(KC_LEFT);
  365. SHIFT(KC_DOWN);
  366. CMD(KC_X);
  367. yank_was_lines = true;
  368. vstate = VIM_START;
  369. break;
  370. case VIM_I:
  371. vstate = VIM_DI;
  372. break;
  373. default:
  374. vstate = VIM_START;
  375. break;
  376. }
  377. break;
  378. case VIM_DI:
  379. /*****************************
  380. * ci- ...delete a word... FROM THE INSIDE!
  381. *****************************/
  382. switch(keycode) {
  383. case VIM_W:
  384. ALT(KC_LEFT);
  385. PRESS(KC_LSHIFT);
  386. ALT(KC_RIGHT);
  387. RELEASE(KC_LSHIFT);
  388. CMD(KC_X);
  389. yank_was_lines = false;
  390. vstate = VIM_START;
  391. default:
  392. vstate = VIM_START;
  393. break;
  394. }
  395. break;
  396. case VIM_V:
  397. /*****************************
  398. * visual!
  399. *****************************/
  400. switch(keycode) {
  401. case VIM_D:
  402. case VIM_X:
  403. CMD(KC_X);
  404. yank_was_lines = false;
  405. vstate = VIM_START;
  406. break;
  407. case VIM_B:
  408. PRESS(KC_LALT);
  409. PRESS(KC_LSHIFT);
  410. PRESS(KC_LEFT);
  411. // leave open for key repeat
  412. break;
  413. case VIM_E:
  414. PRESS(KC_LALT);
  415. PRESS(KC_LSHIFT);
  416. PRESS(KC_RIGHT);
  417. // leave open for key repeat
  418. break;
  419. case VIM_H:
  420. PRESS(KC_LSHIFT);
  421. PRESS(KC_LEFT);
  422. break;
  423. case VIM_I:
  424. vstate = VIM_VI;
  425. break;
  426. case VIM_J:
  427. PRESS(KC_LSHIFT);
  428. PRESS(KC_DOWN);
  429. break;
  430. case VIM_K:
  431. PRESS(KC_LSHIFT);
  432. PRESS(KC_UP);
  433. break;
  434. case VIM_L:
  435. PRESS(KC_LSHIFT);
  436. PRESS(KC_RIGHT);
  437. break;
  438. case VIM_W:
  439. PRESS(KC_LALT);
  440. SHIFT(KC_RIGHT); // select to end of this word
  441. SHIFT(KC_RIGHT); // select to end of next word
  442. SHIFT(KC_LEFT); // select to start of next word
  443. RELEASE(KC_LALT);
  444. break;
  445. case VIM_Y:
  446. CMD(KC_C);
  447. TAP(KC_RIGHT);
  448. yank_was_lines = false;
  449. vstate = VIM_START;
  450. break;
  451. case VIM_V:
  452. case VIM_ESC:
  453. TAP(KC_RIGHT);
  454. vstate = VIM_START;
  455. break;
  456. default:
  457. // do nothing
  458. break;
  459. }
  460. break;
  461. case VIM_VI:
  462. /*****************************
  463. * vi- ...select a word... FROM THE INSIDE!
  464. *****************************/
  465. switch(keycode) {
  466. case VIM_W:
  467. ALT(KC_LEFT);
  468. PRESS(KC_LSHIFT);
  469. ALT(KC_RIGHT);
  470. RELEASE(KC_LSHIFT);
  471. vstate = VIM_V;
  472. default:
  473. // ignore
  474. vstate = VIM_V;
  475. break;
  476. }
  477. break;
  478. case VIM_VS:
  479. /*****************************
  480. * visual line
  481. *****************************/
  482. switch(keycode) {
  483. case VIM_D:
  484. case VIM_X:
  485. CMD(KC_X);
  486. yank_was_lines = true;
  487. vstate = VIM_START;
  488. break;
  489. case VIM_J:
  490. PRESS(KC_LSHIFT);
  491. PRESS(KC_DOWN);
  492. break;
  493. case VIM_K:
  494. PRESS(KC_LSHIFT);
  495. PRESS(KC_UP);
  496. break;
  497. case VIM_Y:
  498. CMD(KC_C);
  499. yank_was_lines = true;
  500. TAP(KC_RIGHT);
  501. vstate = VIM_START;
  502. break;
  503. case VIM_V:
  504. case VIM_ESC:
  505. TAP(KC_RIGHT);
  506. vstate = VIM_START;
  507. break;
  508. default:
  509. // do nothing
  510. break;
  511. }
  512. break;
  513. case VIM_G:
  514. /*****************************
  515. * gg, and a grab-bag of other macros i find useful
  516. *****************************/
  517. switch(keycode) {
  518. case VIM_G:
  519. TAP(KC_HOME);
  520. break;
  521. // codes b
  522. case VIM_H:
  523. CTRL(KC_A);
  524. break;
  525. case VIM_J:
  526. PRESS(KC_PGDN);
  527. break;
  528. case VIM_K:
  529. PRESS(KC_PGUP);
  530. break;
  531. case VIM_L:
  532. CTRL(KC_E);
  533. break;
  534. default:
  535. // do nothing
  536. break;
  537. }
  538. vstate = VIM_START;
  539. break;
  540. case VIM_Y:
  541. /*****************************
  542. * yoink!
  543. *****************************/
  544. switch(keycode) {
  545. case VIM_B:
  546. case VIM_E:
  547. case VIM_H:
  548. case VIM_J:
  549. case VIM_K:
  550. case VIM_L:
  551. case VIM_W:
  552. simple_movement(keycode);
  553. CMD(KC_C);
  554. TAP(KC_RIGHT);
  555. yank_was_lines = false;
  556. break;
  557. case VIM_Y:
  558. CMD(KC_LEFT);
  559. SHIFT(KC_DOWN);
  560. CMD(KC_C);
  561. TAP(KC_RIGHT);
  562. yank_was_lines = true;
  563. break;
  564. default:
  565. // NOTHING
  566. break;
  567. }
  568. vstate = VIM_START;
  569. break;
  570. }
  571. } else {
  572. /************************
  573. * key release events
  574. ************************/
  575. clear_keyboard();
  576. }
  577. return false;
  578. } else {
  579. return true;
  580. }
  581. }