Rev 1 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1 | daniel-mar | 1 | unit DXInput; |
2 | |||
3 | interface |
||
4 | |||
5 | {$INCLUDE DelphiXcfg.inc} |
||
6 | |||
7 | uses |
||
8 | Windows, Messages, SysUtils, Classes, Controls, Forms, MMSystem, |
||
4 | daniel-mar | 9 | DXClass, {$IFDEF VER17UP} Types, {$ENDIF} |
10 | {$IfDef StandardDX} |
||
11 | {$IfDef DX9} |
||
12 | DirectInput; |
||
13 | {$Else} |
||
14 | {$IfDef DX81} |
||
15 | DirectInput8; |
||
16 | {$Else} |
||
17 | DirectInput; |
||
18 | {$EndIf} |
||
19 | {$EndIf} |
||
20 | {$Else} |
||
21 | DirectX; |
||
22 | {$EndIf} |
||
1 | daniel-mar | 23 | |
24 | type |
||
25 | |||
26 | { EDXInputError } |
||
27 | |||
28 | EDXInputError = class(Exception); |
||
29 | |||
30 | { EForceFeedbackEffectError } |
||
31 | |||
32 | EForceFeedbackEffectError = class(Exception); |
||
33 | |||
34 | |||
35 | { TForceFeedbackEffect } |
||
36 | |||
37 | TForceFeedbackEffectType = (etNone, etConstantForce, etPeriodic, etCondition); |
||
38 | |||
39 | TForceFeedbackEffect = class; |
||
40 | TForceFeedbackEffects = class; |
||
41 | |||
42 | TForceFeedbackEffectObject = class |
||
43 | private |
||
44 | FAxes: array[0..1] of DWORD; |
||
45 | FAxesCount: Integer; |
||
46 | Feff: TDIEffect; |
||
47 | FDirections: array[0..1] of DWORD; |
||
48 | FEnvelope: TDIEnvelope; |
||
49 | FConstantForce: TDIConstantForce; |
||
50 | FCondition: TDICondition; |
||
51 | FPeriodic: TDIPeriodic; |
||
52 | FEffect: IDirectInputEffect; |
||
53 | procedure Clear; |
||
54 | procedure Init(Effect: TForceFeedbackEffect); |
||
55 | procedure Release; |
||
56 | public |
||
57 | destructor Destroy; override; |
||
58 | end; |
||
59 | |||
60 | TForceFeedbackEffect = class(TPersistent) |
||
61 | private |
||
62 | FRoot: TForceFeedbackEffects; |
||
63 | FParent: TForceFeedbackEffect; |
||
64 | FList: TList; |
||
65 | FAttackLevel: Integer; |
||
66 | FAttackTime: Integer; |
||
67 | FCondition: TPoint; |
||
68 | FConstant: TPoint; |
||
69 | FEffectType: TForceFeedbackEffectType; |
||
70 | FFadeLevel: Integer; |
||
71 | FFadeTime: Integer; |
||
72 | FName: string; |
||
73 | FPeriod: Integer; |
||
74 | FPlaying: Boolean; |
||
75 | FPower: Integer; |
||
76 | FTime: Integer; |
||
77 | FStartDelayTime: Integer; |
||
78 | FObject: TForceFeedbackEffectObject; |
||
79 | FObject2: TForceFeedbackEffectObject; |
||
80 | FFindEffectFlag: Boolean; |
||
81 | FFindEffectGUID: TGUID; |
||
82 | procedure Acquire; |
||
83 | procedure Finalize; |
||
84 | procedure Initialize; |
||
85 | procedure ChangeEffect; |
||
86 | procedure MakeEff; |
||
87 | procedure CreateEffect; |
||
88 | function GetCount: Integer; |
||
89 | function GetEffect(Index: Integer): TForceFeedbackEffect; |
||
90 | function GetIndex: Integer; |
||
91 | function GetPlaying: Boolean; |
||
92 | procedure SetAttackLevel(Value: Integer); |
||
93 | procedure SetAttackTime(Value: Integer); |
||
94 | procedure SetCondition(Value: TPoint); |
||
95 | procedure SetConstant(Value: TPoint); |
||
96 | procedure SetEffectType(Value: TForceFeedbackEffectType); |
||
97 | procedure SetFadeLevel(Value: Integer); |
||
98 | procedure SetFadeTime(Value: Integer); |
||
99 | procedure SetIndex(Value: Integer); |
||
100 | procedure SetPeriod(Value: Integer); |
||
101 | procedure SetParent(Value: TForceFeedbackEffect); |
||
102 | procedure SetPower(Value: Integer); |
||
103 | procedure SetTime(Value: Integer); |
||
104 | procedure SetStartDelayTime(Value: Integer); |
||
105 | function HasInterface: Boolean; |
||
106 | protected |
||
107 | function GetOwner: TPersistent; override; |
||
108 | property StartDelayTime: Integer read FStartDelayTime write SetStartDelayTime; |
||
109 | public |
||
110 | constructor Create(AParent: TForceFeedbackEffect); |
||
111 | destructor Destroy; override; |
||
112 | procedure Assign(Source: TPersistent); override; |
||
113 | procedure Clear; |
||
114 | function Find(const Name: string): TForceFeedbackEffect; |
||
115 | function IndexOf(const Name: string): Integer; |
||
116 | procedure LoadFromFile(const FileName: string); |
||
117 | procedure LoadFromStream(Stream: TStream); |
||
118 | procedure SaveToFile(const FileName: string); |
||
119 | procedure SaveToStream(Stream: TStream); |
||
120 | procedure Start; |
||
121 | procedure Stop; |
||
122 | procedure Unload(Recurse: Boolean); |
||
123 | property Count: Integer read GetCount; |
||
124 | property Effects[Index: Integer]: TForceFeedbackEffect read GetEffect; default; |
||
125 | property Index: Integer read GetIndex write SetIndex; |
||
126 | property Playing: Boolean read GetPlaying; |
||
127 | property Parent: TForceFeedbackEffect read FParent write SetParent; |
||
128 | property Name: string read FName write FName; |
||
129 | property EffectType: TForceFeedbackEffectType read FEffectType write SetEffectType; |
||
130 | property AttackLevel: Integer read FAttackLevel write SetAttackLevel; |
||
131 | property AttackTime: Integer read FAttackTime write SetAttackTime; |
||
132 | property Condition: TPoint read FCondition write SetCondition; |
||
133 | property Constant: TPoint read FConstant write SetConstant; |
||
134 | property FadeLevel: Integer read FFadeLevel write SetFadeLevel; |
||
135 | property FadeTime: Integer read FFadeTime write SetFadeTime; |
||
136 | property Period: Integer read FPeriod write SetPeriod; |
||
137 | property Power: Integer read FPower write SetPower; |
||
138 | property Time: Integer read FTime write SetTime; |
||
139 | end; |
||
140 | |||
141 | { TForceFeedbackEffects } |
||
142 | |||
143 | TCustomInput = class; |
||
144 | |||
145 | TForceFeedbackEffects = class(TForceFeedbackEffect) |
||
146 | private |
||
147 | FComponent: TComponent; |
||
148 | FInput: TCustomInput; |
||
149 | protected |
||
150 | procedure DefineProperties(Filer: TFiler); override; |
||
151 | public |
||
152 | constructor Create(Input: TCustomInput); |
||
153 | destructor Destroy; override; |
||
154 | property Input: TCustomInput read FInput; |
||
155 | end; |
||
156 | |||
157 | { TCustomInput } |
||
158 | |||
159 | TDXInputState = (isUp, isDown, isLeft, isRight, isButton1, isButton2, isButton3, |
||
160 | isButton4, isButton5, isButton6, isButton7, isButton8, isButton9, isButton10, isButton11, |
||
161 | isButton12, isButton13, isButton14, isButton15, isButton16, isButton17, isButton18, |
||
162 | isButton19, isButton20, isButton21, isButton22, isButton23, isButton24, isButton25, |
||
163 | isButton26, isButton27, isButton28, isButton29, isButton30, isButton31, isButton32); |
||
164 | |||
165 | TDXInputStates = set of TDXInputState; |
||
166 | |||
167 | TCustomDXInput = class; |
||
168 | |||
169 | TCustomInput = class(TPersistent) |
||
170 | private |
||
171 | FBindInputStates: Boolean; |
||
172 | FButtonCount: Integer; |
||
173 | FDataFormat: TDIDataFormat; |
||
174 | FDataFormatObjects: array[0..255] of TDIObjectDataFormat; |
||
175 | FDataFormatGUIDs: array[0..255] of TGUID; |
||
176 | FDevice: IDirectInputDevice; |
||
177 | FDevice2: IDirectInputDevice2; |
||
178 | FDXInput: TCustomDXInput; |
||
179 | FEffects: TForceFeedbackEffects; |
||
180 | FEnabled: Boolean; |
||
181 | FForceFeedback: Boolean; |
||
182 | FForceFeedbackDevice: Boolean; |
||
183 | FInitialized: Boolean; |
||
184 | FStates: TDXInputStates; |
||
185 | procedure Acquire; |
||
186 | procedure Finalize; virtual; |
||
187 | procedure Initialize; virtual; |
||
188 | function GetButton(Index: Integer): Boolean; |
||
189 | function GetCooperativeLevel: Integer; virtual; |
||
190 | function GetDeviceState(dwSize: Integer; var Data): Boolean; |
||
191 | function SetDataFormat: Boolean; |
||
192 | procedure SetEffects(Value: TForceFeedbackEffects); |
||
193 | procedure SetEnabled(Value: Boolean); |
||
194 | procedure SetForceFeedback(Value: Boolean); |
||
195 | procedure SetWindowHandle(Value: Integer); |
||
196 | public |
||
197 | constructor Create(DXInput: TCustomDXInput); virtual; |
||
198 | destructor Destroy; override; |
||
199 | procedure Update; virtual; abstract; |
||
200 | property ButtonCount: Integer read FButtonCount; |
||
201 | property Buttons[Index: Integer]: Boolean read GetButton; |
||
202 | property States: TDXInputStates read FStates; |
||
203 | published |
||
204 | property BindInputStates: Boolean read FBindInputStates write FBindInputStates; |
||
205 | property Effects: TForceFeedbackEffects read FEffects write SetEffects; |
||
206 | property Enabled: Boolean read FEnabled write SetEnabled; |
||
207 | property ForceFeedback: Boolean read FForceFeedback write SetForceFeedback; |
||
208 | end; |
||
209 | |||
210 | { TKeyboard } |
||
211 | |||
212 | PKeyAssign = ^TKeyAssign; |
||
213 | TKeyAssign = array[0..2] of Integer; |
||
214 | |||
215 | TKeyAssignList = array[TDXInputState] of TKeyAssign; |
||
216 | |||
217 | TKeyboard = class(TCustomInput) |
||
218 | private |
||
219 | FKeyStates: TKeyboardState; |
||
220 | procedure Finalize; override; |
||
221 | procedure Initialize; override; |
||
222 | function GetKey(Key: Integer): Boolean; |
||
223 | procedure ReadAssigns(Stream: TStream); |
||
224 | procedure WriteAssigns(Stream: TStream); |
||
225 | protected |
||
226 | procedure DefineProperties(Filer: TFiler); override; |
||
227 | public |
||
228 | KeyAssigns: TKeyAssignList; |
||
229 | constructor Create(DXInput: TCustomDXInput); override; |
||
230 | procedure Update; override; |
||
231 | property Keys[Key: Integer]: Boolean read GetKey; |
||
232 | end; |
||
233 | |||
234 | { TMouse } |
||
235 | |||
236 | TMouse = class(TCustomInput) |
||
237 | private |
||
238 | Fdims: TDIMouseState; |
||
239 | procedure Finalize; override; |
||
240 | procedure Initialize; override; |
||
241 | function GetX: Integer; |
||
242 | function GetY: Integer; |
||
243 | function GetZ: Integer; |
||
244 | public |
||
245 | constructor Create(DXInput: TCustomDXInput); override; |
||
246 | procedure Update; override; |
||
247 | property X: Integer read GetX; |
||
248 | property Y: Integer read GetY; |
||
249 | property Z: Integer read GetZ; |
||
250 | end; |
||
251 | |||
252 | { TJoystick } |
||
253 | |||
254 | TJoystick = class(TCustomInput) |
||
255 | private |
||
256 | Fdijs: TDIJoyState2; |
||
257 | FAutoCenter: Boolean; |
||
258 | FDeviceGUID: TGUID; |
||
259 | FEnumFlag: Boolean; |
||
260 | FEnumIndex: Integer; |
||
261 | FID: Integer; |
||
262 | FID2: Integer; |
||
263 | FJoyCaps: TJoyCaps; |
||
264 | FDeadZone: array[0..SizeOf(TDIJoyState2)-1] of Integer; |
||
265 | FRange: array[0..SizeOf(TDIJoyState2)-1] of Integer; |
||
266 | procedure Finalize; override; |
||
267 | procedure Initialize; override; |
||
268 | function GetCooperativeLevel: Integer; override; |
||
269 | function GetDeadZone(Obj: Integer): Integer; |
||
270 | function GetRange(Obj: Integer): Integer; |
||
271 | function GetX: Integer; |
||
272 | function GetY: Integer; |
||
273 | function GetZ: Integer; |
||
274 | procedure SetDeadZone(Obj: Integer; Value: Integer); |
||
275 | procedure SetRange(Obj: Integer; Value: Integer); |
||
276 | procedure SetAutoCenter(Value: Boolean); |
||
277 | procedure SetID(Value: Integer); |
||
278 | public |
||
279 | constructor Create(DXInput: TCustomDXInput); override; |
||
280 | procedure Update; override; |
||
281 | property DeadZone[Obj: Integer]: Integer read GetDeadZone write SetDeadZone; |
||
282 | property Range[Obj: Integer]: Integer read GetRange write SetRange; |
||
283 | property Joystate: TDIJoyState2 read Fdijs; |
||
284 | property X: Integer read GetX; |
||
285 | property Y: Integer read GetY; |
||
286 | property Z: Integer read GetZ; |
||
287 | published |
||
288 | property AutoCenter: Boolean read FAutoCenter write SetAutoCenter; |
||
289 | property DeadZoneX: Integer index DIJOFS_X read GetDeadZone write SetDeadZone; |
||
290 | property DeadZoneY: Integer index DIJOFS_Y read GetDeadZone write SetDeadZone; |
||
291 | property DeadZoneZ: Integer index DIJOFS_Z read GetDeadZone write SetDeadZone; |
||
292 | property ID: Integer read FID write SetID; |
||
293 | property RangeX: Integer index DIJOFS_X read GetRange write SetRange; |
||
294 | property RangeY: Integer index DIJOFS_Y read GetRange write SetRange; |
||
295 | property RangeZ: Integer index DIJOFS_Z read GetRange write SetRange; |
||
296 | end; |
||
297 | |||
298 | { TCustomDXInput } |
||
299 | |||
300 | TCustomDXInput = class(TComponent) |
||
301 | private |
||
302 | FActiveOnly: Boolean; |
||
303 | FDevice: TList; |
||
304 | FDInput: IDirectInput; |
||
305 | FForm: TCustomForm; |
||
306 | FJoystick: TJoystick; |
||
307 | FKeyboard: TKeyboard; |
||
308 | FMouse: TMouse; |
||
309 | FOldStates: TDXInputStates; |
||
310 | FStates: TDXInputStates; |
||
311 | FSubClass: TControlSubClass; |
||
312 | FUseDirectInput: Boolean; |
||
313 | procedure Finalize; |
||
314 | procedure Initialize; |
||
315 | procedure FormWndProc(var Message: TMessage; DefWindowProc: TWndMethod); |
||
316 | procedure SetActiveOnly(Value: Boolean); |
||
317 | procedure SetJoystick(Value: TJoystick); |
||
318 | procedure SetKeyboard(Value: TKeyboard); |
||
319 | procedure SetMouse(Value: TMouse); |
||
320 | procedure SetWindowHandle; |
||
321 | procedure SetUseDirectInput(Value: Boolean); |
||
322 | protected |
||
323 | procedure Loaded; override; |
||
324 | public |
||
325 | constructor Create(AOwner: TComponent); override; |
||
326 | destructor Destroy; override; |
||
327 | procedure Update; |
||
328 | property ActiveOnly: Boolean read FActiveOnly write SetActiveOnly; |
||
329 | property Joystick: TJoystick read FJoystick write SetJoystick; |
||
330 | property Keyboard: TKeyboard read FKeyboard write SetKeyboard; |
||
331 | property Mouse: TMouse read FMouse write SetMouse; |
||
332 | property States: TDXInputStates read FStates write FStates; |
||
333 | property UseDirectInput: Boolean read FUseDirectInput write SetUseDirectInput; |
||
334 | end; |
||
335 | |||
336 | { TDXInput } |
||
337 | |||
338 | TDXInput = class(TCustomDXInput) |
||
339 | published |
||
340 | property ActiveOnly; |
||
341 | property Joystick; |
||
342 | property Keyboard; |
||
343 | property Mouse; |
||
344 | property UseDirectInput; |
||
345 | end; |
||
346 | |||
347 | function DefKeyAssign: TKeyAssignList; |
||
348 | function DefKeyAssign2_1: TKeyAssignList; |
||
349 | function DefKeyAssign2_2: TKeyAssignList; |
||
350 | |||
351 | implementation |
||
352 | |||
353 | uses DXConsts; |
||
354 | |||
355 | procedure AssignKey(var KeyAssignList: TKeyAssignList; State: TDXInputState; |
||
356 | const Keys: array of Integer); |
||
357 | var |
||
358 | i, i2: Integer; |
||
359 | KeyAssign: PKeyAssign; |
||
360 | begin |
||
361 | KeyAssign := @KeyAssignList[State]; |
||
362 | FillChar(KeyAssign^, SizeOf(TKeyAssign), 0); |
||
363 | |||
364 | i2 := 0; |
||
365 | for i:=LOW(Keys) to HIGH(Keys) do |
||
366 | begin |
||
367 | if i2<3 then |
||
368 | KeyAssign^[i2] := Keys[i] |
||
369 | else |
||
370 | Exit; |
||
371 | Inc(i2); |
||
372 | end; |
||
373 | end; |
||
374 | |||
375 | function DefKeyAssign: TKeyAssignList; |
||
376 | begin |
||
377 | FillChar(Result, SizeOf(Result), 0); |
||
378 | |||
379 | AssignKey(Result, isUp, [Ord('K'), VK_UP, VK_NUMPAD8]); |
||
380 | AssignKey(Result, isDown, [Ord('J'), VK_DOWN, VK_NUMPAD2]); |
||
381 | AssignKey(Result, isLeft, [Ord('H'), VK_LEFT, VK_NUMPAD4]); |
||
382 | AssignKey(Result, isRight, [Ord('L'), VK_RIGHT, VK_NUMPAD6]); |
||
383 | AssignKey(Result, isButton1, [Ord('Z'), VK_SPACE]); |
||
384 | AssignKey(Result, isButton2, [Ord('X'), VK_RETURN]); |
||
385 | AssignKey(Result, isButton9, [VK_F2]); |
||
386 | end; |
||
387 | |||
388 | function DefKeyAssign2_1: TKeyAssignList; |
||
389 | begin |
||
390 | FillChar(Result, SizeOf(Result), 0); |
||
391 | |||
392 | AssignKey(Result, isUp, [Ord('K'), VK_UP, VK_NUMPAD8]); |
||
393 | AssignKey(Result, isDown, [Ord('J'), VK_DOWN, VK_NUMPAD2]); |
||
394 | AssignKey(Result, isLeft, [Ord('H'), VK_LEFT, VK_NUMPAD4]); |
||
395 | AssignKey(Result, isRight, [Ord('L'), VK_RIGHT, VK_NUMPAD6]); |
||
396 | AssignKey(Result, isButton1, [VK_SPACE , VK_NUMPAD0]); |
||
397 | AssignKey(Result, isButton2, [VK_RETURN, VK_NUMPAD5]); |
||
398 | AssignKey(Result, isButton9, [VK_F2]); |
||
399 | end; |
||
400 | |||
401 | function DefKeyAssign2_2: TKeyAssignList; |
||
402 | begin |
||
403 | FillChar(Result, SizeOf(Result), 0); |
||
404 | |||
405 | AssignKey(Result, isUp, [Ord('E')]); |
||
406 | AssignKey(Result, isDown, [Ord('C')]); |
||
407 | AssignKey(Result, isLeft, [Ord('S')]); |
||
408 | AssignKey(Result, isRight, [Ord('F')]); |
||
409 | AssignKey(Result, isButton1, [Ord('Z')]); |
||
410 | AssignKey(Result, isButton2, [Ord('X')]); |
||
411 | AssignKey(Result, isButton9, [VK_F2]); |
||
412 | end; |
||
413 | |||
414 | { TForceFeedbackEffectObject } |
||
415 | |||
416 | destructor TForceFeedbackEffectObject.Destroy; |
||
417 | begin |
||
418 | Release; |
||
419 | inherited Destroy; |
||
420 | end; |
||
421 | |||
422 | function ConvertTime(i: Integer): DWORD; |
||
423 | begin |
||
424 | if i=-1 then Result := INFINITE else Result := i*1000; |
||
425 | end; |
||
426 | |||
427 | procedure TForceFeedbackEffectObject.Clear; |
||
428 | begin |
||
429 | FillChar(Feff, SizeOf(Feff), 0); |
||
430 | end; |
||
431 | |||
432 | procedure TForceFeedbackEffectObject.Init(Effect: TForceFeedbackEffect); |
||
433 | begin |
||
434 | with FEnvelope do |
||
435 | begin |
||
436 | dwSize := SizeOf(FEnvelope); |
||
437 | |||
438 | dwAttackLevel := Effect.FAttackLevel; |
||
439 | if Effect.FTime<0 then |
||
440 | dwAttackTime := Effect.FAttackTime*1000 |
||
441 | else |
||
442 | dwAttackTime := Min(Effect.FAttackTime, Effect.FTime)*1000; |
||
443 | |||
444 | if Effect.FTime<0 then |
||
445 | begin |
||
446 | dwFadeLevel := 0; |
||
447 | dwFadeTime := 0; |
||
448 | end else |
||
449 | begin |
||
450 | dwFadeLevel := Effect.FFadeLevel; |
||
451 | dwFadeTime := Min(Effect.FFadeTime, Effect.FTime)*1000; |
||
452 | end; |
||
453 | end; |
||
454 | |||
455 | FillChar(Feff, SizeOf(Feff), 0); |
||
456 | with Feff do |
||
457 | begin |
||
458 | dwSize := SizeOf(Feff); |
||
459 | dwFlags := DIEFF_CARTESIAN or DIEFF_OBJECTOFFSETS; |
||
460 | dwDuration := ConvertTime(Effect.FTime); |
||
461 | dwSamplePeriod := 0; |
||
462 | dwGain := Effect.FPower; |
||
463 | dwTriggerButton := DIEB_NOTRIGGER; |
||
464 | dwTriggerRepeatInterval := 0; |
||
465 | cAxes := FAxesCount; |
||
466 | rgdwAxes := @FAxes; |
||
467 | rglDirection := @FDirections; |
||
468 | lpEnvelope := @FEnvelope; |
||
469 | //dwStartDelay := Effect.FStartDelayTime; |
||
470 | end; |
||
471 | end; |
||
472 | |||
473 | procedure TForceFeedbackEffectObject.Release; |
||
474 | begin |
||
475 | FEffect := nil; |
||
476 | end; |
||
477 | |||
478 | { TForceFeedbackEffect } |
||
479 | |||
480 | constructor TForceFeedbackEffect.Create(AParent: TForceFeedbackEffect); |
||
481 | begin |
||
482 | inherited Create; |
||
483 | FParent := AParent; |
||
484 | FList := TList.Create; |
||
485 | |||
486 | if FParent<>nil then |
||
487 | begin |
||
488 | FParent.FList.Add(Self); |
||
489 | FRoot := FParent.FRoot; |
||
490 | end else |
||
491 | begin |
||
492 | FName := 'Effects'; |
||
493 | FRoot := Self as TForceFeedbackEffects; |
||
494 | end; |
||
495 | |||
496 | FObject := TForceFeedbackEffectObject.Create; |
||
497 | FObject2 := TForceFeedbackEffectObject.Create; |
||
498 | |||
499 | AttackTime := 0; |
||
500 | Constant := Point(0, 0); |
||
501 | EffectType := etNone; |
||
502 | FadeTime := 0; |
||
503 | Period := 50; |
||
504 | Power := 10000; |
||
505 | Time := 1000; |
||
506 | end; |
||
507 | |||
508 | destructor TForceFeedbackEffect.Destroy; |
||
509 | begin |
||
510 | Clear; |
||
511 | FObject.Free; |
||
512 | FObject2.Free; |
||
513 | FList.Free; |
||
514 | if FParent<>nil then |
||
515 | FParent.FList.Remove(Self); |
||
516 | inherited Destroy; |
||
517 | end; |
||
518 | |||
519 | function TForceFeedbackEffect.GetOwner: TPersistent; |
||
520 | begin |
||
521 | Result := Parent; |
||
522 | end; |
||
523 | |||
524 | procedure TForceFeedbackEffect.Assign(Source: TPersistent); |
||
525 | var |
||
526 | i: Integer; |
||
527 | begin |
||
528 | if Source is TForceFeedbackEffect then |
||
529 | begin |
||
530 | if Source<>Self then |
||
531 | begin |
||
532 | Clear; |
||
533 | |||
534 | EffectType := etNone; |
||
535 | |||
536 | Name := TForceFeedbackEffect(Source).Name; |
||
537 | |||
538 | AttackLevel := TForceFeedbackEffect(Source).AttackLevel; |
||
539 | AttackTime := TForceFeedbackEffect(Source).AttackTime; |
||
540 | Constant := TForceFeedbackEffect(Source).Constant; |
||
541 | Condition := TForceFeedbackEffect(Source).Condition; |
||
542 | EffectType := TForceFeedbackEffect(Source).EffectType; |
||
543 | FadeLevel := TForceFeedbackEffect(Source).FadeLevel; |
||
544 | FadeTime := TForceFeedbackEffect(Source).FadeTime; |
||
545 | Period := TForceFeedbackEffect(Source).Period; |
||
546 | Power := TForceFeedbackEffect(Source).Power; |
||
547 | Time := TForceFeedbackEffect(Source).Time; |
||
548 | StartDelayTime := TForceFeedbackEffect(Source).StartDelayTime; |
||
549 | |||
550 | EffectType := TForceFeedbackEffect(Source).EffectType; |
||
551 | |||
552 | for i:=0 to TForceFeedbackEffect(Source).Count-1 do |
||
553 | TForceFeedbackEffect.Create(Self).Assign(TForceFeedbackEffect(Source)[i]); |
||
554 | end; |
||
555 | end else |
||
556 | inherited Assign(Source); |
||
557 | end; |
||
558 | |||
559 | procedure TForceFeedbackEffect.Acquire; |
||
560 | var |
||
561 | i: Integer; |
||
562 | begin |
||
563 | if Playing and (Time=-1) then |
||
564 | Start; |
||
565 | |||
566 | for i:=0 to Count-1 do |
||
567 | Effects[i].Initialize; |
||
568 | end; |
||
569 | |||
570 | procedure TForceFeedbackEffect.Clear; |
||
571 | begin |
||
572 | while Count>0 do |
||
573 | Effects[Count-1].Free; |
||
574 | end; |
||
575 | |||
576 | procedure TForceFeedbackEffect.Initialize; |
||
577 | var |
||
578 | i: Integer; |
||
579 | begin |
||
580 | CreateEffect; |
||
581 | for i:=0 to Count-1 do |
||
582 | Effects[i].Initialize; |
||
583 | end; |
||
584 | |||
585 | procedure TForceFeedbackEffect.Finalize; |
||
586 | var |
||
587 | i: Integer; |
||
588 | begin |
||
589 | try |
||
590 | Stop; |
||
591 | FObject.Release; |
||
592 | FObject2.Release; |
||
593 | finally |
||
594 | for i:=0 to Count-1 do |
||
595 | Effects[i].Finalize; |
||
596 | end; |
||
597 | end; |
||
598 | |||
599 | function TForceFeedbackEffect.Find(const Name: string): TForceFeedbackEffect; |
||
600 | var |
||
601 | i, p: Integer; |
||
602 | Effect: TForceFeedbackEffect; |
||
603 | AName: string; |
||
604 | begin |
||
605 | AName := Name; |
||
606 | Effect := Self; |
||
607 | |||
608 | p := AnsiPos('.', AName); |
||
609 | while p<>0 do |
||
610 | begin |
||
611 | i := Effect.IndexOf(AName); |
||
612 | if i<>-1 then |
||
613 | begin |
||
614 | Result := Effect[i]; |
||
615 | Exit; |
||
616 | end else |
||
617 | begin |
||
618 | i := Effect.IndexOf(Copy(Name, 1, p-1)); |
||
619 | if i=-1 then |
||
620 | raise EForceFeedbackEffectError.CreateFmt(SEffectNotFound, [Name]); |
||
621 | Effect := Effect[i]; |
||
622 | AName := Copy(Name, p+1, MaxInt); |
||
623 | p := AnsiPos('.', AName); |
||
624 | end; |
||
625 | end; |
||
626 | |||
627 | i := Effect.IndexOf(Name); |
||
628 | if i=-1 then |
||
629 | raise EForceFeedbackEffectError.CreateFmt(SEffectNotFound, [Name]); |
||
630 | Result := Effect[i]; |
||
631 | end; |
||
632 | |||
633 | function TForceFeedbackEffect.IndexOf(const Name: string): Integer; |
||
634 | var |
||
635 | i: Integer; |
||
636 | begin |
||
637 | Result := -1; |
||
638 | for i:=0 to Count-1 do |
||
639 | if Effects[i].Name=Name then |
||
640 | begin |
||
641 | Result := i; |
||
642 | Break; |
||
643 | end; |
||
644 | end; |
||
645 | |||
646 | function TForceFeedbackEffect.HasInterface: Boolean; |
||
647 | begin |
||
648 | Result := (FEffectType<>etNone) and ((FObject.FEffect<>nil) or (FObject2.FEffect<>nil)); |
||
649 | end; |
||
650 | |||
651 | procedure TForceFeedbackEffect.MakeEff; |
||
652 | var |
||
653 | Constant2: TPoint; |
||
654 | begin |
||
655 | FObject.Clear; |
||
656 | FObject2.Clear; |
||
657 | |||
658 | with Constant2 do |
||
659 | begin |
||
660 | X := -FConstant.X; |
||
661 | Y := -FConstant.Y; |
||
662 | end; |
||
663 | |||
664 | case FEffectType of |
||
665 | etConstantForce: { etConstantForce } |
||
666 | begin |
||
667 | with FObject do |
||
668 | begin |
||
669 | FDirections[0] := Constant2.X; |
||
670 | FDirections[1] := Constant2.Y; |
||
671 | |||
672 | FAxesCount := 2; |
||
673 | FAxes[0] := DIJOFS_X; |
||
674 | FAxes[1] := DIJOFS_Y; |
||
675 | |||
676 | with Constant2 do |
||
677 | FConstantForce.lMagnitude := Trunc(Sqrt(X*X+Y*Y)); |
||
678 | |||
679 | Init(Self); |
||
680 | with Feff do |
||
681 | begin |
||
682 | cbTypeSpecificParams := SizeOf(FConstantForce); |
||
683 | lpvTypeSpecificParams := @FConstantForce; |
||
684 | end; |
||
685 | end; |
||
686 | end; |
||
687 | etPeriodic: { etPeriodic } |
||
688 | begin |
||
689 | with FObject do |
||
690 | begin |
||
691 | FDirections[0] := Constant2.X; |
||
692 | FDirections[1] := Constant2.Y; |
||
693 | |||
694 | FAxesCount := 2; |
||
695 | FAxes[0] := DIJOFS_X; |
||
696 | FAxes[1] := DIJOFS_Y; |
||
697 | |||
698 | with FPeriodic do |
||
699 | begin |
||
700 | with Constant2 do |
||
701 | dwMagnitude := Trunc(Sqrt(X*X+Y*Y)); |
||
702 | lOffset := 0; |
||
703 | dwPhase := 0; |
||
704 | dwPeriod := ConvertTime(FPeriod); |
||
705 | end; |
||
706 | |||
707 | Init(Self); |
||
708 | with Feff do |
||
709 | begin |
||
710 | cbTypeSpecificParams := SizeOf(FPeriodic); |
||
711 | lpvTypeSpecificParams := @FPeriodic; |
||
712 | end; |
||
713 | end; |
||
714 | end; |
||
715 | etCondition: { etCondition } |
||
716 | begin |
||
717 | with FObject do |
||
718 | begin |
||
719 | FillChar(FDirections, SizeOf(FDirections), 0); |
||
720 | |||
721 | FAxesCount := 1; |
||
722 | FAxes[0] := DIJOFS_X; |
||
723 | |||
724 | with FCondition do |
||
725 | begin |
||
726 | lOffset := -Constant2.X; |
||
727 | lPositiveCoefficient := Self.FCondition.X; |
||
728 | lNegativeCoefficient := -Self.FCondition.X; |
||
729 | dwPositiveSaturation := 0; |
||
730 | dwNegativeSaturation := 0; |
||
731 | lDeadBand := 0; |
||
732 | end; |
||
733 | |||
734 | Init(Self); |
||
735 | with Feff do |
||
736 | begin |
||
737 | cbTypeSpecificParams := SizeOf(FCondition); |
||
738 | lpvTypeSpecificParams := @FCondition; |
||
739 | end; |
||
740 | end; |
||
741 | |||
742 | with FObject2 do |
||
743 | begin |
||
744 | FillChar(FDirections, SizeOf(FDirections), 0); |
||
745 | |||
746 | FAxesCount := 1; |
||
747 | FAxes[0] := DIJOFS_Y; |
||
748 | |||
749 | with FCondition do |
||
750 | begin |
||
751 | lOffset := -Constant2.Y; |
||
752 | lPositiveCoefficient := Self.FCondition.Y; |
||
753 | lNegativeCoefficient := -Self.FCondition.Y; |
||
754 | dwPositiveSaturation := 0; |
||
755 | dwNegativeSaturation := 0; |
||
756 | lDeadBand := 0; |
||
757 | end; |
||
758 | |||
759 | Init(Self); |
||
760 | with Feff do |
||
761 | begin |
||
762 | cbTypeSpecificParams := SizeOf(FCondition); |
||
763 | lpvTypeSpecificParams := @FCondition; |
||
764 | end; |
||
765 | end; |
||
766 | end; |
||
767 | end; |
||
768 | end; |
||
769 | |||
770 | procedure TForceFeedbackEffect.CreateEffect; |
||
771 | |||
772 | function FindEffectCallBack(const pdei: TDIEffectInfoA; |
||
773 | pvRef: Pointer): HRESULT; stdcall; |
||
774 | begin |
||
775 | with TForceFeedbackEffect(pvRef) do |
||
776 | begin |
||
777 | FFindEffectFlag := True; |
||
778 | FFindEffectGUID := pdei.guid; |
||
779 | end; |
||
780 | |||
4 | daniel-mar | 781 | Result := Integer(DIENUM_STOP); |
1 | daniel-mar | 782 | end; |
783 | |||
784 | procedure CreateIEffectGuid(const GUID: TGUID; |
||
785 | EffectObject: TForceFeedbackEffectObject); |
||
786 | begin |
||
787 | if EffectObject.Feff.dwSize=0 then Exit; |
||
788 | |||
789 | if FRoot.FInput.FDevice2<>nil then |
||
4 | daniel-mar | 790 | FRoot.FInput.FDevice2.CreateEffect(GUID, @EffectObject.Feff, EffectObject.FEffect, nil); |
1 | daniel-mar | 791 | end; |
792 | |||
793 | procedure CreateIEffect(dwFlags: DWORD; |
||
794 | EffectObject: TForceFeedbackEffectObject); |
||
795 | begin |
||
796 | if EffectObject.Feff.dwSize=0 then Exit; |
||
797 | |||
798 | if FRoot.FInput.FDevice2<>nil then |
||
799 | begin |
||
800 | FFindEffectFlag := False; |
||
801 | FRoot.FInput.FDevice2.EnumEffects(@FindEffectCallBack, |
||
802 | Self, dwFlags); |
||
803 | if FFindEffectFlag then |
||
804 | CreateIEffectGuid(FFindEffectGUID, EffectObject); |
||
805 | end; |
||
806 | end; |
||
807 | |||
808 | begin |
||
809 | FObject.Release; |
||
810 | FObject2.Release; |
||
811 | |||
812 | if (FRoot.FInput=nil) or (FRoot.FInput.FDevice2=nil) or |
||
813 | (not FRoot.FInput.FForceFeedbackDevice) or |
||
814 | (not FRoot.FInput.FForceFeedback) then Exit; |
||
815 | |||
816 | if FEffectType=etNone then Exit; |
||
817 | |||
818 | MakeEff; |
||
819 | case FEffectType of |
||
820 | etConstantForce: |
||
821 | begin |
||
822 | CreateIEffectGUID(GUID_ConstantForce, FObject); |
||
823 | end; |
||
824 | etPeriodic: |
||
825 | begin |
||
826 | CreateIEffect(DIEFT_PERIODIC, FObject); |
||
827 | end; |
||
828 | etCondition: |
||
829 | begin |
||
830 | CreateIEffect(DIEFT_CONDITION, FObject); |
||
831 | CreateIEffect(DIEFT_CONDITION, FObject2); |
||
832 | end; |
||
833 | end; |
||
834 | |||
835 | if Playing and (Time=-1) then |
||
836 | Start; |
||
837 | end; |
||
838 | |||
839 | procedure TForceFeedbackEffect.ChangeEffect; |
||
840 | var |
||
841 | dwFlags: DWORD; |
||
842 | begin |
||
843 | if HasInterface then |
||
844 | begin |
||
845 | MakeEff; |
||
846 | |||
847 | dwFlags := DIEP_DIRECTION or DIEP_DURATION or DIEP_ENVELOPE or |
||
848 | DIEP_GAIN or DIEP_SAMPLEPERIOD or DIEP_TRIGGERBUTTON or |
||
849 | DIEP_TRIGGERREPEATINTERVAL or DIEP_TYPESPECIFICPARAMS; |
||
850 | |||
851 | if Playing then |
||
852 | dwFlags := dwFlags or DIEP_START; |
||
853 | |||
854 | if FObject.FEffect<>nil then FObject.FEffect.SetParameters(FObject.Feff, dwFlags); |
||
855 | if FObject2.FEffect<>nil then FObject2.FEffect.SetParameters(FObject2.Feff, dwFlags); |
||
856 | end; |
||
857 | end; |
||
858 | |||
859 | function TForceFeedbackEffect.GetPlaying: Boolean; |
||
860 | var |
||
861 | dwFlags: DWORD; |
||
862 | begin |
||
863 | Result := False; |
||
864 | |||
865 | if not FPlaying then Exit; |
||
866 | |||
867 | if FPlaying and (FTime=-1) then |
||
868 | begin |
||
869 | Result := True; |
||
870 | Exit; |
||
871 | end; |
||
872 | |||
873 | if FObject.FEffect<>nil then |
||
874 | begin |
||
875 | dwFlags := 0; |
||
876 | FObject.FEffect.GetEffectStatus(dwFlags); |
||
877 | if dwFlags and DIEGES_PLAYING<>0 then |
||
878 | begin |
||
879 | Result := True; |
||
880 | Exit; |
||
881 | end; |
||
882 | end; |
||
883 | |||
884 | if FObject2.FEffect<>nil then |
||
885 | begin |
||
886 | dwFlags := 0; |
||
887 | FObject2.FEffect.GetEffectStatus(dwFlags); |
||
888 | if dwFlags and DIEGES_PLAYING<>0 then |
||
889 | begin |
||
890 | Result := True; |
||
891 | Exit; |
||
892 | end; |
||
893 | end; |
||
894 | |||
895 | if not Result then |
||
896 | FPlaying := False; |
||
897 | end; |
||
898 | |||
899 | function TForceFeedbackEffect.GetCount: Integer; |
||
900 | begin |
||
901 | Result := FList.Count; |
||
902 | end; |
||
903 | |||
904 | function TForceFeedbackEffect.GetEffect(Index: Integer): TForceFeedbackEffect; |
||
905 | begin |
||
906 | Result :=FList[Index]; |
||
907 | end; |
||
908 | |||
909 | function TForceFeedbackEffect.GetIndex: Integer; |
||
910 | begin |
||
911 | if FParent<>nil then |
||
912 | Result := FParent.FList.IndexOf(Self) |
||
913 | else |
||
914 | Result := 0; |
||
915 | end; |
||
916 | |||
917 | procedure TForceFeedbackEffect.SetIndex(Value: Integer); |
||
918 | begin |
||
919 | if FParent<>nil then |
||
920 | begin |
||
921 | FParent.FList.Remove(Self); |
||
922 | FParent.FList.Insert(Value, Self); |
||
923 | end; |
||
924 | end; |
||
925 | |||
926 | procedure TForceFeedbackEffect.SetParent(Value: TForceFeedbackEffect); |
||
927 | begin |
||
928 | if Parent<>Value then |
||
929 | begin |
||
930 | if (Value=nil) or (FRoot<>Value.FRoot) then |
||
931 | raise EForceFeedbackEffectError.CreateFmt(SCannotChanged, ['Parent']); |
||
932 | |||
933 | FParent.FList.Remove(Self); |
||
934 | FParent := Value; |
||
935 | FParent.FList.Add(Self); |
||
936 | end; |
||
937 | end; |
||
938 | |||
939 | procedure TForceFeedbackEffect.SetAttackLevel(Value: Integer); |
||
940 | begin |
||
941 | if Value<0 then Value := 0; |
||
942 | if Value>10000 then Value := 10000; |
||
943 | |||
944 | if FAttackLevel<>Value then |
||
945 | begin |
||
946 | FAttackLevel := Value; |
||
947 | ChangeEffect; |
||
948 | end; |
||
949 | end; |
||
950 | |||
951 | procedure TForceFeedbackEffect.SetAttackTime(Value: Integer); |
||
952 | begin |
||
953 | if Value<0 then Value := 0; |
||
954 | |||
955 | if FAttackTime<>Value then |
||
956 | begin |
||
957 | FAttackTime := Value; |
||
958 | ChangeEffect; |
||
959 | end; |
||
960 | end; |
||
961 | |||
962 | procedure TForceFeedbackEffect.SetCondition(Value: TPoint); |
||
963 | begin |
||
964 | with Value do |
||
965 | begin |
||
966 | if X<-10000 then X := -10000; |
||
967 | if X>+10000 then X := +10000; |
||
968 | |||
969 | if Y<-10000 then Y := -10000; |
||
970 | if Y>+10000 then Y := +10000; |
||
971 | end; |
||
972 | |||
973 | if not CompareMem(@FCondition, @Value, SizeOf(FCondition)) then |
||
974 | begin |
||
975 | FCondition := Value; |
||
976 | |||
977 | if HasInterface then |
||
978 | ChangeEffect; |
||
979 | end; |
||
980 | end; |
||
981 | |||
982 | procedure TForceFeedbackEffect.SetConstant(Value: TPoint); |
||
983 | begin |
||
984 | with Value do |
||
985 | begin |
||
986 | if X<-10000 then X := -10000; |
||
987 | if X>+10000 then X := +10000; |
||
988 | |||
989 | if Y<-10000 then Y := -10000; |
||
990 | if Y>+10000 then Y := +10000; |
||
991 | end; |
||
992 | |||
993 | if not CompareMem(@FConstant, @Value, SizeOf(FConstant)) then |
||
994 | begin |
||
995 | FConstant := Value; |
||
996 | |||
997 | if HasInterface then |
||
998 | ChangeEffect; |
||
999 | end; |
||
1000 | end; |
||
1001 | |||
1002 | procedure TForceFeedbackEffect.SetEffectType(Value: TForceFeedbackEffectType); |
||
1003 | begin |
||
1004 | if FEffectType<>Value then |
||
1005 | begin |
||
1006 | FEffectType := Value; |
||
1007 | Stop; |
||
1008 | CreateEffect; |
||
1009 | end; |
||
1010 | end; |
||
1011 | |||
1012 | procedure TForceFeedbackEffect.SetFadeLevel(Value: Integer); |
||
1013 | begin |
||
1014 | if Value<0 then Value := 0; |
||
1015 | if Value>10000 then Value := 10000; |
||
1016 | |||
1017 | if FFadeLevel<>Value then |
||
1018 | begin |
||
1019 | FFadeLevel := Value; |
||
1020 | ChangeEffect; |
||
1021 | end; |
||
1022 | end; |
||
1023 | |||
1024 | procedure TForceFeedbackEffect.SetFadeTime(Value: Integer); |
||
1025 | begin |
||
1026 | if Value<0 then Value := 0; |
||
1027 | |||
1028 | if FFadeTime<>Value then |
||
1029 | begin |
||
1030 | FFadeTime := Value; |
||
1031 | ChangeEffect; |
||
1032 | end; |
||
1033 | end; |
||
1034 | |||
1035 | procedure TForceFeedbackEffect.SetPeriod(Value: Integer); |
||
1036 | begin |
||
1037 | if Value<0 then Value := 0; |
||
1038 | |||
1039 | if FPeriod<>Value then |
||
1040 | begin |
||
1041 | FPeriod := Value; |
||
1042 | ChangeEffect; |
||
1043 | end; |
||
1044 | end; |
||
1045 | |||
1046 | procedure TForceFeedbackEffect.SetPower(Value: Integer); |
||
1047 | begin |
||
1048 | if Value<0 then Value := 0; |
||
1049 | if Value>10000 then Value := 10000; |
||
1050 | |||
1051 | if FPower<>Value then |
||
1052 | begin |
||
1053 | FPower := Value; |
||
1054 | ChangeEffect; |
||
1055 | end; |
||
1056 | end; |
||
1057 | |||
1058 | procedure TForceFeedbackEffect.SetTime(Value: Integer); |
||
1059 | begin |
||
1060 | if (Value<>-1) and (Value<0) then Value := 0; |
||
1061 | |||
1062 | if FTime<>Value then |
||
1063 | begin |
||
1064 | FTime := Value; |
||
1065 | Stop; |
||
1066 | ChangeEffect; |
||
1067 | end; |
||
1068 | end; |
||
1069 | |||
1070 | procedure TForceFeedbackEffect.SetStartDelayTime(Value: Integer); |
||
1071 | begin |
||
1072 | if Value<0 then Value := 0; |
||
1073 | |||
1074 | if FStartDelayTime<>Value then |
||
1075 | begin |
||
1076 | FStartDelayTime := Value; |
||
1077 | Stop; |
||
1078 | ChangeEffect; |
||
1079 | end; |
||
1080 | end; |
||
1081 | |||
1082 | procedure TForceFeedbackEffect.Start; |
||
1083 | |||
1084 | procedure StartEffect(Effect: IDirectInputEffect); |
||
1085 | var |
||
1086 | hr: HRESULT; |
||
1087 | begin |
||
1088 | if Effect<>nil then |
||
1089 | begin |
||
1090 | hr := Effect.Start(1, 0); |
||
1091 | if (hr=DIERR_INPUTLOST) or (hr=DIERR_NOTACQUIRED) then |
||
1092 | begin |
||
1093 | FRoot.FInput.Acquire; |
||
1094 | Effect.Start(1, 0); |
||
1095 | end; |
||
1096 | end; |
||
1097 | end; |
||
1098 | |||
1099 | var |
||
1100 | i: Integer; |
||
1101 | begin |
||
1102 | for i:=0 to Count-1 do |
||
1103 | Effects[i].Start; |
||
1104 | |||
1105 | if not HasInterface then |
||
1106 | begin |
||
1107 | CreateEffect; |
||
1108 | if not HasInterface then Exit; |
||
1109 | end; |
||
1110 | |||
1111 | StartEffect(FObject.FEffect); |
||
1112 | StartEffect(FObject2.FEffect); |
||
1113 | |||
1114 | FPlaying := True; |
||
1115 | end; |
||
1116 | |||
1117 | procedure TForceFeedbackEffect.Stop; |
||
1118 | var |
||
1119 | i: Integer; |
||
1120 | begin |
||
1121 | if Playing then |
||
1122 | begin |
||
1123 | FPlaying := False; |
||
1124 | if FObject.FEffect<>nil then FObject.FEffect.Stop; |
||
1125 | if FObject2.FEffect<>nil then FObject2.FEffect.Stop; |
||
1126 | end; |
||
1127 | |||
1128 | for i:=0 to Count-1 do |
||
1129 | Effects[i].Stop; |
||
1130 | end; |
||
1131 | |||
1132 | procedure TForceFeedbackEffect.Unload(Recurse: Boolean); |
||
1133 | var |
||
1134 | i: Integer; |
||
1135 | begin |
||
1136 | if Playing then |
||
1137 | begin |
||
1138 | if FObject.FEffect<>nil then FObject.FEffect.Stop; |
||
1139 | if FObject2.FEffect<>nil then FObject2.FEffect.Stop; |
||
1140 | end; |
||
1141 | |||
1142 | if FObject.FEffect<>nil then FObject.FEffect.Unload; |
||
1143 | if FObject2.FEffect<>nil then FObject2.FEffect.Unload; |
||
1144 | |||
1145 | if Recurse then |
||
1146 | begin |
||
1147 | for i:=0 to Count-1 do |
||
1148 | Effects[i].Unload(True); |
||
1149 | end; |
||
1150 | end; |
||
1151 | |||
1152 | type |
||
1153 | TForceFeedbackEffectItem = class(TCollectionItem) |
||
1154 | private |
||
1155 | FName: string; |
||
1156 | FEffectType: TForceFeedbackEffectType; |
||
1157 | FAttackLevel: Integer; |
||
1158 | FAttackTime: Integer; |
||
1159 | FConditionX: Integer; |
||
1160 | FConditionY: Integer; |
||
1161 | FConstantX: Integer; |
||
1162 | FConstantY: Integer; |
||
1163 | FFadeLevel: Integer; |
||
1164 | FFadeTime: Integer; |
||
1165 | FPeriod: Integer; |
||
1166 | FPower: Integer; |
||
1167 | FTime: Integer; |
||
1168 | FStartDelayTime: Integer; |
||
1169 | FEffects: TCollection; |
||
1170 | function GetStoredEffects: Boolean; |
||
1171 | public |
||
1172 | constructor Create(Collection: TCollection); override; |
||
1173 | destructor Destroy; override; |
||
1174 | procedure Assign(Source: TPersistent); override; |
||
1175 | procedure AssignTo(Dest: TPersistent); override; |
||
1176 | published |
||
1177 | property Name: string read FName write FName; |
||
1178 | property EffectType: TForceFeedbackEffectType read FEffectType write FEffectType; |
||
1179 | property AttackLevel: Integer read FAttackLevel write FAttackLevel default 0; |
||
1180 | property AttackTime: Integer read FAttackTime write FAttackTime default 0; |
||
1181 | property ConditionX: Integer read FConditionX write FConditionX default 0; |
||
1182 | property ConditionY: Integer read FConditionY write FConditionY default 0; |
||
1183 | property ConstantX: Integer read FConstantX write FConstantX default 0; |
||
1184 | property ConstantY: Integer read FConstantY write FConstantY default 0; |
||
1185 | property FadeLevel: Integer read FFadeLevel write FFadeLevel default 0; |
||
1186 | property FadeTime: Integer read FFadeTime write FFadeTime default 0; |
||
1187 | property Period: Integer read FPeriod write FPeriod; |
||
1188 | property Power: Integer read FPower write FPower; |
||
1189 | property Time: Integer read FTime write FTime; |
||
1190 | property StartDelayTime: Integer read FStartDelayTime write FStartDelayTime; |
||
1191 | property Effects: TCollection read FEffects write FEffects stored GetStoredEffects; |
||
1192 | end; |
||
1193 | |||
1194 | TForceFeedbackEffectComponent = class(TComponent) |
||
1195 | private |
||
1196 | FEffects: TCollection; |
||
1197 | published |
||
1198 | property Effects: TCollection read FEffects write FEffects; |
||
1199 | end; |
||
1200 | |||
1201 | constructor TForceFeedbackEffectItem.Create(Collection: TCollection); |
||
1202 | begin |
||
1203 | inherited Create(Collection); |
||
1204 | FEffects := TCollection.Create(TForceFeedbackEffectItem); |
||
1205 | end; |
||
1206 | |||
1207 | destructor TForceFeedbackEffectItem.Destroy; |
||
1208 | begin |
||
1209 | FEffects.Free; |
||
1210 | inherited Destroy; |
||
1211 | end; |
||
1212 | |||
1213 | procedure TForceFeedbackEffectItem.Assign(Source: TPersistent); |
||
1214 | var |
||
1215 | Effect: TForceFeedbackEffect; |
||
1216 | i: Integer; |
||
1217 | begin |
||
1218 | Effect := Source as TForceFeedbackEffect; |
||
1219 | |||
1220 | FName := Effect.Name; |
||
1221 | FEffectType := Effect.EffectType; |
||
1222 | FAttackLevel := Effect.AttackLevel; |
||
1223 | FAttackTime := Effect.AttackTime; |
||
1224 | FConditionX := Effect.Condition.X; |
||
1225 | FConditionY := Effect.Condition.Y; |
||
1226 | FConstantX := Effect.Constant.X; |
||
1227 | FConstantY := Effect.Constant.Y; |
||
1228 | FFadeLevel := Effect.FadeLevel; |
||
1229 | FFadeTime := Effect.FadeTime; |
||
1230 | FPeriod := Effect.Period; |
||
1231 | FPower := Effect.Power; |
||
1232 | FTime := Effect.Time; |
||
1233 | FStartDelayTime := Effect.StartDelayTime; |
||
1234 | |||
1235 | for i:=0 to Effect.Count-1 do |
||
1236 | TForceFeedbackEffectItem.Create(FEffects).Assign(Effect[i]); |
||
1237 | end; |
||
1238 | |||
1239 | procedure TForceFeedbackEffectItem.AssignTo(Dest: TPersistent); |
||
1240 | var |
||
1241 | Effect: TForceFeedbackEffect; |
||
1242 | i: Integer; |
||
1243 | begin |
||
1244 | Effect := Dest as TForceFeedbackEffect; |
||
1245 | |||
1246 | Effect.EffectType := etNone; |
||
1247 | |||
1248 | Effect.Name := FName; |
||
1249 | Effect.AttackLevel := FAttackLevel; |
||
1250 | Effect.AttackTime := FAttackTime; |
||
1251 | Effect.Condition := Point(FConditionX, FConditionY); |
||
1252 | Effect.Constant := Point(FConstantX, FConstantY); |
||
1253 | Effect.FadeLevel := FFadeLevel; |
||
1254 | Effect.FadeTime := FFadeTime; |
||
1255 | Effect.Period := FPeriod; |
||
1256 | Effect.Power := FPower; |
||
1257 | Effect.Time := FTime; |
||
1258 | Effect.StartDelayTime := FStartDelayTime; |
||
1259 | |||
1260 | Effect.EffectType := FEffectType; |
||
1261 | |||
1262 | for i:=0 to FEffects.Count-1 do |
||
1263 | TForceFeedbackEffectItem(FEffects.Items[i]).AssignTo(TForceFeedbackEffect.Create(Effect)); |
||
1264 | end; |
||
1265 | |||
1266 | function TForceFeedbackEffectItem.GetStoredEffects: Boolean; |
||
1267 | begin |
||
1268 | Result := FEffects.Count>0; |
||
1269 | end; |
||
1270 | |||
1271 | procedure TForceFeedbackEffect.LoadFromFile(const FileName: string); |
||
1272 | var |
||
1273 | Stream: TFileStream; |
||
1274 | begin |
||
1275 | Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); |
||
1276 | try |
||
1277 | LoadFromStream(Stream); |
||
1278 | finally |
||
1279 | Stream.Free; |
||
1280 | end; |
||
1281 | end; |
||
1282 | |||
1283 | procedure TForceFeedbackEffect.LoadFromStream(Stream: TStream); |
||
1284 | var |
||
1285 | Component: TForceFeedbackEffectComponent; |
||
1286 | begin |
||
1287 | Clear; |
||
1288 | |||
1289 | Component := TForceFeedbackEffectComponent(FRoot.FComponent); |
||
1290 | try |
||
1291 | Component.FEffects := TCollection.Create(TForceFeedbackEffectItem); |
||
1292 | Stream.ReadComponentRes(Component); |
||
1293 | TForceFeedbackEffectItem(Component.FEffects.Items[0]).AssignTo(Self); |
||
1294 | finally |
||
1295 | Component.FEffects.Free; |
||
1296 | Component.FEffects := nil; |
||
1297 | end; |
||
1298 | end; |
||
1299 | |||
1300 | procedure TForceFeedbackEffect.SaveToFile(const FileName: string); |
||
1301 | var |
||
1302 | Stream: TFileStream; |
||
1303 | begin |
||
1304 | Stream := TFileStream.Create(FileName, fmCreate); |
||
1305 | try |
||
1306 | SaveToStream(Stream); |
||
1307 | finally |
||
1308 | Stream.Free; |
||
1309 | end; |
||
1310 | end; |
||
1311 | |||
1312 | procedure TForceFeedbackEffect.SaveToStream(Stream: TStream); |
||
1313 | var |
||
1314 | Component: TForceFeedbackEffectComponent; |
||
1315 | begin |
||
1316 | Component := TForceFeedbackEffectComponent(FRoot.FComponent); |
||
1317 | try |
||
1318 | Component.FEffects := TCollection.Create(TForceFeedbackEffectItem); |
||
1319 | TForceFeedbackEffectItem.Create(Component.FEffects).Assign(Self); |
||
1320 | Stream.WriteComponentRes('DelphiXForceFeedbackEffect', Component); |
||
1321 | finally |
||
1322 | Component.FEffects.Free; |
||
1323 | Component.FEffects := nil; |
||
1324 | end; |
||
1325 | end; |
||
1326 | |||
1327 | { TForceFeedbackEffects } |
||
1328 | |||
1329 | constructor TForceFeedbackEffects.Create(Input: TCustomInput); |
||
1330 | begin |
||
1331 | inherited Create(nil); |
||
1332 | FInput := Input; |
||
1333 | FComponent := TForceFeedbackEffectComponent.Create(nil); |
||
1334 | end; |
||
1335 | |||
1336 | destructor TForceFeedbackEffects.Destroy; |
||
1337 | begin |
||
1338 | FComponent.Free; |
||
1339 | inherited Destroy; |
||
1340 | end; |
||
1341 | |||
1342 | procedure TForceFeedbackEffects.DefineProperties(Filer: TFiler); |
||
1343 | begin |
||
1344 | inherited DefineProperties(Filer); |
||
1345 | Filer.DefineBinaryProperty('Effects', LoadFromStream, SaveToStream, True); |
||
1346 | end; |
||
1347 | |||
1348 | { TCustomInput } |
||
1349 | |||
1350 | constructor TCustomInput.Create(DXInput: TCustomDXInput); |
||
1351 | begin |
||
1352 | inherited Create; |
||
1353 | FDXInput := DXInput; |
||
1354 | FDXInput.FDevice.Add(Self); |
||
1355 | FEffects := TForceFeedbackEffects.Create(Self); |
||
1356 | FEnabled := True; |
||
1357 | FBindInputStates := True; |
||
1358 | end; |
||
1359 | |||
1360 | destructor TCustomInput.Destroy; |
||
1361 | begin |
||
1362 | Finalize; |
||
1363 | FEffects.Free; |
||
1364 | FDXInput.FDevice.Remove(Self); |
||
1365 | inherited Destroy; |
||
1366 | end; |
||
1367 | |||
1368 | procedure TCustomInput.Acquire; |
||
1369 | begin |
||
1370 | if FDXInput.FActiveOnly and (GetForegroundWindow<>FDXInput.FForm.Handle) then |
||
1371 | Exit; |
||
1372 | |||
1373 | if FDevice<>nil then |
||
1374 | FDevice.Acquire; |
||
1375 | |||
1376 | FEffects.Acquire; |
||
1377 | end; |
||
1378 | |||
1379 | procedure TCustomInput.Finalize; |
||
1380 | begin |
||
1381 | if FDevice<>nil then FDevice.Unacquire; |
||
1382 | FInitialized := False; |
||
1383 | FButtonCount := 0; |
||
1384 | FEffects.Finalize; |
||
1385 | FDevice := nil; |
||
1386 | FDevice2 := nil; |
||
1387 | FForceFeedbackDevice := False; |
||
1388 | FStates := []; |
||
1389 | end; |
||
1390 | |||
1391 | procedure TCustomInput.Initialize; |
||
1392 | begin |
||
1393 | FInitialized := True; |
||
1394 | FEffects.Initialize; |
||
1395 | end; |
||
1396 | |||
1397 | function TCustomInput.GetButton(Index: Integer): Boolean; |
||
1398 | begin |
||
1399 | if Index in [0..31] then |
||
1400 | Result := TDXInputState(Integer(isButton1)+Index) in FStates |
||
1401 | else |
||
1402 | Result := False; |
||
1403 | end; |
||
1404 | |||
1405 | function TCustomInput.GetCooperativeLevel: Integer; |
||
1406 | const |
||
1407 | Levels: array[Boolean] of Integer = (DISCL_NONEXCLUSIVE, DISCL_EXCLUSIVE); |
||
1408 | Levels2: array[Boolean] of Integer = (DISCL_BACKGROUND, DISCL_FOREGROUND); |
||
1409 | begin |
||
1410 | Result := Levels[FForceFeedbackDevice and FForceFeedback] or Levels2[FDXInput.ActiveOnly]; |
||
1411 | end; |
||
1412 | |||
1413 | function TCustomInput.GetDeviceState(dwSize: Integer; var Data): Boolean; |
||
1414 | var |
||
1415 | hr: HRESULT; |
||
1416 | begin |
||
1417 | FillChar(Data, dwSize, 0); |
||
1418 | |||
1419 | if FDevice<>nil then |
||
1420 | begin |
||
4 | daniel-mar | 1421 | hr := FDevice.GetDeviceState(dwSize, @Data); |
1 | daniel-mar | 1422 | if (hr=DIERR_INPUTLOST) or (hr=DIERR_NOTACQUIRED) then |
1423 | begin |
||
1424 | FDevice.Acquire; |
||
4 | daniel-mar | 1425 | hr := FDevice.GetDeviceState(dwSize, @Data); |
1 | daniel-mar | 1426 | end; |
1427 | Result := hr=DI_OK; |
||
1428 | end else |
||
1429 | Result := False; |
||
1430 | end; |
||
1431 | |||
1432 | function TCustomInput.SetDataFormat: Boolean; |
||
1433 | |||
1434 | function DIEnumDeviceObjectsProc(const peff: TDIDeviceObjectInstanceA; |
||
1435 | pvRef: Pointer): HRESULT; stdcall; |
||
1436 | begin |
||
4 | daniel-mar | 1437 | Result := Integer(DIENUM_CONTINUE); |
1 | daniel-mar | 1438 | |
1439 | if CompareMem(@peff.guidType, @GUID_Unknown, SizeOf(TGUID)) then Exit; |
||
1440 | |||
1441 | with TCustomInput(pvRef) do |
||
1442 | begin |
||
1443 | if peff.dwOfs<FDataFormat.dwDataSize then |
||
1444 | begin |
||
1445 | FDataFormatGUIDs[FDataFormat.dwNumObjs] := peff.guidType; |
||
1446 | |||
1447 | with FDataFormatObjects[FDataFormat.dwNumObjs] do |
||
1448 | begin |
||
1449 | pguid := @FDataFormatGUIDs[FDataFormat.dwNumObjs]; |
||
1450 | dwOfs := peff.dwOfs; |
||
1451 | dwType := peff.dwType; |
||
1452 | dwFlags := 0; |
||
1453 | end; |
||
1454 | Inc(FDataFormat.dwNumObjs); |
||
1455 | end; |
||
1456 | end; |
||
1457 | end; |
||
1458 | |||
1459 | begin |
||
1460 | Result := False; |
||
1461 | if FDevice<>nil then |
||
1462 | begin |
||
1463 | with FDataFormat do |
||
1464 | begin |
||
1465 | dwSize := SizeOf(FDataFormat); |
||
1466 | dwObjSize := SizeOf(TDIObjectDataFormat); |
||
1467 | dwNumObjs := 0; |
||
1468 | rgodf := @FDataFormatObjects; |
||
1469 | end; |
||
1470 | |||
1471 | FDevice.EnumObjects(@DIEnumDeviceObjectsProc, Self, DIDFT_ALL); |
||
1472 | if FDevice.SetDataFormat(FDataFormat)<>DI_OK then Exit; |
||
1473 | end; |
||
1474 | Result := True; |
||
1475 | end; |
||
1476 | |||
1477 | procedure TCustomInput.SetEffects(Value: TForceFeedbackEffects); |
||
1478 | begin |
||
1479 | FEffects.Assign(Value); |
||
1480 | end; |
||
1481 | |||
1482 | procedure TCustomInput.SetEnabled(Value: Boolean); |
||
1483 | begin |
||
1484 | if FEnabled<>Value then |
||
1485 | begin |
||
1486 | FEnabled := Value; |
||
1487 | if FDXInput.ComponentState*[csLoading, csReading]=[] then |
||
1488 | Initialize; |
||
1489 | end; |
||
1490 | end; |
||
1491 | |||
1492 | procedure TCustomInput.SetForceFeedback(Value: Boolean); |
||
1493 | begin |
||
1494 | if FForceFeedback<>Value then |
||
1495 | begin |
||
1496 | FForceFeedback := Value; |
||
1497 | if FDXInput.ComponentState*[csLoading, csReading]=[] then |
||
1498 | Initialize; |
||
1499 | end; |
||
1500 | end; |
||
1501 | |||
1502 | procedure TCustomInput.SetWindowHandle(Value: Integer); |
||
1503 | begin |
||
1504 | if FDevice<>nil then |
||
1505 | FDevice.SetCooperativeLevel(Value, GetCooperativeLevel); |
||
1506 | end; |
||
1507 | |||
1508 | { TKeyboard } |
||
1509 | |||
1510 | constructor TKeyboard.Create(DXInput: TCustomDXInput); |
||
1511 | begin |
||
1512 | inherited Create(DXInput); |
||
1513 | KeyAssigns := DefKeyAssign; |
||
1514 | end; |
||
1515 | |||
1516 | procedure TKeyboard.DefineProperties(Filer: TFiler); |
||
1517 | begin |
||
1518 | inherited DefineProperties(Filer); |
||
1519 | Filer.DefineBinaryProperty('Aissgns', ReadAssigns, WriteAssigns, False); |
||
1520 | Filer.DefineBinaryProperty('Assigns', ReadAssigns, WriteAssigns, True); |
||
1521 | end; |
||
1522 | |||
1523 | function TKeyboard.GetKey(Key: Integer): Boolean; |
||
1524 | begin |
||
1525 | if Key in [1..255] then |
||
1526 | Result := FKeyStates[Key] and $80<>0 |
||
1527 | else |
||
1528 | Result := False; |
||
1529 | end; |
||
1530 | |||
1531 | procedure TKeyboard.Finalize; |
||
1532 | begin |
||
1533 | FillChar(FKeyStates, SizeOf(FKeyStates), 0); |
||
1534 | inherited Finalize; |
||
1535 | end; |
||
1536 | |||
1537 | procedure TKeyboard.Initialize; |
||
1538 | begin |
||
1539 | Finalize; |
||
1540 | |||
1541 | if (not FEnabled) or (csDesigning in FDXInput.ComponentState) then Exit; |
||
1542 | |||
1543 | if FDXInput.FDInput<>nil then |
||
1544 | begin |
||
1545 | if FDXInput.FDInput.CreateDevice(GUID_SysKeyboard, FDevice, nil)<>DI_OK then Exit; |
||
1546 | FDevice.SetDataFormat(c_dfDIKeyboard); |
||
1547 | end; |
||
1548 | |||
1549 | FButtonCount := 32; |
||
1550 | |||
1551 | inherited Initialize; |
||
1552 | end; |
||
1553 | |||
1554 | procedure TKeyboard.Update; |
||
1555 | |||
1556 | function DIKEYtoVK(Key: Byte): Integer; |
||
1557 | begin |
||
1558 | Result := 0; |
||
1559 | case Key of |
||
1560 | DIK_ESCAPE : Result := VK_ESCAPE; |
||
1561 | DIK_1 : Result := Ord('1'); |
||
1562 | DIK_2 : Result := Ord('2'); |
||
1563 | DIK_3 : Result := Ord('3'); |
||
1564 | DIK_4 : Result := Ord('4'); |
||
1565 | DIK_5 : Result := Ord('5'); |
||
1566 | DIK_6 : Result := Ord('6'); |
||
1567 | DIK_7 : Result := Ord('7'); |
||
1568 | DIK_8 : Result := Ord('8'); |
||
1569 | DIK_9 : Result := Ord('9'); |
||
1570 | DIK_0 : Result := Ord('0'); |
||
1571 | DIK_EQUALS : Result := Ord('='); |
||
1572 | DIK_BACK : Result := VK_BACK; |
||
1573 | DIK_TAB : Result := VK_TAB; |
||
1574 | DIK_Q : Result := Ord('Q'); |
||
1575 | DIK_W : Result := Ord('W'); |
||
1576 | DIK_E : Result := Ord('E'); |
||
1577 | DIK_R : Result := Ord('R'); |
||
1578 | DIK_T : Result := Ord('T'); |
||
1579 | DIK_Y : Result := Ord('Y'); |
||
1580 | DIK_U : Result := Ord('U'); |
||
1581 | DIK_I : Result := Ord('I'); |
||
1582 | DIK_O : Result := Ord('O'); |
||
1583 | DIK_P : Result := Ord('P'); |
||
1584 | DIK_LBRACKET : Result := Ord('['); |
||
1585 | DIK_RBRACKET : Result := Ord(']'); |
||
1586 | DIK_RETURN : Result := VK_RETURN; |
||
1587 | DIK_LCONTROL : Result := VK_CONTROL; |
||
1588 | DIK_A : Result := Ord('A'); |
||
1589 | DIK_S : Result := Ord('S'); |
||
1590 | DIK_D : Result := Ord('D'); |
||
1591 | DIK_F : Result := Ord('F'); |
||
1592 | DIK_G : Result := Ord('G'); |
||
1593 | DIK_H : Result := Ord('H'); |
||
1594 | DIK_J : Result := Ord('J'); |
||
1595 | DIK_K : Result := Ord('K'); |
||
1596 | DIK_L : Result := Ord('L'); |
||
1597 | DIK_SEMICOLON : Result := Ord(';'); |
||
1598 | DIK_APOSTROPHE : Result := Ord(''''); |
||
1599 | DIK_LSHIFT : Result := VK_SHIFT; |
||
1600 | DIK_BACKSLASH : Result := Ord('\'); |
||
1601 | DIK_Z : Result := Ord('Z'); |
||
1602 | DIK_X : Result := Ord('X'); |
||
1603 | DIK_C : Result := Ord('C'); |
||
1604 | DIK_V : Result := Ord('V'); |
||
1605 | DIK_B : Result := Ord('B'); |
||
1606 | DIK_N : Result := Ord('N'); |
||
1607 | DIK_M : Result := Ord('M'); |
||
1608 | DIK_COMMA : Result := Ord(','); |
||
1609 | DIK_PERIOD : Result := Ord('.'); |
||
1610 | DIK_SLASH : Result := Ord('/'); |
||
1611 | DIK_RSHIFT : Result := VK_SHIFT; |
||
1612 | DIK_MULTIPLY : Result := Ord('*'); |
||
1613 | DIK_LMENU : Result := VK_MENU; |
||
1614 | DIK_SPACE : Result := VK_SPACE; |
||
1615 | DIK_CAPITAL : Result := VK_CAPITAL; |
||
1616 | DIK_F1 : Result := VK_F1; |
||
1617 | DIK_F2 : Result := VK_F2; |
||
1618 | DIK_F3 : Result := VK_F3; |
||
1619 | DIK_F4 : Result := VK_F4; |
||
1620 | DIK_F5 : Result := VK_F5; |
||
1621 | DIK_F6 : Result := VK_F6; |
||
1622 | DIK_F7 : Result := VK_F7; |
||
1623 | DIK_F8 : Result := VK_F8; |
||
1624 | DIK_F9 : Result := VK_F9; |
||
1625 | DIK_F10 : Result := VK_F10; |
||
1626 | DIK_NUMLOCK : Result := VK_NUMLOCK; |
||
1627 | DIK_SCROLL : Result := VK_SCROLL; |
||
1628 | DIK_NUMPAD7 : Result := VK_NUMPAD7; |
||
1629 | DIK_NUMPAD8 : Result := VK_NUMPAD8; |
||
1630 | DIK_NUMPAD9 : Result := VK_NUMPAD9; |
||
1631 | DIK_SUBTRACT : Result := VK_SUBTRACT; |
||
1632 | DIK_NUMPAD4 : Result := VK_NUMPAD4; |
||
1633 | DIK_NUMPAD5 : Result := VK_NUMPAD5; |
||
1634 | DIK_NUMPAD6 : Result := VK_NUMPAD6; |
||
1635 | DIK_ADD : Result := VK_ADD; |
||
1636 | DIK_NUMPAD1 : Result := VK_NUMPAD1; |
||
1637 | DIK_NUMPAD2 : Result := VK_NUMPAD2; |
||
1638 | DIK_NUMPAD3 : Result := VK_NUMPAD3; |
||
1639 | DIK_NUMPAD0 : Result := VK_NUMPAD0; |
||
1640 | DIK_DECIMAL : Result := VK_DECIMAL; |
||
1641 | DIK_F11 : Result := VK_F11; |
||
1642 | DIK_F12 : Result := VK_F12; |
||
1643 | DIK_NUMPADENTER : Result := VK_RETURN; |
||
1644 | DIK_RCONTROL : Result := VK_CONTROL; |
||
1645 | DIK_DIVIDE : Result := VK_DIVIDE; |
||
1646 | DIK_RMENU : Result := VK_MENU; |
||
1647 | DIK_HOME : Result := VK_HOME; |
||
1648 | DIK_UP : Result := VK_UP; |
||
1649 | DIK_PRIOR : Result := VK_PRIOR; |
||
1650 | DIK_LEFT : Result := VK_LEFT; |
||
1651 | DIK_RIGHT : Result := VK_RIGHT; |
||
1652 | DIK_END : Result := VK_END; |
||
1653 | DIK_DOWN : Result := VK_DOWN; |
||
1654 | DIK_NEXT : Result := VK_NEXT; |
||
1655 | DIK_INSERT : Result := VK_INSERT; |
||
1656 | DIK_DELETE : Result := VK_DELETE; |
||
1657 | DIK_LWIN : Result := VK_LWIN; |
||
1658 | DIK_RWIN : Result := VK_RWIN; |
||
1659 | DIK_APPS : Result := VK_APPS; |
||
1660 | end; |
||
1661 | end; |
||
4 | daniel-mar | 1662 | {$IFDEF StandardDX} |
1663 | type |
||
1664 | TDIKeyboardState = array[0..255] of Byte; |
||
1665 | {$ENDIF} |
||
1666 | var |
||
1 | daniel-mar | 1667 | j: Integer; |
1668 | i: TDXInputState; |
||
1669 | dikb: TDIKeyboardState; |
||
1670 | begin |
||
1671 | FillChar(FKeyStates, SizeOf(FKeyStates), 0); |
||
1672 | FStates := []; |
||
1673 | |||
1674 | if (not FInitialized) or FDXInput.FActiveOnly and (GetForegroundWindow<>FDXInput.FForm.Handle) then |
||
1675 | Exit; |
||
1676 | |||
1677 | if FDevice<>nil then |
||
1678 | begin |
||
1679 | FillChar(dikb, SizeOf(dikb), 0); |
||
1680 | |||
1681 | if GetDeviceState(SizeOf(dikb), dikb) then |
||
1682 | begin |
||
1683 | { The DirectInput key code is converted into the Windows virtual key code. } |
||
1684 | for j:=Low(dikb) to High(dikb) do |
||
1685 | if dikb[j] and $80<>0 then |
||
1686 | FKeyStates[Byte(DIKEYtoVK(j))] := $80; |
||
1687 | end; |
||
1688 | end else |
||
1689 | begin |
||
1690 | GetKeyboardState(FKeyStates); |
||
1691 | end; |
||
1692 | |||
1693 | for i:=LOW(TDXInputState) to HIGH(TDXInputState) do |
||
1694 | begin |
||
1695 | for j:=0 to 2 do |
||
1696 | if Keys[KeyAssigns[i, j]] then |
||
1697 | begin |
||
1698 | FStates := FStates + [i]; |
||
1699 | Break; |
||
1700 | end; |
||
1701 | end; |
||
1702 | end; |
||
1703 | |||
1704 | procedure TKeyboard.ReadAssigns(Stream: TStream); |
||
1705 | begin |
||
1706 | Stream.ReadBuffer(KeyAssigns, SizeOf(KeyAssigns)); |
||
1707 | end; |
||
1708 | |||
1709 | procedure TKeyboard.WriteAssigns(Stream: TStream); |
||
1710 | begin |
||
1711 | Stream.WriteBuffer(KeyAssigns, SizeOf(KeyAssigns)); |
||
1712 | end; |
||
1713 | |||
1714 | { TMouse } |
||
1715 | |||
1716 | constructor TMouse.Create(DXInput: TCustomDXInput); |
||
1717 | begin |
||
1718 | inherited Create(DXInput); |
||
1719 | BindInputStates := False; |
||
1720 | Enabled := False; |
||
1721 | end; |
||
1722 | |||
1723 | function TMouse.GetX: Integer; |
||
1724 | begin |
||
1725 | Result := Fdims.lX; |
||
1726 | end; |
||
1727 | |||
1728 | function TMouse.GetY: Integer; |
||
1729 | begin |
||
1730 | Result := Fdims.lY; |
||
1731 | end; |
||
1732 | |||
1733 | function TMouse.GetZ: Integer; |
||
1734 | begin |
||
1735 | Result := Fdims.lZ; |
||
1736 | end; |
||
1737 | |||
1738 | procedure TMouse.Finalize; |
||
1739 | begin |
||
1740 | FillChar(Fdims, SizeOf(Fdims), 0); |
||
1741 | inherited Finalize; |
||
1742 | end; |
||
1743 | |||
1744 | procedure TMouse.Initialize; |
||
1745 | begin |
||
1746 | Finalize; |
||
1747 | |||
1748 | if (not FEnabled) or (csDesigning in FDXInput.ComponentState) then Exit; |
||
1749 | |||
1750 | if FDXInput.FDInput<>nil then |
||
1751 | begin |
||
1752 | if FDXInput.FDInput.CreateDevice(GUID_SysMouse, FDevice, nil)<>DI_OK then Exit; |
||
1753 | FDevice.SetDataFormat(c_dfDIMouse); |
||
1754 | end else |
||
1755 | raise EDXInputError.Create(SNecessaryDirectInputUseMouse); |
||
1756 | |||
1757 | FButtonCount := 3; |
||
1758 | |||
1759 | inherited Initialize; |
||
1760 | end; |
||
1761 | |||
1762 | procedure TMouse.Update; |
||
1763 | begin |
||
1764 | FillChar(Fdims, SizeOf(Fdims), 0); |
||
1765 | FStates := []; |
||
1766 | |||
1767 | if (not FInitialized) or FDXInput.FActiveOnly and (GetForegroundWindow<>FDXInput.FForm.Handle) then |
||
1768 | Exit; |
||
1769 | |||
1770 | if FDevice<>nil then |
||
1771 | begin |
||
1772 | FillChar(Fdims, SizeOf(Fdims), 0); |
||
1773 | GetDeviceState(SizeOf(Fdims), Fdims); |
||
1774 | end; |
||
1775 | |||
1776 | if Fdims.lX<0 then FStates := FStates + [isLeft]; |
||
1777 | if Fdims.lX>0 then FStates := FStates + [isRight]; |
||
1778 | if Fdims.lY<0 then FStates := FStates + [isUp]; |
||
1779 | if Fdims.lY>0 then FStates := FStates + [isDown]; |
||
1780 | |||
1781 | if Fdims.rgbButtons[0] and $80<>0 then FStates := FStates + [isButton1]; |
||
1782 | if Fdims.rgbButtons[1] and $80<>0 then FStates := FStates + [isButton2]; |
||
1783 | if Fdims.rgbButtons[2] and $80<>0 then FStates := FStates + [isButton3]; |
||
1784 | end; |
||
1785 | |||
1786 | { TJoystick } |
||
1787 | |||
1788 | function SetDWORDProperty(pdev: IDirectInputDevice; guidProperty: PGUID; |
||
1789 | dwObject, dwHow, dwValue: DWORD): HResult; |
||
1790 | var |
||
1791 | dipdw: TDIPropDWORD; |
||
1792 | begin |
||
1793 | dipdw.diph.dwSize := SizeOf(dipdw); |
||
1794 | dipdw.diph.dwHeaderSize := SizeOf(dipdw.diph); |
||
1795 | dipdw.diph.dwObj := dwObject; |
||
1796 | dipdw.diph.dwHow := dwHow; |
||
1797 | dipdw.dwData := dwValue; |
||
1798 | |||
1799 | Result := pdev.SetProperty(guidProperty, dipdw.diph); |
||
1800 | end; |
||
1801 | |||
1802 | function SetRangeProperty(pdev: IDirectInputDevice; guidProperty: PGUID; |
||
1803 | dwObject, dwHow, Value: DWORD): HResult; |
||
1804 | var |
||
1805 | diprg: TDIPropRange; |
||
1806 | begin |
||
1807 | diprg.diph.dwSize := SizeOf(diprg); |
||
1808 | diprg.diph.dwHeaderSize := SizeOf(diprg.diph); |
||
1809 | diprg.diph.dwObj := dwObject; |
||
1810 | diprg.diph.dwHow := dwHow; |
||
1811 | diprg.lMin := -Value; |
||
1812 | diprg.lMax := +Value; |
||
1813 | |||
1814 | Result := pdev.SetProperty(guidProperty, diprg.diph); |
||
1815 | end; |
||
1816 | |||
1817 | constructor TJoystick.Create(DXInput: TCustomDXInput); |
||
1818 | begin |
||
1819 | inherited Create(DXInput); |
||
1820 | FAutoCenter := True; |
||
1821 | |||
1822 | FID := 0; |
||
1823 | |||
1824 | DeadZoneX := 50; |
||
1825 | DeadZoneY := 50; |
||
1826 | DeadZoneZ := 50; |
||
1827 | |||
1828 | RangeX := 1000; |
||
1829 | RangeY := 1000; |
||
1830 | RangeZ := 1000; |
||
1831 | end; |
||
1832 | |||
1833 | function TJoystick.GetX: Integer; |
||
1834 | begin |
||
1835 | Result := Fdijs.lX; |
||
1836 | end; |
||
1837 | |||
1838 | function TJoystick.GetY: Integer; |
||
1839 | begin |
||
1840 | Result := Fdijs.lY; |
||
1841 | end; |
||
1842 | |||
1843 | function TJoystick.GetZ: Integer; |
||
1844 | begin |
||
1845 | Result := Fdijs.lZ; |
||
1846 | end; |
||
1847 | |||
1848 | procedure TJoystick.Finalize; |
||
1849 | begin |
||
1850 | FID2 := -1; |
||
1851 | FillChar(Fdijs, SizeOf(Fdijs), 0); |
||
1852 | FillChar(FJoyCaps, SizeOf(FJoyCaps), 0); |
||
1853 | inherited Finalize; |
||
1854 | end; |
||
1855 | |||
1856 | function TJoystick.GetCooperativeLevel: Integer; |
||
1857 | begin |
||
1858 | if not FAutoCenter then |
||
1859 | Result := DISCL_EXCLUSIVE or DISCL_FOREGROUND |
||
1860 | else |
||
1861 | Result := inherited GetCooperativeLevel; |
||
1862 | end; |
||
1863 | |||
1864 | function TJoystick_EnumJoysticksCallback(const lpddi: TDIDeviceInstanceA; |
||
1865 | pvRef: Pointer): HRESULT; stdcall; |
||
1866 | begin |
||
4 | daniel-mar | 1867 | Result := Integer(DIENUM_CONTINUE); |
1 | daniel-mar | 1868 | |
1869 | with TJoystick(pvRef) do |
||
1870 | begin |
||
1871 | if FEnumIndex=FID then |
||
1872 | begin |
||
1873 | FDeviceGUID := lpddi.guidInstance; |
||
1874 | FEnumFlag := True; |
||
4 | daniel-mar | 1875 | Result := Integer(DIENUM_STOP); |
1 | daniel-mar | 1876 | Exit; |
1877 | end; |
||
1878 | Inc(FEnumIndex); |
||
1879 | end; |
||
1880 | end; |
||
1881 | |||
1882 | procedure TJoystick.Initialize; |
||
1883 | var |
||
1884 | i, j: Integer; |
||
1885 | devcaps: TDIDevCaps; |
||
1886 | begin |
||
1887 | Finalize; |
||
1888 | |||
1889 | if (not FEnabled) or (FID<0) or (csDesigning in FDXInput.ComponentState) then Exit; |
||
1890 | |||
1891 | try |
||
1892 | try |
||
1893 | if FDXInput.FDInput<>nil then |
||
1894 | begin |
||
1895 | { Device search. } |
||
1896 | FEnumFlag := False; |
||
1897 | FEnumIndex := 0; |
||
1898 | |||
4 | daniel-mar | 1899 | FDXInput.FDInput.EnumDevices({DIDEVTYPE_JOYSTICK}4, @TJoystick_EnumJoysticksCallback, |
1 | daniel-mar | 1900 | Self, DIEDFL_ATTACHEDONLY); |
1901 | |||
1902 | if not FEnumFlag then Exit; |
||
1903 | |||
1904 | { Device making. } |
||
1905 | if FDXInput.FDInput.CreateDevice(FDeviceGUID, FDevice, nil)<>DI_OK then Exit; |
||
1906 | |||
1907 | devcaps.dwSize := SizeOf(devcaps); |
||
1908 | if FDevice.GetCapabilities(devcaps)=DI_OK then |
||
1909 | begin |
||
1910 | FButtonCount := devcaps.dwButtons; |
||
1911 | if devcaps.dwFlags and DIDC_FORCEFEEDBACK<>0 then |
||
1912 | FForceFeedbackDevice := True; |
||
1913 | end; |
||
1914 | |||
4 | daniel-mar | 1915 | //if FDXInput.FDInput.CreateDevice(GUID_Joystick, FDevice, nil)<>DI_OK then Exit; get out by Paul van Dinther |
1 | daniel-mar | 1916 | |
1917 | { Device data format (TDIDataFormat) making. } |
||
1918 | |||
1919 | with FDataFormat do |
||
1920 | begin |
||
1921 | dwFlags := DIDF_ABSAXIS; |
||
1922 | dwDataSize := SizeOf(Fdijs); |
||
1923 | end; |
||
1924 | |||
1925 | if not SetDataFormat then |
||
1926 | begin |
||
1927 | FDevice := nil; |
||
1928 | Exit; |
||
1929 | end; |
||
1930 | |||
1931 | AutoCenter := FAutoCenter; |
||
1932 | |||
1933 | for i:=Low(FDeadZone) to High(FDeadZone) do |
||
1934 | SetDeadZone(i, FDeadZone[i]); |
||
1935 | |||
1936 | for i:=Low(FRange) to High(FRange) do |
||
1937 | SetRange(i, FRange[i]); |
||
1938 | |||
1939 | FDevice2 := FDevice as IDirectInputDevice2; |
||
1940 | end; |
||
1941 | except |
||
1942 | Finalize; |
||
1943 | raise; |
||
1944 | end; |
||
1945 | finally |
||
1946 | if FDevice=nil then |
||
1947 | begin |
||
1948 | { Because DirectInput cannot be used, the GetJoyPosEx function is used. } |
||
1949 | FID2 := -1; |
||
1950 | |||
1951 | j := 0; |
||
1952 | for i:=0 to 255 do |
||
1953 | begin |
||
1954 | FillChar(FJoyCaps, SizeOf(FJoyCaps), 0); |
||
1955 | if joyGetDevCaps(i, @FJoyCaps, SizeOf(FJoyCaps))=JOYERR_NOERROR then |
||
1956 | begin |
||
1957 | if FID=j then |
||
1958 | begin |
||
1959 | FID2 := i; |
||
1960 | Break; |
||
1961 | end; |
||
1962 | Inc(j); |
||
1963 | end; |
||
1964 | end; |
||
1965 | |||
1966 | if FID2<>-1 then |
||
1967 | begin |
||
1968 | if joyGetDevCaps(FID2, @FJoyCaps, SizeOf(FJoyCaps))=JOYERR_NOERROR then |
||
1969 | begin |
||
1970 | FButtonCount := FJoyCaps.wNumButtons; |
||
1971 | end else |
||
1972 | begin |
||
1973 | FID2 := -1; |
||
1974 | end; |
||
1975 | end; |
||
1976 | end; |
||
1977 | end; |
||
1978 | |||
1979 | inherited Initialize; |
||
1980 | end; |
||
1981 | |||
1982 | procedure TJoystick.SetAutoCenter(Value: Boolean); |
||
1983 | begin |
||
1984 | FAutoCenter := Value; |
||
1985 | |||
1986 | if FDevice<>nil then |
||
1987 | SetDWORDProperty(FDevice, DIPROP_AUTOCENTER, 0, DIPH_DEVICE, Ord(Value)); |
||
1988 | end; |
||
1989 | |||
1990 | procedure TJoystick.SetID(Value: Integer); |
||
1991 | begin |
||
1992 | if Value<>FID then |
||
1993 | begin |
||
1994 | FID := Value; |
||
1995 | Initialize; |
||
1996 | end; |
||
1997 | end; |
||
1998 | |||
1999 | function TJoystick.GetDeadZone(Obj: Integer): Integer; |
||
2000 | begin |
||
2001 | Result := 0; |
||
2002 | if (Obj>=Low(FDeadZone)) and (Obj<High(FDeadZone)) then |
||
2003 | Result := FDeadZone[Obj]; |
||
2004 | end; |
||
2005 | |||
2006 | function TJoystick.GetRange(Obj: Integer): Integer; |
||
2007 | begin |
||
2008 | Result := 0; |
||
2009 | if (Obj>=Low(FRange)) and (Obj<High(FRange)) then |
||
2010 | Result := FRange[Obj]; |
||
2011 | end; |
||
2012 | |||
2013 | procedure TJoystick.SetDeadZone(Obj: Integer; Value: Integer); |
||
2014 | begin |
||
2015 | if (Obj<Low(FDeadZone)) or (Obj>=High(FDeadZone)) then Exit; |
||
2016 | |||
2017 | if Value<0 then Value := 0; |
||
2018 | if Value>100 then Value := 100; |
||
2019 | |||
2020 | if Obj=Integer(@PDIJoyState2(nil).rgdwPOV[0]) then |
||
2021 | begin |
||
2022 | FDeadZone[Obj] := -1; |
||
2023 | Exit; |
||
2024 | end; |
||
2025 | |||
2026 | FDeadZone[Obj] := Value; |
||
2027 | |||
2028 | if FDevice<>nil then |
||
2029 | begin |
||
2030 | if SetDWORDProperty(FDevice, DIPROP_DEADZONE, Obj, DIPH_BYOFFSET, Value*100)<>DI_OK then |
||
2031 | FDeadZone[Obj] := -1; |
||
2032 | end; |
||
2033 | end; |
||
2034 | |||
2035 | procedure TJoystick.SetRange(Obj: Integer; Value: Integer); |
||
2036 | begin |
||
2037 | if (Obj<Low(FRange)) or (Obj>=High(FRange)) then Exit; |
||
2038 | |||
2039 | if Value<0 then Value := 0; |
||
2040 | |||
2041 | if Obj=Integer(@PDIJoyState2(nil).rgdwPOV[0]) then |
||
2042 | begin |
||
2043 | FRange[Obj] := -1; |
||
2044 | Exit; |
||
2045 | end; |
||
2046 | |||
2047 | FRange[Obj] := Value; |
||
2048 | |||
2049 | if FDevice<>nil then |
||
2050 | begin |
||
2051 | if SetRangeProperty(FDevice, DIPROP_RANGE, Obj, DIPH_BYOFFSET, Value)<>DI_OK then |
||
2052 | FRange[Obj] := -1; |
||
2053 | end; |
||
2054 | end; |
||
2055 | |||
2056 | procedure TJoystick.Update; |
||
2057 | |||
2058 | function ConvertValue(Value, wXmax, wXmin, DeadZone, Range: Integer): Integer; |
||
2059 | var |
||
2060 | c, w: Integer; |
||
2061 | begin |
||
2062 | Result := 0; |
||
2063 | |||
2064 | c := (wXmax - wXmin) div 2; |
||
2065 | Value := Value-c; |
||
2066 | |||
2067 | w := c*DeadZone div 100; |
||
2068 | c := c - w; |
||
2069 | |||
2070 | if c=0 then Exit; |
||
2071 | |||
2072 | if Abs(Value)>w then |
||
2073 | begin |
||
2074 | if Value>0 then |
||
2075 | Result := MulDiv(Value-w, Range, c) |
||
2076 | else |
||
2077 | Result := MulDiv(Value+w, Range, c); |
||
2078 | end; |
||
2079 | end; |
||
2080 | |||
2081 | var |
||
2082 | i: Integer; |
||
2083 | JoyInfo: TJoyInfoEx; |
||
2084 | begin |
||
2085 | FillChar(Fdijs, SizeOf(Fdijs), 0); |
||
2086 | FStates := []; |
||
2087 | |||
2088 | if (not FInitialized) or FDXInput.FActiveOnly and (GetForegroundWindow<>FDXInput.FForm.Handle) then |
||
2089 | Exit; |
||
2090 | |||
2091 | if FDevice<>nil then |
||
2092 | begin |
||
2093 | FDevice2.Poll; |
||
2094 | GetDeviceState(SizeOf(Fdijs), Fdijs); |
||
2095 | end else |
||
2096 | begin |
||
2097 | if FID2<>-1 then |
||
2098 | begin |
||
2099 | JoyInfo.dwSize := SizeOf(JoyInfo); |
||
2100 | JoyInfo.dwFlags := JOY_RETURNX or JOY_RETURNY or JOY_RETURNZ or JOY_RETURNPOV or |
||
2101 | JOY_RETURNBUTTONS or JOY_RETURNCENTERED; |
||
2102 | |||
2103 | joyGetPosEx(FID2, @JoyInfo); |
||
2104 | |||
2105 | with FJoyCaps do |
||
2106 | Fdijs.lX := ConvertValue(JoyInfo.wXpos, wXmax, wXmin, FDeadZone[DIJOFS_X], FRange[DIJOFS_X]); |
||
2107 | |||
2108 | with FJoyCaps do |
||
2109 | Fdijs.lY := ConvertValue(JoyInfo.wYpos, wYmax, wYmin, FDeadZone[DIJOFS_Y], FRange[DIJOFS_Y]); |
||
2110 | |||
2111 | with FJoyCaps do |
||
2112 | Fdijs.lZ := ConvertValue(JoyInfo.wZpos, wZmax, wZmin, FDeadZone[DIJOFS_Z], FRange[DIJOFS_Z]); |
||
2113 | |||
2114 | Fdijs.rgdwPOV[0] := JoyInfo.dwPOV; |
||
2115 | |||
2116 | for i:=0 to FJoyCaps.wNumButtons-1 do |
||
2117 | if JoyInfo.wButtons and (1 shl i)<>0 then |
||
2118 | Fdijs.rgbButtons[i] := $80; |
||
2119 | end; |
||
2120 | end; |
||
2121 | |||
2122 | for i:=0 to 31 do |
||
2123 | if Fdijs.rgbButtons[i] and $80<>0 then |
||
2124 | FStates := FStates + [TDXInputState(Ord(isButton1)+i)]; |
||
2125 | |||
2126 | if Fdijs.lX<0 then FStates := FStates + [isLeft]; |
||
2127 | if Fdijs.lX>0 then FStates := FStates + [isRight]; |
||
2128 | if Fdijs.lY<0 then FStates := FStates + [isUp]; |
||
2129 | if Fdijs.lY>0 then FStates := FStates + [isDown]; |
||
2130 | end; |
||
2131 | |||
2132 | { TCustomDXInput } |
||
2133 | |||
2134 | var |
||
2135 | FDirectInput: IDirectInput; |
||
2136 | FDirectInputCount: Integer; |
||
2137 | |||
2138 | procedure InitDirectInput(out DI: IDirectInput); |
||
2139 | type |
||
2140 | TDirectInputCreate = function(hinst: THandle; dwVersion: DWORD; |
||
4 | daniel-mar | 2141 | out ppDI: {$IFDEF UNICODE}IDirectInputW{$ELSE}IDirectInputA{$ENDIF}; punkOuter: IUnknown): HRESULT; stdcall; |
1 | daniel-mar | 2142 | begin |
2143 | if FDirectInput=nil then |
||
2144 | begin |
||
2145 | try |
||
2146 | TDirectInputCreate(DXLoadLibrary('DInput.dll', 'DirectInputCreateA')) |
||
2147 | (HInstance, DIRECTINPUT_VERSION, FDirectInput, nil); |
||
2148 | except |
||
2149 | FDirectInput := nil; |
||
2150 | end; |
||
2151 | end; |
||
2152 | |||
2153 | DI := FDirectInput; |
||
2154 | if FDirectInput<>nil then |
||
2155 | Inc(FDirectInputCount); |
||
2156 | end; |
||
2157 | |||
2158 | procedure FinDirectInput(var DI: IDirectInput); |
||
2159 | begin |
||
2160 | if DI<>nil then |
||
2161 | begin |
||
2162 | DI := nil; |
||
2163 | Dec(FDirectInputCount); |
||
2164 | if FDirectInputCount<=0 then |
||
2165 | begin |
||
2166 | FDirectInputCount := 0; |
||
2167 | FDirectInput := nil; |
||
2168 | end; |
||
2169 | end; |
||
2170 | end; |
||
2171 | |||
2172 | constructor TCustomDXInput.Create(AOwner: TComponent); |
||
2173 | var |
||
2174 | Component: TComponent; |
||
2175 | begin |
||
2176 | inherited Create(AOwner); |
||
2177 | |||
2178 | FDevice := TList.Create; |
||
2179 | |||
2180 | FActiveOnly := True; |
||
2181 | FJoystick := TJoystick.Create(Self); |
||
2182 | FKeyboard := TKeyboard.Create(Self); |
||
2183 | FMouse := TMouse.Create(Self); |
||
2184 | FUseDirectInput := True; |
||
2185 | |||
2186 | Component := Owner; |
||
2187 | while (Component<>nil) and (not (Component is TCustomForm)) do |
||
2188 | Component := Component.Owner; |
||
2189 | if Component=nil then |
||
2190 | raise EDXInputError.CreateFmt(SNoForm, ['Owner']); |
||
2191 | FForm := TCustomForm(Component); |
||
2192 | |||
2193 | FSubClass := TControlSubClass.Create(FForm, FormWndProc); |
||
2194 | end; |
||
2195 | |||
2196 | destructor TCustomDXInput.Destroy; |
||
2197 | begin |
||
2198 | Finalize; |
||
2199 | FJoystick.Free; |
||
2200 | FKeyboard.Free; |
||
2201 | FMouse.Free; |
||
2202 | FSubClass.Free; |
||
2203 | while FDevice.Count>0 do |
||
2204 | TCustomInput(FDevice[FDevice.Count-1]).Free; |
||
2205 | FDevice.Free; |
||
2206 | inherited Destroy; |
||
2207 | end; |
||
2208 | |||
2209 | procedure TCustomDXInput.FormWndProc(var Message: TMessage; DefWindowProc: TWndMethod); |
||
2210 | |||
2211 | procedure AcquireDevice; |
||
2212 | var |
||
2213 | i: Integer; |
||
2214 | begin |
||
2215 | for i:=0 to FDevice.Count-1 do |
||
2216 | TCustomInput(FDevice[i]).Acquire; |
||
2217 | end; |
||
2218 | |||
2219 | begin |
||
2220 | case Message.Msg of |
||
2221 | WM_CREATE: |
||
2222 | begin |
||
2223 | { Window handle of Form changed. } |
||
2224 | DefWindowProc(Message); |
||
2225 | SetWindowHandle; |
||
2226 | Exit; |
||
2227 | end; |
||
2228 | WM_ACTIVATEAPP: |
||
2229 | begin |
||
2230 | DefWindowProc(Message); |
||
2231 | if TWMActivateApp(Message).Active then |
||
2232 | AcquireDevice; |
||
2233 | Exit; |
||
2234 | end; |
||
2235 | WM_ACTIVATE: |
||
2236 | begin |
||
2237 | DefWindowProc(Message); |
||
2238 | if TWMActivate(Message).Active<>WA_INACTIVE then |
||
2239 | AcquireDevice; |
||
2240 | Exit; |
||
2241 | end; |
||
2242 | end; |
||
2243 | DefWindowProc(Message); |
||
2244 | end; |
||
2245 | |||
2246 | procedure TCustomDXInput.Finalize; |
||
2247 | var |
||
2248 | i: Integer; |
||
2249 | begin |
||
2250 | for i:=0 to FDevice.Count-1 do |
||
2251 | TCustomInput(FDevice[i]).Finalize; |
||
2252 | FinDirectInput(FDInput); |
||
2253 | end; |
||
2254 | |||
2255 | procedure TCustomDXInput.Loaded; |
||
2256 | begin |
||
2257 | Initialize; |
||
2258 | end; |
||
2259 | |||
2260 | procedure TCustomDXInput.Initialize; |
||
2261 | var |
||
2262 | i: Integer; |
||
2263 | begin |
||
2264 | Finalize; |
||
2265 | if not (csDesigning in ComponentState) then |
||
2266 | begin |
||
2267 | if FUseDirectInput then InitDirectInput(FDInput); |
||
2268 | |||
2269 | for i:=0 to FDevice.Count-1 do |
||
2270 | TCustomInput(FDevice[i]).Initialize; |
||
2271 | |||
2272 | SetWindowHandle; |
||
2273 | |||
2274 | Update; |
||
2275 | end; |
||
2276 | end; |
||
2277 | |||
2278 | procedure TCustomDXInput.SetActiveOnly(Value: Boolean); |
||
2279 | begin |
||
2280 | if Value<>FActiveOnly then |
||
2281 | begin |
||
2282 | FActiveOnly := Value; |
||
2283 | if [csLoading, csReading]*ComponentState=[] then SetWindowHandle; |
||
2284 | end; |
||
2285 | end; |
||
2286 | |||
2287 | procedure TCustomDXInput.SetJoystick(Value: TJoystick); |
||
2288 | begin |
||
2289 | FJoystick.Assign(Value); |
||
2290 | end; |
||
2291 | |||
2292 | procedure TCustomDXInput.SetKeyboard(Value: TKeyboard); |
||
2293 | begin |
||
2294 | FKeyboard.Assign(Value); |
||
2295 | end; |
||
2296 | |||
2297 | procedure TCustomDXInput.SetMouse(Value: TMouse); |
||
2298 | begin |
||
2299 | FMouse.Assign(Value); |
||
2300 | end; |
||
2301 | |||
2302 | procedure TCustomDXInput.SetUseDirectInput(Value: Boolean); |
||
2303 | begin |
||
2304 | if FUseDirectInput<>Value then |
||
2305 | begin |
||
2306 | FUseDirectInput := Value; |
||
2307 | Initialize; |
||
2308 | end; |
||
2309 | end; |
||
2310 | |||
2311 | procedure TCustomDXInput.SetWindowHandle; |
||
2312 | var |
||
2313 | i: Integer; |
||
2314 | begin |
||
2315 | for i:=0 to FDevice.Count-1 do |
||
2316 | TCustomInput(FDevice[i]).SetWindowHandle(FForm.Handle); |
||
2317 | end; |
||
2318 | |||
2319 | procedure TCustomDXInput.Update; |
||
2320 | var |
||
2321 | j: Integer; |
||
2322 | i: TDXInputState; |
||
2323 | s: TDXInputStates; |
||
2324 | begin |
||
2325 | s := []; |
||
2326 | |||
2327 | for j:=0 to FDevice.Count-1 do |
||
2328 | begin |
||
2329 | TCustomInput(FDevice[j]).Update; |
||
2330 | if TCustomInput(FDevice[j]).FBindInputStates then |
||
2331 | s := s + TCustomInput(FDevice[j]).States; |
||
2332 | end; |
||
2333 | |||
2334 | for i:=Low(TDXInputState) to High(TDXInputState) do |
||
2335 | begin |
||
2336 | if (i in s) and (not (i in FOldStates)) then |
||
2337 | FStates := FStates + [i]; |
||
2338 | if (not (i in s)) and (i in FOldStates) then |
||
2339 | FStates := FStates - [i]; |
||
2340 | end; |
||
2341 | |||
2342 | FOldStates := s; |
||
2343 | end; |
||
2344 | |||
4 | daniel-mar | 2345 | end. |