Unix.KbdMouse.Mod 14 KB

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