keyclick.pas 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. { example for : Interrupt redirection (Hardware interrupts)
  2. set_pm_interrupt()
  3. get_pm_interrupt()
  4. lock_code()
  5. lock_data()
  6. unlock_code()
  7. unlock_data()
  8. tseginfo record
  9. }
  10. { This example demonstrates how to chain to a hardware interrupt.
  11. In more detail, it hooks the keyboard interrupt, calls a user procedure
  12. which in this case simply turns the PC speaker on and off. Then the old
  13. interrupt is called.
  14. }
  15. uses crt, { readkey() }
  16. go32;
  17. const kbdint = $9; { keyboard is IRQ 1 -> interrupt 9 }
  18. var oldint9_handler : tseginfo; { holds old PM interrupt handler address }
  19. newint9_handler : tseginfo; { new PM interrupt handler }
  20. clickproc : pointer; { pointer to interrupt handler }
  21. {$ASMMODE DIRECT}
  22. { interrupt handler }
  23. procedure int9_handler; assembler;
  24. asm
  25. cli
  26. { save all registers, because we don't know which the compiler uses for
  27. the called procedure }
  28. pushal
  29. { set up to call a FPC procedure }
  30. movw %cs:INT9_DS, %ax
  31. movw %ax, %ds
  32. movw %ax, %es
  33. movw U_GO32_DOSMEMSELECTOR, %ax
  34. movw %ax, %fs
  35. { call user procedure }
  36. call *_CLICKPROC
  37. { restore all registers }
  38. popal
  39. ljmp %cs:OLDHANDLER { call old handler }
  40. { we don't need to do anything more, because the old interrupt handler
  41. does this for us (send EOI command, iret, sti...) }
  42. INT9_DS: .word 0
  43. OLDHANDLER:
  44. .long 0
  45. .word 0
  46. end;
  47. { dummy procedure to retrieve exact length of handler, for locking and
  48. unlocking functions }
  49. procedure int9_dummy; begin end;
  50. { demo user procedure, simply clicks on every keypress }
  51. procedure clicker;
  52. begin
  53. sound(500); delay(10); nosound;
  54. end;
  55. { dummy procedure to retrieve exact length of user procedure for locking and
  56. unlocking functions }
  57. procedure clicker_dummy; begin end;
  58. { installs our new handler }
  59. procedure install_click;
  60. begin
  61. clickproc := @clicker;
  62. { lock used code and data }
  63. lock_data(clickproc, sizeof(clickproc));
  64. lock_data(dosmemselector, sizeof(dosmemselector));
  65. lock_code(@clicker, longint(@clicker_dummy)-longint(@clicker));
  66. lock_code(@int9_handler, longint(@int9_dummy)-longint(@int9_handler));
  67. { fill in new handler's 48 bit pointer }
  68. newint9_handler.offset := @int9_handler;
  69. newint9_handler.segment := get_cs;
  70. { get old PM interrupt handler }
  71. get_pm_interrupt(kbdint, oldint9_handler);
  72. { store old PM interrupt handlers address in interrupt handler }
  73. asm
  74. movw %ds, %ax
  75. movw %ax, INT9_DS
  76. movl _OLDINT9_HANDLER, %eax
  77. movl %eax, OLDHANDLER
  78. movw 4+_OLDINT9_HANDLER, %ax
  79. movw %ax, 4+OLDHANDLER
  80. end;
  81. { set the new interrupt handler }
  82. set_pm_interrupt(kbdint, newint9_handler);
  83. end;
  84. { deinstalls our interrupt handler }
  85. procedure remove_click;
  86. begin
  87. { set old handler }
  88. set_pm_interrupt(kbdint, oldint9_handler);
  89. { unlock used code & data }
  90. unlock_data(dosmemselector, sizeof(dosmemselector));
  91. unlock_data(clickproc, sizeof(clickproc));
  92. unlock_code(@clicker, longint(@clicker_dummy)-longint(@clicker));
  93. unlock_code(@int9_handler, longint(@int9_dummy)-longint(@int9_handler));
  94. end;
  95. var ch : char;
  96. begin
  97. install_click;
  98. Writeln('Enter any message. Press return when finished');
  99. while (ch <> #13) do begin
  100. ch := readkey; write(ch);
  101. end;
  102. remove_click;
  103. end.