home *** CD-ROM | disk | FTP | other *** search
/ DOS/V Power Report 1997 May / VPR9705A.ISO / OLS / Os2 / MYKBD03 / MYKBD03.LZH / MYKBD.C < prev    next >
C/C++ Source or Header  |  1996-01-04  |  22KB  |  805 lines

  1. /* mykbd.c : Ver. 0.3 */
  2. /* Copyright (C) K.Yoshizawa 1996 */
  3.  
  4. /*==========================================================================
  5.  
  6. ●対応コンパイラ
  7.  
  8. このプログラムは、ごく一部を除いて、 ANSI-C で書かれています。
  9.  
  10. ANSI-Cにしたがっていないのは、『一文字入力、即リターン』のための getch() だけ
  11. です。その部分さえ修正すれば、どのような ANSI-C 対応のコンパイラでも使用可能
  12. だと思います。
  13.  
  14. ●コーディング スタイル
  15.  
  16. 1 TAB = 4 SPACE を仮定しています。main() はファイルの最後に置いてあります。
  17.  
  18. ●下手糞な点
  19.  
  20. さほど汎用性を持たせるつもりもないので、「決め打ち」しまくってます。
  21.  
  22. ●履歴
  23.  
  24. Ver.    DATE        COMMENT
  25. 0.3        1996/01/05    最初の公開バージョン
  26.  
  27. ============================================================================*/
  28.  
  29. /****************************************************************************/
  30. /*    includeファイル                                                    */
  31. /****************************************************************************/
  32.  
  33. /* ANSI-C 標準ヘッダー ファイル */
  34. #include <stdio.h>
  35. #include <stdlib.h>
  36. #include <string.h>
  37.  
  38. /* Borland C 固有のヘッダー ファイル */
  39. #include <conio.h>    /* for getch() */
  40.  
  41. /****************************************************************************/
  42. /*    共通定義                                                                */
  43. /****************************************************************************/
  44.  
  45. typedef unsigned char BYTE;
  46. typedef unsigned short WORD;
  47.  
  48. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
  49.  
  50. /* IBMKBD.SYS を読み込むためのバッファの大きさ */
  51. #define KBD_BUF_SIZE 0x4000
  52.  
  53. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
  54.  
  55. /* スキャンコード入れ替えの最大個数 */
  56. #define MAX_N_SWAP    256
  57.  
  58. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
  59.  
  60. /* パッチ ルーチンの最大長 */
  61. /* オーバーフローはチェックしてないので、十分大きく確保すること */
  62. #define MAX_PATCH_SIZE    1024
  63.  
  64. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
  65.  
  66. /* NEW EXE ヘッダへアクセスするためのマクロ */
  67. /* 途中でめんどうになったので、全部は作ってない */
  68. #define SEG_TBL_OFS(BUF)    (*(WORD*)&(BUF)[0x80+0x22]+0x80)
  69. #define SEG_TBL_CNT(BUF)    (*(WORD*)&(BUF)[0x80+0x1c])
  70. #define SECT_SIZE(BUF)        (1<<(*(WORD*)&(BUF)[0x80+0x32]))
  71.  
  72. #define SEG_OFS(BUF,N)         (*(WORD*)&(BUF)[SEG_TBL_OFS(BUF)+(N)*8]*\
  73.                             SECT_SIZE(BUF))
  74. #define SEG_FILE(BUF,N)        (*(WORD*)&(BUF)[SEG_TBL_OFS(BUF)+(N)*8+2])
  75. #define SEG_FLAG(BUF,N)        (*(WORD*)&(BUF)[SEG_TBL_OFS(BUF)+(N)*8+4])
  76. #define SEG_ALLOC(BUF,N)    (*(WORD*)&(BUF)[SEG_TBL_OFS(BUF)+(N)*8+6])
  77.  
  78. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
  79.  
  80. #define PRINTF if(verbose) printf
  81. #define FFLUSH if(verbose) fflush
  82.  
  83. /****************************************************************************/
  84. /*    グローバル変数群                                                        */
  85. /****************************************************************************/
  86.  
  87. static int verbose = 0;        /* DEBUG 時は 1 にすると各種メッセージ出力 */
  88.  
  89. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
  90.  
  91. /* IBMKBD.SYS & MYKBD.SYS のためのバッファ */
  92. static BYTE kbd_buf[KBD_BUF_SIZE];
  93. static int org_size;
  94. static int new_size;
  95.  
  96. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
  97.  
  98. /* DATA / CODE セグメントのセグメントNo. */
  99. static int data_seg, code_seg;
  100.  
  101. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
  102.  
  103. /* I/O port 60H からデータを読み込んでいる部分のマシン語のパターン。 */
  104. static WORD in_60_pat[] = {
  105.     0xe4, 0x60,            /* in al,60h        */
  106.     0x88, 0x46, 0xfe,    /* mov [bp-2], al    */
  107. };
  108.  
  109. /* パッチをあてる場所 */
  110. #define IN_60_PAT_OFS    2
  111.  
  112. /* 上のパータンのあったアドレス(-1は未発見を意味する) */
  113. static in_60_ofs = -1;
  114.  
  115. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
  116.  
  117. /* デバイス ドライバ に対する init 命令の最後で、コード セグメントとデータ */
  118. /* セグメントの切り離しアドレスをセットしている部分のマシン語のパターン。 */
  119. /* 0xffff は、その 1 バイトの値が不定であることを示す。 */
  120. static WORD limit_addr_pat[] =
  121. {
  122.     0xc4, 0x5e, 0xfc,        /* les bx,ss:[-04+bp] */
  123.     0x26, 0xc7, 0x47, 0x0e,    /* mov word ptr es:[bx+0eh], NNNN */
  124.     0xffff, 0xffff,
  125.     0x26, 0xc7, 0x47, 0x10,    /* mov word ptr es:[bx+10h], NNNN */
  126.     0xffff, 0xffff,
  127. };
  128.  
  129. /* 上の NNNN の各バイト位置 */
  130. #define CODE_LIMIT_LO    7
  131. #define CODE_LIMIT_HI    8
  132. #define DATA_LIMIT_LO    13
  133. #define DATA_LIMIT_HI    14
  134.  
  135. /* 上のパータンのあったアドレス(-1は未発見を意味する) */
  136. static limit_addr_ofs = -1;
  137.  
  138. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
  139.  
  140. /* スキャンコード入れ替えテーブル */
  141.  
  142. static BYTE swap_table[MAX_N_SWAP][2];
  143. static int n_swap;
  144.  
  145. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
  146.  
  147. /* パッチ ルーチンの一時置き場 */
  148. static BYTE patch_buf[MAX_PATCH_SIZE];
  149. static int patch_size;
  150.  
  151. /****************************************************************************/
  152. /*    タイトル、使用法、その他ユーザインターフェース系の関数群                */
  153. /****************************************************************************/
  154.  
  155. static
  156. void title(void)
  157. {
  158.     printf(
  159. "\n"
  160. "mykbd : Keyboard Layout Configuration Utility (Ver. 0.3)\n"
  161. "Copyright (C) K.Yoshizawa 1996\n"
  162. "\n"
  163. "--- This utility must be run under DOS/V window ---\n"
  164. "\n"
  165.     );
  166. }
  167.  
  168. static
  169. void pause(void)
  170. {
  171.     printf(
  172. "    >>続きがあります。【Enter(←┘)】を押してください。(【ESC】で中断)\n"
  173.     );
  174.     for (;;) {
  175.         switch (getch()) {
  176.         case 0x0d:            /* CR */
  177.         case 0x0a:            /* NL(LF) */
  178.             return;
  179.         case 0x1b:            /* ESC */
  180.         case 0x03:            /* CTRL-C */
  181.             exit(1);
  182.             break;            /* dummy break */
  183.         }
  184.     }
  185. }
  186.  
  187. static
  188. void usage(void)
  189. {
  190.     printf(
  191. "\n"
  192. "●概要\n"
  193. "  OS/2 Warp のキーボード ドライバ IBMKBD.SYS を解析・変更して、\n"
  194. "\n"
  195. "    【左CTRL】<->【CapsLock】、【ESC】<->【半角/全角】\n"
  196. "\n"
  197. "  などのキーの入れ替え機能を持った MYKBD.SYS を生成します。\n"
  198. "\n"
  199. "  OADG 106 日本語キーボードが対象ですが、他のキーボード(例えば 101 英語キー\n"
  200. "  ボード)などでも動作するでしょう。\n"
  201. "\n"
  202.     );
  203.     pause();
  204.     printf(
  205. "\n"
  206. "●無保証\n"
  207. "  このソフトウェアは無保証です。このソフトウェアによっていかなる事態が発\n"
  208. "  生しようとも、当方はいっさい関知しません。あくまでも、自己の責任と危険\n"
  209. "  負担のもとに使用してください。また、このソフトウェアに関するサポート、\n"
  210. "  質問に対する回答などを行うことも、いっさいお約束できません。\n"
  211. "  以上の事項に同意できない場合は、このソフトウェアの使用を中止してくださ\n"
  212. "  い。\n"
  213. "\n"
  214. "●再配布\n"
  215. "  このソフトウェアはフリーソフトウェアです。配布ファイルに変更を加えない\n"
  216. "  限り、自由に再配布してかまいません。\n"
  217. "  変更を加えた場合は、変更の内容と変更者を特定するに十分な情報を添付する\n"
  218. "  ならば、特に私の許可を得ずとも、自由に再配布してかまいません。(このユー\n"
  219. "  ティリティの能力や対応範囲を広げるための変更は、大歓迎です。)\n"
  220. "  これ以外の形態の再配布は禁止します。\n"
  221. "\n"
  222.     );
  223.     pause();
  224.     printf(
  225. "\n"
  226. "●使い方\n"
  227. "(1) 既に MYKBD.SYS を使用している場合は、いったん CONFIG.SYS を元に戻して\n"
  228. "    再起動してください。(使用していなければ、何もする必要はありません。)\n"
  229. "\n"
  230. "(2) OS/2 Warp の CD-ROM、または、フロッピー(IBMKBD.SYS が入っているもの)\n"
  231. "    をセットして、次のようにタイプしてください。\n"
  232. "\n"
  233. "      C>MYKBD  OS/2のディレクトリ  IBMKBD.SYSのありか  変更データファイル\n"
  234. "\n"
  235. "      ◎OS/2のディレクトリ\n"
  236. "        OS/2 Warp をインストールしたディレクトリを指定します。\n"
  237. "      ◎IBMKBD.SYSのありか\n"
  238. "        CD-ROM またはフロッピーの中の IBMKBD.SYS へのパスを指定します。\n"
  239. "      ◎変更データファイル\n"
  240. "        どのキーを入れ替えるのかを記述したファイルを指定します。あらかじ\n"
  241. "        め用意してあるのは、次の二つです。\n"
  242. "          ・CTRL.DAT    :【左CTRL】<->【CapsLock】\n"
  243. "          ・ESC.DAT     :【ESC】<->【半角/全角】\n"
  244. "        複数のファイルを組み合わせて指定することもできます。\n"
  245. "\n"
  246.     );
  247.     pause();
  248.     printf(
  249. "\n"
  250. "(3) OS/2 のディレクトリの下のサブディレクトリ BOOT に、キー入れ替え用に\n"
  251. "    変更された新しいキーボード ドライバ MYKBD.SYS が作成されるはずです。\n"
  252. "    CONFIG.SYS で次のような行を探し、\n"
  253. "\n"
  254. "      BASEDEV=IBMKBD.SYS\n"
  255. "\n"
  256. "    下のように変更してください。\n"
  257. "\n"
  258. "      BASEDEV=MYKBD.SYS\n"
  259. "\n"
  260. "    そして、OS/2 をハードディスクから再起動してください。これでキーが入れ\n"
  261. "    替わるはずです。\n"
  262. "\n"
  263. "(4) うまくいかない場合は、OS/2 をフロッピーから起動して、上で行った\n"
  264. "     CONFIG.SYS の変更を元に戻してください。起動用のフロッピーとしては、\n"
  265. "   「ユーティリティ ディスケット」として作成したフロッピーが使えます。事\n"
  266. "    前に作成しておくことを、お勧めします。\n"
  267. "\n"
  268.     );
  269.     pause();
  270.     printf(
  271. "\n"
  272. "●制約\n"
  273. "(1) キー入れ替えの効果は、システム全体におよびます。したがって、『複数人\n"
  274. "    で一台のマシンを共用しているので、人によって入れ替えをキャンセルした\n"
  275. "    い』などと言われても、それはできません。\n"
  276. "\n"
  277. "(2) OS/2 Warp の Ver.3.00 と 3.01 で動作確認しています。しかし、これ以外\n"
  278. "    の版の OS/2 でうまくいく保証はありません。もし、『解析失敗』または\n"
  279. "    『変更失敗』のエラーメッセージが出てしまったら、プログラム(MYKBD.C)を\n"
  280. "    修正するか、それができない方は、あきらめてください。\n"
  281. "\n"
  282. "●例\n"
  283. "  この例では、C:\\OS2 が OS/2 Warp をインスートルしたディレクトリ、E:ドラ\n"
  284. "  イブが CD-ROM で、【左CTRL】<->【CapsLock】、【ESC】<->【半角/全角】の\n"
  285. "  双方を入れ替えています。\n"
  286. "\n"
  287. "     C>MYKBD C:\\OS2 E:\\OS2IMAGE\\DISK_1\\IBMKBD.SYS CTRL.DAT ESC.DAT\n"
  288. "\n"
  289.     );
  290. }
  291.  
  292. /****************************************************************************/
  293. /*    ファイル入出力関数群                                                    */
  294. /****************************************************************************/
  295.  
  296. static
  297. long load_binary_file(char *fname, BYTE *buf, int buf_size)
  298. {
  299.     long s;
  300.     FILE *fp;
  301.  
  302.     printf("ファイル '%s' 読み込み中 ... ", fname);
  303.     fflush(stdout);
  304.  
  305.     if ((fp = fopen(fname, "rb")) == NULL) {
  306.         printf("ファイルがオープンできません\n");
  307.         perror(fname);
  308.         return 0;
  309.     }
  310.  
  311.     s = fread(buf, 1, buf_size, fp);
  312.     if (s <= 0) {
  313.         printf("ファイルからデータが読めません\n");
  314.         perror(fname);
  315.         fclose(fp);
  316.         return 0;
  317.     }
  318.  
  319.     if ( ! feof(fp)) {
  320.         printf("ファイルが大きすぎます\n");
  321.         return 0;
  322.     }
  323.  
  324.     fclose(fp);
  325.  
  326.     printf("OK (size = 0x%04lx(%ld) byte)\n", s, s);
  327.  
  328.     return s;
  329. }
  330.  
  331. static
  332. long save_binary_file(char *fname, BYTE *buf, int data_size)
  333. {
  334.     long s;
  335.     FILE *fp;
  336.  
  337.     printf("ファイル '%s' 書き込み中 ... ", fname);
  338.     fflush(stdout);
  339.  
  340.     if ((fp = fopen(fname, "wb")) == NULL) {
  341.         printf("ファイルがオープンできません\n");
  342.         perror(fname);
  343.         return 0;
  344.     }
  345.  
  346.     s = fwrite(buf, 1, data_size, fp);
  347.     if (s != data_size) {
  348.         printf("ファイルにデータを書き込めません\n");
  349.         perror(fname);
  350.         fclose(fp);
  351.         return 0;
  352.     }
  353.  
  354.     fclose(fp);
  355.  
  356.     printf("OK (size = 0x%04lx(%ld) byte)\n", s, s);
  357.  
  358.     return s;
  359. }
  360.  
  361. static
  362. int load_swap_info_file(char *fname)
  363. {
  364.     FILE *fp;
  365.     char buf[256];
  366.     long lcount;
  367.  
  368.     printf("変更データ ファイル '%s' 読み込み中 ... ", fname);
  369.     fflush(stdout);
  370.  
  371.     if ((fp = fopen(fname, "rt")) == NULL) {
  372.         printf("ファイルがオープンできません\n");
  373.         perror(fname);
  374.         return 0;
  375.     }
  376.  
  377.     lcount = 0;
  378.  
  379.     PRINTF("\n");
  380.  
  381.     while (fgets(buf, sizeof(buf), fp) != NULL) {
  382.         char ch;
  383.         int b1, b2;
  384.  
  385.         lcount++;
  386.         if (sscanf(buf, "%1s", &ch) == 0 || ch == '#') continue;
  387.         if (sscanf(buf, "%x%x", &b1, &b2) != 2
  388.         || b1 < 0 || b1 > 0xff || b2 < 0 || b2 > 0xff) {
  389.             printf(
  390. "%s:%ld行目:書式エラー(入れ替え scan code の指定が不正)\n"
  391.             , fname, lcount);
  392.             fclose(fp);
  393.             return 0;
  394.         }
  395.         if (++n_swap >= MAX_N_SWAP) {
  396.             printf(
  397. "%s:%ld行目:入れ替えキーの個数が多すぎます(スキャン コードで最大 %d 個)\n"
  398.             , fname, lcount, MAX_N_SWAP);
  399.             fclose(fp);
  400.             return 0;
  401.         }
  402.         swap_table[n_swap-1][0] = b1;
  403.         swap_table[n_swap-1][1] = b2;
  404.         PRINTF("  %02x -> %02x\n"
  405.         , swap_table[n_swap-1][0] , swap_table[n_swap-1][1]);
  406.     }
  407.  
  408.     fclose(fp);
  409.  
  410.     printf("OK\n");
  411.  
  412.     return 1;
  413. }
  414.  
  415. /****************************************************************************/
  416. /*    デバイスドライバ解析関数群                                                */
  417. /****************************************************************************/
  418.  
  419. /* buf (buf_sizeバイト)の中の buf[base] 以降で pat (pat_sizeバイト)を探し */
  420. /* て、そのありかを返す。*/
  421. static
  422. int search_pat(BYTE *buf, int buf_size, int base, WORD *pat, int pat_size)
  423. {
  424.     int i, j;
  425.  
  426.     for (i = base; i < buf_size - pat_size; i++) {
  427.         for (j = 0; j < pat_size; j++) {
  428.             if ((pat[j] & 0xff00) != 0) continue;
  429.             if (buf[i + j] != pat[j]) break;
  430.         }
  431.         if (j == pat_size) return i;
  432.     }
  433.     return -1;
  434. }
  435.  
  436. static
  437. int analysis(void)
  438. {
  439.     int i;
  440.     int n_segs;
  441.     int seg_flag;
  442.     int pos;
  443.  
  444.     if ((n_segs = SEG_TBL_CNT(kbd_buf)) != 2) {
  445.         printf(
  446. "セグメントの個数が %d 個です。\n"
  447. "セグメントの個数は 2 個であることを仮定しています。\n"
  448.         , n_segs);
  449.         return 0;
  450.     }
  451.  
  452.     data_seg = code_seg = -1;
  453.     for (i = 0; i < n_segs; i++) {
  454.         PRINTF("SEGMENT #%04x\n", i);
  455.         seg_flag = SEG_FLAG(kbd_buf, i);
  456.         PRINTF("  FLAG       : %04x", seg_flag);
  457.         if ((seg_flag & 0x0007) == 0x0000) {
  458.             PRINTF(" CODE");
  459.             code_seg = i;
  460.         }
  461.         if ((seg_flag & 0x0007) == 0x0001) {
  462.             PRINTF(" DATA");
  463.             data_seg = i;
  464.         }
  465.         PRINTF("\n");
  466.         PRINTF("  OFFSET     : %04x\n", SEG_OFS(kbd_buf, i));
  467.         PRINTF("  FILE SIZE  : %04x\n", SEG_FILE(kbd_buf, i));
  468.         PRINTF("  ALLOC SIZE : %04x\n", SEG_ALLOC(kbd_buf, i));
  469.     }
  470.     if (data_seg != 0 || code_seg != 1) {
  471.         printf(
  472. "セグメントが次の順に並んでいることを仮定していますが、そうなっていません。\n"
  473. "  #0000 DATA セグメント\n"
  474. "  #0001 CODE セグメント\n"
  475.         );
  476.         return 0;
  477.     }
  478.  
  479.     PRINTF("I/O port 入力部分を探索中 ...");
  480.     FFLUSH(stdout);
  481.     for (
  482.         pos = 0;
  483.         (pos = search_pat(kbd_buf, org_size, pos, in_60_pat
  484.                             , sizeof(in_60_pat)/sizeof(in_60_pat[0]) )) >= 0;
  485.         pos++
  486.     ) {
  487.         PRINTF(" 発見(0x%04x)", pos);
  488.         FFLUSH(stdout);
  489.         if (in_60_ofs < 0) {
  490.             in_60_ofs = pos;
  491.         } else {
  492.             PRINTF(
  493. "複数の I/O port 入力部分があるため、どこを変更してよいのか分かりません。\n"
  494.             );
  495.             return 0;
  496.         }
  497.     }
  498.     if (in_60_ofs < 0) {
  499.         PRINTF("探索失敗\n");
  500.         return 0;
  501.     }
  502.     PRINTF(" ... OK\n");
  503.  
  504.     PRINTF("セグメント切り離しアドレス設定部分を探索中 ...");
  505.     FFLUSH(stdout);
  506.     for (
  507.         pos = 0;
  508.         (pos = search_pat(kbd_buf, org_size, pos, limit_addr_pat
  509.                     , sizeof(limit_addr_pat)/sizeof(limit_addr_pat[0]) )) >= 0;
  510.         pos++
  511.     ) {
  512.         if (kbd_buf[pos + CODE_LIMIT_HI] >= 0x0d
  513.         &&  kbd_buf[pos + CODE_LIMIT_HI] <= 0x10
  514.         ) {
  515.             PRINTF("発見(0x%04x)", pos);
  516.             FFLUSH(stdout);
  517.             if (limit_addr_ofs < 0) {
  518.                 limit_addr_ofs = pos;
  519.             } else {
  520.                 printf(
  521. "複数のセグメント上限設定部分らしきコードがあるため、どこを変更してよいのか\n"
  522. "分かりません。\n"
  523.                 );
  524.                 return 0;
  525.             }
  526.         }
  527.     }
  528.     if (limit_addr_ofs < 0) {
  529.         PRINTF("探索失敗\n");
  530.         return 0;
  531.     }
  532.     PRINTF(" ... OK\n");
  533.     PRINTF("  mov word ptr es:[bx+0eh], %02x%02xh\n"
  534.     , kbd_buf[limit_addr_ofs + CODE_LIMIT_HI]
  535.     , kbd_buf[limit_addr_ofs + CODE_LIMIT_LO]);
  536.     PRINTF("  mov word ptr es:[bx+10h], %02x%02xh\n"
  537.     , kbd_buf[limit_addr_ofs + DATA_LIMIT_HI]
  538.     , kbd_buf[limit_addr_ofs + DATA_LIMIT_LO]);
  539.  
  540.     return 1;
  541. }
  542.  
  543. /****************************************************************************/
  544. /*    デバイスドライバ変更(パッチあて)関数群                                    */
  545. /****************************************************************************/
  546.  
  547. static
  548. int generate(void)
  549. {
  550.     WORD SaveE0;
  551.     WORD patch_entry_ofs;
  552.     WORD new_code_seg_size;
  553.  
  554.     /* 一つの前のコードが E0 かどうか覚えておくための変数域を用意 */
  555.     {
  556.         SaveE0 = SEG_ALLOC(kbd_buf, data_seg);
  557.         SEG_ALLOC(kbd_buf, data_seg) += 2;
  558.         PRINTF("スキャン コード待避変数アドレス = 0x%04x\n", SaveE0);
  559.  
  560.         PRINTF("DATA セグメント切り離しアドレス 0x%04x ->"
  561.             , *(WORD*)&kbd_buf[limit_addr_ofs + DATA_LIMIT_LO]);
  562.         *(WORD*)&kbd_buf[limit_addr_ofs + DATA_LIMIT_LO]
  563.             = SEG_ALLOC(kbd_buf, data_seg);
  564.         PRINTF("0x%04x\n"
  565.             , *(WORD*)&kbd_buf[limit_addr_ofs + DATA_LIMIT_LO]);
  566.     }
  567.  
  568.     /* パッチ ルーチンを用意する。*/
  569.     {
  570.         int addr;    /* セグメント内アドレス(ファイル内オフセットとは異なる) */
  571.         WORD label1;
  572.         WORD ofs;
  573.         int i;
  574.  
  575.         addr = 0;
  576.  
  577.         label1 = 12 + n_swap * 9;
  578.  
  579.         patch_entry_ofs
  580.             = SEG_FILE(kbd_buf, code_seg) + SEG_OFS(kbd_buf, code_seg);
  581.  
  582.         /* 直前のスキャン コードが E0 なら現在のスキャン コードを素通し */
  583.         /* するためのルーチン (12 byte) */
  584.         patch_buf[addr++] = 0x50;    /* push ax */
  585.         patch_buf[addr++] = 0xa0;    /* mov al, [SaveE0] */
  586.         patch_buf[addr++] = SaveE0;
  587.         patch_buf[addr++] = SaveE0 >> 8;
  588.         patch_buf[addr++] = 0x3c;    /* cmp al, E0H */
  589.         patch_buf[addr++] = 0xe0;
  590.         patch_buf[addr++] = 0x58;    /* pop ax */
  591.         patch_buf[addr++] = 0x75;    /* jne +3*/
  592.         patch_buf[addr++] = 0x03;
  593.         ofs = label1 - (addr + 3);
  594.         patch_buf[addr++] = 0xe9;    /* jmp label1*/
  595.         patch_buf[addr++] = ofs;
  596.         patch_buf[addr++] = ofs >> 8;
  597.  
  598.         /* 各スキャン コードの入れ替えルーチン (9 byte)*/
  599.         for (i=0; i<n_swap; i++) {
  600.             patch_buf[addr++] = 0x3c;    /* cmp al,imm(original scan code) */
  601.             patch_buf[addr++] = swap_table[i][0];
  602.             patch_buf[addr++] = 0x75;    /* jne +5 */
  603.             patch_buf[addr++] = 0x05;
  604.             patch_buf[addr++] = 0xb0;    /* mov al,imm(new scan code) */
  605.             patch_buf[addr++] = swap_table[i][1];
  606.             ofs = label1 - (addr + 3);
  607.             patch_buf[addr++] = 0xe9;    /* jmp label1*/
  608.             patch_buf[addr++] = ofs;
  609.             patch_buf[addr++] = ofs >> 8;
  610.         }
  611.  
  612. /* ここが label1 の位置に相当 */
  613.  
  614.         /* 後始末ルーチン (9 byte) */
  615.         patch_buf[addr++] = 0xa2;    /* mov [SaveE0], al */
  616.         patch_buf[addr++] = SaveE0;
  617.         patch_buf[addr++] = SaveE0 >> 8;
  618.  
  619.         patch_buf[addr++] = kbd_buf[in_60_ofs + IN_60_PAT_OFS];
  620.         patch_buf[addr++] = kbd_buf[in_60_ofs + IN_60_PAT_OFS + 1];
  621.         patch_buf[addr++] = kbd_buf[in_60_ofs + IN_60_PAT_OFS + 2];
  622.  
  623.         ofs = (in_60_ofs + IN_60_PAT_OFS + 3) - (patch_entry_ofs + addr + 3);
  624.         patch_buf[addr++] = 0xe9;    /* jmp */
  625.         patch_buf[addr++] = ofs;
  626.         patch_buf[addr++] = ofs >> 8;
  627.  
  628.         while (addr % 2 != 0) patch_buf[addr++] = 0x90;    /* nop */
  629.  
  630.         patch_size = addr;
  631.  
  632.         PRINTF("パッチ ルーチン サイズ : 0x%04x(%d) byte\n"
  633.             , patch_size, patch_size);
  634.     }
  635.  
  636.     /* 新しいファイル サイズ */
  637.     new_size = org_size + patch_size;
  638.     PRINTF("ファイル サイズ : 0x%04x(%d) byte -> 0x%04x(%d) byte\n"
  639.             , org_size, org_size, new_size, new_size);
  640.  
  641.     /* OLD EXE HEADER 修正 */
  642.     {
  643.         WORD page_size;
  644.  
  645.         page_size = (new_size + 511) / 512;
  646.  
  647.         *(WORD*)&kbd_buf[2] = new_size % 512;
  648.         *(WORD*)&kbd_buf[4] = page_size;
  649.         PRINTF("OLD-EXE / BYTE IN LAST PAGE = 0x%04x\n", *(WORD*)&kbd_buf[2]);
  650.         PRINTF("OLD-EXE / NUM OF PAGE = 0x%04x\n", *(WORD*)&kbd_buf[4]);
  651.     }
  652.  
  653.     /* リロケーション移動 */
  654.     /* パッチ ルーチン移動 */
  655.     /* コード セグメント切り離しアドレスの修正 */
  656.     {
  657.         WORD rel_pos0;
  658.         WORD rel_pos1;
  659.         WORD rel_size;
  660.  
  661.         rel_pos0 = patch_entry_ofs;
  662.         rel_size = 2 + *(WORD*)&kbd_buf[rel_pos0] * 8;
  663.         rel_pos1 = rel_pos0 + patch_size;
  664.  
  665.         memmove(&kbd_buf[rel_pos1], &kbd_buf[rel_pos0], patch_size);
  666.  
  667.         PRINTF("リロケーション移動 : 0x%04x -> 0x%04x (0x%04x(%d) byte)\n"
  668.             , rel_pos0, rel_pos1, rel_size, rel_size);
  669.  
  670.         memmove(&kbd_buf[rel_pos0], patch_buf, patch_size);
  671.  
  672.         PRINTF("パッチ ルーチン組み込み : -> 0x%04x\n", in_60_ofs);
  673.  
  674.         new_code_seg_size
  675.             = SEG_FILE(kbd_buf, code_seg) + patch_size;
  676.  
  677.         PRINTF("CODE セグメント切り離しアドレス 0x%04x ->"
  678.             , *(WORD*)&kbd_buf[limit_addr_ofs + CODE_LIMIT_LO]);
  679.         *(WORD*)&kbd_buf[limit_addr_ofs + CODE_LIMIT_LO]
  680.             = new_code_seg_size;
  681.         PRINTF("0x%04x\n"
  682.             , *(WORD*)&kbd_buf[limit_addr_ofs + CODE_LIMIT_LO]);
  683.     }
  684.  
  685.     /* NEW EXE HEADER 修正 */
  686.     {
  687.         SEG_FILE(kbd_buf, code_seg) = new_code_seg_size;
  688.         SEG_ALLOC(kbd_buf, code_seg) = ((new_code_seg_size + 3) / 4) * 4;
  689.         PRINTF("NEW-EXE CODE FILE SIZE = 0x%04x\n"
  690.             , SEG_FILE(kbd_buf, code_seg));
  691.         PRINTF("NEW-EXE CODE ALLOC SIZE = 0x%04x\n"
  692.             , SEG_ALLOC(kbd_buf, code_seg));
  693.     }
  694.  
  695.     /* パッチ ルーチンへのジャンプ命令埋め込み */
  696.     {
  697.         WORD ofs;
  698.  
  699.         ofs = patch_entry_ofs - (in_60_ofs + IN_60_PAT_OFS + 3);
  700.  
  701.         kbd_buf[in_60_ofs + IN_60_PAT_OFS] = 0xe9;    /* jmp ofs16 */
  702.         kbd_buf[in_60_ofs + IN_60_PAT_OFS + 1] = ofs;
  703.         kbd_buf[in_60_ofs + IN_60_PAT_OFS + 2] = ofs >> 8;
  704.  
  705.         PRINTF("パッチ アドレス : 0x%04x\n", in_60_ofs + IN_60_PAT_OFS);
  706.     }
  707.  
  708.     return 1;
  709. }
  710.  
  711. /****************************************************************************/
  712. /*    main関数                                                            */
  713. /****************************************************************************/
  714.  
  715. int main(int argc, char *argv[])
  716. {
  717.     char ibmkbd_fname[256];
  718.     char mykbd_fname[256];
  719.  
  720.     title();
  721.  
  722.     if (argc < 4) {
  723.         usage();
  724.         return 1;
  725.     }
  726.  
  727.     /* MYKBD.SYS のパスを作る */
  728.     {
  729.         int s;
  730.  
  731.         strcpy(mykbd_fname, argv[1]);
  732.         s = strlen(mykbd_fname);
  733.         if (mykbd_fname[s - 1] == '\\') mykbd_fname[s - 1] = '\0';
  734.         strcat(mykbd_fname, "\\BOOT\\MYKBD.SYS");
  735.         strupr(mykbd_fname);
  736.     }
  737.  
  738.     /* IBMKBD.SYS のパスを作る */
  739.     {
  740.         strcpy(ibmkbd_fname, argv[2]);
  741.         strupr(ibmkbd_fname);
  742.     }
  743.  
  744.     /* IBMKBD.SYS を読み込む */
  745.     {
  746.         org_size = load_binary_file(ibmkbd_fname, kbd_buf, sizeof(kbd_buf));
  747.         if (org_size == 0) {
  748.             printf(
  749. "スペルミスをしているか、ディレクトリを間違えているか、さもなければ、現在\n"
  750. "OS/2 が使用中の IBMKBD.SYS を指定してしまったものと思われます。\n"
  751.             );
  752.             return 1;
  753.         }
  754.     }
  755.  
  756.     /* キー入れ替え用の変更データ ファイルを読み込む */
  757.     {
  758.         int i;
  759.  
  760.         for (i = 3; i < argc; i++) {
  761.             if (load_swap_info_file(argv[i]) == 0) {
  762.                 return 1;
  763.             }
  764.         }
  765.     }
  766.  
  767.     /* 読み込んだ IBMKBD.SYS を解析する */
  768.     if (analysis() == 0) {
  769.         printf("解析失敗\n");
  770.         return 1;
  771.     }
  772.  
  773.     if (generate() == 0) {
  774.         printf("変更失敗\n");
  775.         return 1;
  776.     }
  777.  
  778.     /* MYKBD.SYS に書き込む */
  779.     {
  780.         if (save_binary_file(mykbd_fname, kbd_buf, new_size) == 0) {
  781.             printf(
  782. "スペルミスをしているか、ディレクトリを間違えているか、さもなければ、現在\n"
  783. "OS/2 が使用中の MYKBD.SYS を上書きしようとしてしまったものと思われます。\n"
  784.             );
  785.             return 1;
  786.         }
  787.     }
  788.  
  789.     printf(
  790. "\n"
  791. "%s が生成されました。CONFIG.SYS で次のような行を探し、\n"
  792. "\n"
  793. "  BASEDEV=IBMKBD.SYS\n"
  794. "\n"
  795. "下のように変更してください。\n"
  796. "\n"
  797. "  BASEDEV=MYKBD.SYS\n"
  798. "\n"
  799. "そして、OS/2 をハードディスクから再起動してください。これでキーが入れ\n"
  800. "替わるはずです。\n"
  801.     , mykbd_fname);
  802.  
  803.     return 0;
  804. }
  805.