Unix.KbdMouse.Mod 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. (* ETH Oberon, Copyright 2000 ETH Zürich Institut für Computersysteme, ETH Zentrum, CH-8092 Zürich.
  2. Refer to the general ETH Oberon System license contract available at: http://www.oberon.ethz.ch/ *)
  3. MODULE KbdMouse; (* g.f. 9.7.07 *)
  4. (* replacement for the keyboard and mouse drivers in the Unix ports *)
  5. IMPORT Machine, S := SYSTEM, Inputs, Plugins, X11, Displays, XDisplay, Api:=X11Api, Modules, Objects;
  6. CONST
  7. ML = 0; MM = 1; MR = 2;
  8. ModeSwitch = 13;
  9. MetaMask = { Api.Mod4Mask, ModeSwitch };
  10. VAR
  11. event: Api.XEvent; xbuttons: WORDSET;
  12. compstatus: Api.ComposeStatus;
  13. disp: XDisplay.Display;
  14. MMseen, MRseen: BOOLEAN;
  15. TYPE
  16. Poll = OBJECT
  17. BEGIN {ACTIVE, SAFE,PRIORITY(Objects.High - 1)}
  18. LOOP
  19. Objects.Sleep( 15 ); PollXQueue;
  20. END
  21. END Poll;
  22. VAR
  23. poll: Poll; keySymbol: ARRAY 256 OF LONGINT;
  24. PROCEDURE CheckAlternateKeys( VAR mb: SET );
  25. BEGIN
  26. IF ~MMseen & (Api.ControlMask IN xbuttons) THEN INCL( mb, MM ) END;
  27. IF ~MRseen & (Api.Mod1Mask IN xbuttons) THEN INCL( mb, MR ) END
  28. END CheckAlternateKeys;
  29. PROCEDURE SendMouseMsg( x, y, dz: LONGINT; xbuttons: SET );
  30. VAR mm: Inputs.AbsMouseMsg;
  31. BEGIN
  32. Machine.Release( Machine.X11 );
  33. mm.keys := {};
  34. mm.x := x; mm.y := y; mm.dz := dz;
  35. IF Api.Button1Mask IN xbuttons THEN INCL( mm.keys, ML ) END;
  36. IF Api.Button2Mask IN xbuttons THEN INCL( mm.keys, MM ); MMseen := TRUE END;
  37. IF Api.Button3Mask IN xbuttons THEN INCL( mm.keys, MR ); MRseen := TRUE END;
  38. IF ~(MMseen & MRseen) THEN CheckAlternateKeys( mm.keys ) END;
  39. Inputs.mouse.Handle( mm );
  40. Machine.Acquire( Machine.X11 )
  41. END SendMouseMsg;
  42. PROCEDURE SendKeyboardMsg( km: Inputs.KeyboardMsg );
  43. BEGIN
  44. Machine.Release( Machine.X11 );
  45. Inputs.keyboard.Handle( km );
  46. Machine.Acquire( Machine.X11 )
  47. END SendKeyboardMsg;
  48. PROCEDURE PollXQueue;
  49. CONST bufsize = 20;
  50. VAR keycount, xr, yr, x, y, dz, i: LONGINT;
  51. rw, cw: X11.Window;
  52. keysym: X11.KeySym; xd: X11.DisplayPtr;
  53. newxbuttons, bdiff: WORDSET;
  54. km: Inputs.KeyboardMsg;
  55. kp : Api.XKeyEvent;
  56. be : Api.XButtonPressedEvent;
  57. em: Api.XExposeEvent;
  58. cm : Api.XClientMessageEvent;
  59. datal: Api.Data40l;
  60. cn: Api.XConfigureEvent;
  61. res, events: LONGINT;
  62. buffer: ARRAY bufsize OF CHAR;
  63. BEGIN
  64. xd := disp.xdisp;
  65. Machine.Acquire( Machine.X11 );
  66. events := Api.Pending( xd );
  67. WHILE events > 0 DO
  68. Api.NextEvent( xd, event );
  69. CASE event.typ OF
  70. | Api.KeyPress: kp := S.VAL( Api.XKeyEvent, event );
  71. X11.lastEventTime := kp.time;
  72. keycount := Api.LookupString( kp, buffer, bufsize, keysym, compstatus );
  73. X11.QueryPointer( xd, event.window, rw, cw, xr, yr, x, y, newxbuttons );
  74. IF keycount = 0 THEN
  75. bdiff := newxbuttons / xbuttons; xbuttons := newxbuttons;
  76. km.ch := 0X;
  77. IF Api.ShiftMask IN bdiff THEN km.keysym := Inputs.KsShiftL
  78. ELSIF Api.ControlMask IN bdiff THEN
  79. km.keysym := Inputs.KsControlL;
  80. IF ~MMseen THEN SendMouseMsg( x, y, 0, xbuttons ) END
  81. ELSIF Api.Mod1Mask IN bdiff THEN
  82. km.keysym := Inputs.KsAltL;
  83. IF ~MRseen THEN SendMouseMsg( x, y, 0, xbuttons ) END
  84. ELSIF MetaMask*bdiff # {} THEN km.keysym := Inputs.KsMetaL
  85. ELSIF Api.Mod5Mask IN bdiff THEN km.keysym := Inputs.KsAltR
  86. ELSIF keysym = 0FE20H THEN (* handle Shift-Tab key *)
  87. km.keysym := Inputs.KsTab; km.ch :=09X
  88. ELSE
  89. km.keysym := LONGINT(keysym);
  90. END;
  91. km.flags := KeyState( );
  92. SendKeyboardMsg( km )
  93. ELSE
  94. IF (Api.ControlMask IN kp.state) & (keysym = 32) THEN (* check Ctrl-space *)
  95. km.ch := CHR( keysym ); km.flags := KeyState( );
  96. km.keysym := LONGINT(keysym);
  97. SendKeyboardMsg( km ); (* IME keys *)
  98. ELSE
  99. xbuttons := newxbuttons; i := 0;
  100. WHILE i < keycount DO
  101. km.ch := buffer[i];
  102. IF km.ch = 0F1X THEN km.ch := 0A4X
  103. ELSIF km.ch = 0F2X THEN km.ch := 0A5X
  104. END;
  105. km.keysym := keySymbol[ORD( km.ch )];
  106. km.flags := KeyState( );
  107. SendKeyboardMsg( km );
  108. INC( i )
  109. END
  110. END;
  111. END;
  112. | Api.KeyRelease: kp := S.VAL(Api.XKeyEvent, event);
  113. X11.lastEventTime := kp.time;
  114. X11.QueryPointer( xd, event.window, rw, cw, xr, yr, x, y, newxbuttons );
  115. bdiff := newxbuttons / xbuttons; xbuttons := newxbuttons;
  116. IF bdiff # {} THEN
  117. km.ch := 0X;
  118. IF Api.ShiftMask IN bdiff THEN km.keysym := Inputs.KsShiftL
  119. ELSIF Api.ControlMask IN bdiff THEN
  120. km.keysym := Inputs.KsControlL;
  121. IF ~MMseen THEN SendMouseMsg( x, y, 0, xbuttons ) END
  122. ELSIF Api.Mod1Mask IN bdiff THEN
  123. km.keysym := Inputs.KsAltL;
  124. IF ~MRseen THEN SendMouseMsg( x, y, 0, xbuttons ) END
  125. ELSIF MetaMask*bdiff # {} THEN km.keysym := Inputs.KsMetaL
  126. ELSIF Api.Mod5Mask IN bdiff THEN km.keysym := Inputs.KsAltR
  127. END;
  128. km.flags := KeyState( ) + {Inputs.Release};
  129. SendKeyboardMsg( km )
  130. END
  131. | Api.ButtonPress: be := S.VAL(Api.XButtonPressedEvent, event);
  132. X11.lastEventTime := be.time;
  133. dz := 0;
  134. CASE be.button OF
  135. | Api.Button1: INCL( xbuttons, Api.Button1Mask )
  136. | Api.Button2: INCL( xbuttons, Api.Button2Mask )
  137. | Api.Button3: INCL( xbuttons, Api.Button3Mask )
  138. | Api.Button4: dz := -1
  139. | Api.Button5: dz := +1
  140. ELSE (* ignore *)
  141. END;
  142. SendMouseMsg( be.x, be.y, dz, xbuttons )
  143. | Api.ButtonRelease: be := S.VAL(Api.XButtonReleasedEvent, event);
  144. X11.lastEventTime := be.time;
  145. CASE be.button OF
  146. | Api.Button1: EXCL( xbuttons, Api.Button1Mask )
  147. | Api.Button2: EXCL( xbuttons, Api.Button2Mask )
  148. | Api.Button3: EXCL( xbuttons, Api.Button3Mask )
  149. ELSE (* ignore *)
  150. END;
  151. SendMouseMsg( be.x, be.y, 0, xbuttons )
  152. | Api.MotionNotify:
  153. X11.QueryPointer( xd, event.window, rw, cw, xr, yr, x, y, xbuttons );
  154. SendMouseMsg( x, y, 0, xbuttons )
  155. | Api.Expose, Api.GraphicsExpose:
  156. (* hacking, clear all expoure events in queue *)
  157. REPEAT res := Api.CheckTypedEvent(xd, Api.Expose, event) UNTIL res # X11.True;
  158. REPEAT
  159. res := Api.CheckWindowEvent(xd, disp.primary, Api.ExposureMask, event)
  160. UNTIL res # X11.True;
  161. em := S.VAL( Api.XExposeEvent, event );
  162. IF em.count = 0 THEN (* wait until last message*)
  163. (* Let DisplayRefresher handle this *)
  164. km.keysym := 0FFC6H;
  165. SendKeyboardMsg( km );
  166. END;
  167. (* clear all expoure events in queue, again *)
  168. REPEAT res := Api.CheckTypedEvent(xd, Api.Expose, event) UNTIL res # X11.True;
  169. | Api.NoExpose:
  170. | Api.MappingNotify:
  171. X11.RefreshKeyboardMapping( ADDRESSOF( event ) )
  172. | Api.ClientMessage:
  173. cm := S.VAL( Api.XClientMessageEvent, event );
  174. datal := S.VAL( Api.Data40l, cm.data );
  175. IF S.VAL( X11.Atom,datal[0] ) = disp.wmDelete THEN
  176. (* shutdown *)
  177. Machine.Release( Machine.X11 );
  178. Modules.Shutdown( Modules.Reboot );
  179. END;
  180. | Api.UnmapNotify:
  181. | Api.MapNotify:
  182. | Api.SelectionClear:
  183. IF Api.ClearSelection # NIL THEN Api.ClearSelection(); END
  184. | Api.SelectionNotify:
  185. IF Api.ReceiveSelection # NIL THEN
  186. Machine.Release( Machine.X11 );
  187. Api.ReceiveSelection( S.VAL( Api.XSelectionEvent, event ) );
  188. Machine.Acquire( Machine.X11 )
  189. END
  190. | Api.SelectionRequest:
  191. IF Api.SendSelection # NIL THEN
  192. Machine.Release( Machine.X11 );
  193. Api.SendSelection( S.VAL( Api.XSelectionRequestEvent, event ) );
  194. Machine.Acquire( Machine.X11 )
  195. END
  196. | Api.ConfigureNotify: cn := S.VAL(Api.XConfigureEvent, event);
  197. ELSE
  198. (* ignore *)
  199. END;
  200. events := Api.Pending( xd );
  201. END;
  202. Machine.Release( Machine.X11 );
  203. END PollXQueue;
  204. (* Returns wether key (SHIFT, CTRL or ALT) is pressed *)
  205. PROCEDURE KeyState( ): SET;
  206. VAR keys: SET;
  207. BEGIN
  208. keys := {};
  209. IF Api.ShiftMask IN xbuttons THEN INCL( keys, Inputs.LeftShift ) END;
  210. IF Api.ControlMask IN xbuttons THEN INCL( keys, Inputs.LeftCtrl ) END;
  211. IF Api.Mod1Mask IN xbuttons THEN INCL( keys, Inputs.LeftAlt ) END;
  212. IF MetaMask*xbuttons # {} THEN INCL( keys, Inputs.LeftMeta ) END;
  213. IF Api.Mod5Mask IN xbuttons THEN INCL( keys, Inputs.RightAlt ) END;
  214. RETURN keys
  215. END KeyState;
  216. PROCEDURE Keysym( CONST str: ARRAY OF CHAR ): X11.KeySym;
  217. BEGIN
  218. RETURN X11.StringToKeysym( ADDRESSOF( str ) )
  219. END Keysym;
  220. PROCEDURE Init*;
  221. VAR FK: ARRAY 8 OF CHAR;
  222. n, i, k: LONGINT; modifiers: X11.Modifiers;
  223. shift, control, meta, alt, capslock, numlock: X11.KeySym;
  224. PROCEDURE Rebind( CONST keystr: ARRAY OF CHAR; nofmod: LONGINT; key: CHAR );
  225. VAR newkeystr: ARRAY 8 OF CHAR;
  226. oldkeysym: X11.KeySym;
  227. BEGIN
  228. Machine.Acquire( Machine.X11 );
  229. oldkeysym := Keysym( keystr );
  230. newkeystr[0] := key; newkeystr[1] := 0X;
  231. X11.RebindKeysym( disp.xdisp, oldkeysym, modifiers, nofmod, ADDRESSOF( newkeystr ), 1 );
  232. Machine.Release( Machine.X11 )
  233. END Rebind;
  234. PROCEDURE Rebind4( CONST keyString: ARRAY OF CHAR; n: LONGINT; key: CHAR );
  235. BEGIN
  236. Rebind( keyString, n, key );
  237. modifiers[n] := shift; Rebind( keyString, n + 1, key );
  238. modifiers[n] := control; Rebind( keyString, n + 1, key );
  239. modifiers[n + 1] := shift; Rebind( keyString, n + 2, key );
  240. END Rebind4;
  241. BEGIN
  242. MMseen := FALSE; MRseen := FALSE;
  243. Machine.Acquire( Machine.X11 );
  244. X11.SelectInput( disp.xdisp, disp.primary,
  245. X11.ExposureMask + X11.ButtonPressMask + X11.OwnerGrabButtonMask +
  246. X11.ButtonReleaseMask + X11.PointerMotionHintMask + X11.PointerMotionMask +
  247. X11.KeyPressMask + X11.KeyReleaseMask + X11.StructureNotifyMask );
  248. Machine.Release( Machine.X11 );
  249. shift := Keysym( "Shift_L" ); control := Keysym( "Control_L" );
  250. meta := Keysym( "Meta-L" ); alt := Keysym( "Alt_L" );
  251. capslock := Keysym( "Caps_Lock" ); numlock := Keysym( "Num_Lock" );
  252. modifiers[0] := shift;
  253. Rebind( "Pause", 1, 0ADX ); (* SHIFT-BREAK *)
  254. modifiers[0] := control; Rebind( "Return", 1, 0AX );
  255. modifiers[1] := numlock; Rebind( "Return", 2, 0AX );
  256. modifiers[1] := capslock; Rebind( "Return", 2, 0AX );
  257. modifiers[2] := numlock; Rebind( "Return", 3, 0AX );
  258. FOR k := 0 TO 4 DO
  259. CASE k OF
  260. | 0: n := 0;
  261. | 1: modifiers[0] := meta; n := 1;
  262. | 2: modifiers[0] := capslock; n := 1
  263. | 3: modifiers[0] := numlock; n := 1
  264. | 4: modifiers[0] := capslock; modifiers[1] := numlock; n := 2
  265. END;
  266. i := 0; FK := "F0";
  267. WHILE i < 10 DO FK[1] := CHR( ORD( "0" ) + i ); Rebind4( FK, n, CHR( 0F0H + i ) ); INC( i ) END;
  268. i := 10; FK := "F10";
  269. WHILE i <= 12 DO FK[2] := CHR( ORD( "0" ) + i - 10 ); Rebind4( FK, n, CHR( 0F0H + i ) ); INC( i ) END;
  270. Rebind4( "BackSpace", n, 7FX );
  271. Rebind4( "Delete", n, 0A1X );
  272. Rebind4( "Escape", n, 1BX );
  273. Rebind4( "Up", n, 0C1X ); Rebind4( "Down", n, 0C2X );
  274. Rebind4( "Left", n, 0C4X ); Rebind4( "Right", n, 0C3X );
  275. IF k < 3 THEN
  276. (* do not for NumLock on *)
  277. Rebind4( "KP_Up", n, 0C1X ); Rebind4( "KP_Down", n, 0C2X );
  278. Rebind4( "KP_Left", n, 0C4X ); Rebind4( "KP_Right", n, 0C3X );
  279. END;
  280. Rebind4( "Prior", n, 0A2X ); Rebind4( "KP_Prior", n, 0A2X );
  281. Rebind4( "Next", n, 0A3X ); Rebind4( "KP_Next", n, 0A3X );
  282. Rebind4( "Insert", n, 0A0X );
  283. Rebind4( "Home", n, 0A8X ); Rebind4( "KP_Home", n, 0A8X );
  284. Rebind4( "End", n, 0A9X ); Rebind4( "KP_End", n, 0A9X );
  285. END;
  286. (* special keyboard: *)
  287. modifiers[0] := shift; modifiers[1] := meta;
  288. FOR i := 0 TO 2 DO
  289. Rebind( "aacute", i, 094X );
  290. Rebind( "agrave", i, 08BX );
  291. Rebind( "Adiaeresis", i, 080X ); Rebind( "adiaeresis", i, 083X );
  292. Rebind( "acircumflex", i, 086X );
  293. Rebind( "eacute", i, 090X );
  294. Rebind( "egrave", i, 08CX );
  295. Rebind( "ediaeresis", i, 091X );
  296. Rebind( "ecircumflex", i, 087X );
  297. Rebind( "igrave", i, 08DX );
  298. Rebind( "idiaeresis", i, 092X );
  299. Rebind( "icircumflex", i, 088X );
  300. Rebind( "ograve", i, 08EX );
  301. Rebind( "Odiaeresis", i, 081X ); Rebind( "odiaeresis", i, 084X );
  302. Rebind( "ocircumflex", i, 089X );
  303. Rebind( "ugrave", i, 08FX );
  304. Rebind( "Udiaeresis", i, 082X ); Rebind( "udiaeresis", i, 085X );
  305. Rebind( "ucircumflex", i, 08AX );
  306. Rebind( "ccedilla", i, 093X );
  307. Rebind( "ntilde", i, 095X );
  308. Rebind( "ssharp", i, 096X );
  309. Rebind( "idotless", i, 0FDX);
  310. Rebind( "Iabovedot", i, 0DDX);
  311. Rebind( "gbreve", i, 0F0X );
  312. Rebind( "Gbreve", i, 0D0X );
  313. Rebind( "scedilla", i, 0FEX );
  314. Rebind( "Scedilla", i, 0DEX );
  315. END;
  316. InitKeysym;
  317. NEW( poll );
  318. END Init;
  319. PROCEDURE InitKeysym;
  320. VAR i: LONGINT;
  321. BEGIN
  322. FOR i := 0 TO 255 DO keySymbol[i] := i END;
  323. keySymbol[07FH] := Inputs.KsBackSpace;
  324. keySymbol[009H] := Inputs.KsTab;
  325. keySymbol[00AH] := Inputs.KsReturn;
  326. keySymbol[00DH] := Inputs.KsReturn;
  327. keySymbol[0C1H] := Inputs.KsUp;
  328. keySymbol[0C2H] := Inputs.KsDown;
  329. keySymbol[0C3H] := Inputs.KsRight;
  330. keySymbol[0C4H] := Inputs.KsLeft;
  331. keySymbol[0A0H] := Inputs.KsInsert;
  332. keySymbol[0A1H] := Inputs.KsDelete;
  333. keySymbol[0A2H] := Inputs.KsPageUp;
  334. keySymbol[0A3H] := Inputs.KsPageDown;
  335. keySymbol[0A8H] := Inputs.KsHome;
  336. keySymbol[0A9H] := Inputs.KsEnd;
  337. keySymbol[01BH] := Inputs.KsEscape;
  338. FOR i := 0F1H TO 0FCH DO keySymbol[i] := 0FFBEH + (i - 0F1H) END;
  339. keySymbol[0A4H] := Inputs.KsF1;
  340. keySymbol[0A5H] := Inputs.KsF2;
  341. END InitKeysym;
  342. PROCEDURE GetXDisplay;
  343. VAR p: Plugins.Plugin;
  344. BEGIN
  345. p := Displays.registry.Await( "XDisplay" ); disp := p( XDisplay.Display )
  346. END GetXDisplay;
  347. BEGIN
  348. ASSERT( S.VAL( LONGINT, {0} ) = 1 );
  349. GetXDisplay;
  350. END KbdMouse.
  351. (** Remark:
  352. 1. Keyboard character codes correspond to the ASCII character set. Some other important codes are:
  353. SHIFT-BREAK 0ADX
  354. BREAK 0ACX
  355. F1 ... F12 0F1X ... 0FCX
  356. UP ARROW 0C1X
  357. RIGHT ARROW 0C3X
  358. DOWN ARROW 0C2X
  359. LEFT ARROW 0C4X
  360. INSERT 0A0X
  361. DELETE 0A1X
  362. PAGE-UP 0A2X
  363. PAGE-DOWN 0A3X
  364. some none ascii character get mapped to UTF8:
  365. ä, Ä 131, 128
  366. ö, Ö 132, 129
  367. ü, Ü 133, 130
  368. ß 150
  369. . . .
  370. *)